From: rnelson@wsuaix.csc.wsu.edu (roger nelson;S23487)
Newsgroups: comp.os.msdos.programmer
Subject: A foreign language translation Pascal unit
Date: 11 Jan 93 03:41:57 GMT
Article-I.D.: serval.1993Jan11.034157.14452
Organization: Washington State University


Here is the Turbo Pascal Unit for translating phrases to various languages.
It can be used for both DOS and Windows.

A couple of weeks ago I asked if windows provided facilities for allowing
an application to switch between one or more foreign languages
and gave a brief outline of what I was planning on doing.

A number of people replied suggesting windows string tables, however
this seemed to have a fair amount of overhead.
Others suggested DLL or making resources files, but this didn't allow the
user to change the language on the fly. 

Thanks to everyone who replied.

This unit allows the user to change the language on the fly and only stores the
phrases used by the current program for the current language in main memory.

By editing the PHRASES.LNG file, users can also provide localizations
for other languages (not supplied by the programmer) without having
to recompile the application program.

I thought others might find this unit useful so I am posting the short
program listing here.

I am also supplying a sample PHRASES.LNG file which has translations of
several common user interface strings for ENGLISH, FRENCH, SPANISH and
ITALIAN.  This file is UUENCODED because it uses IBM-PC 8-bit characters
for accented characters in French,Spanish and Italian.

I hope that other programmers will provide multilingual support for their
applications.
_____________________________________________________________________
      ______________
____  | ^          |    Roger Nelson          rnelson@wsuaix.csc.wsu.edu
\^^ | | ^          |    Biological Systems Engineering Department
 |^^//  ^^         |
 |  '  ^          +|<---Washington State University
 \_  ^    _________|    Pullman, WA 99164-6120
   `-----'              Work: (509)335-4714  Home: (509)332-8387
                        FAX: (509)335-2722

LANGUAG.PAS   
---Cut Here-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<-----8<---

UNIT languag;
{
   This TurboPascal unit will help provide translation of text strings
   to different human languages.

   Written by Roger Nelson  Jan. 1993
   Comments, suggestions, questions and bug reports can be sent to:

       Roger Nelson
       Biological Systems Engr. Dept.
       Washington State University
       Pullman, WA 99164-6120

       rnelson@wsuaix.csc.wsu.edu

       Phone: (509)335-1578
       FAX  : (509)335-2722


   An equivelent module can also be provided for the programming languages:
   C and scheme by request.
   ________________________________________________________________________

   Phrases are stored in the phrases file: PHRASES.LNG
   which must be placed in in the same directory as the application
   program executables.
   (The phrases.lng file must also be available to the compiler.)

   The phrases files has the following format which allows for the compiler
   to double check the existance of a phrase so you can't inadvertantly
   leave out a phrase from your translations!!!! 


   phraseID,
   ( programlist
   ENGLISH English phrase
   SPANISH Spanish phrase
   ITALIAN Italian phrase
   FRENCH French phrase
      :
      :
   )
   NextphrasesID,
      :
      :

   The phraseID must be a unique valid Pascal Identifier and must be
   followed by a comma. The phraseID and comma must be on their own line.

   THE ( AND ) CHARACTERS ARE ACTUALLY PASCAL COMMENT CHARACTERS AND MUST
   BE ON THEIR OWN LINES.

   After the first comment (on the same line) is a list of all programs in
   which the phrase is used, only those phrases used by the program will
   be loaded. This is useful if your application consists of several programs,
   but where not all phrases are used in all the programs.

   Each translation must be on its own line, the name of the language
   must be uppercase with consistent spelling and one word.

   There must be only one space or one tab character seperating the
   language from the phrase.

   There must not be any blank lines between the ) and the next phrase ID.

   The very first phrases in PHRASES.LNG must be the translation for the
   name of the language:

   L_LANGUAGE,
   ( PROGRAM1 PROGRAM2
   ENGLISH English phrase
   FRENCH Francais phrase
   SPANISH Espanol phrase
   ITALIAN Italiano phrase
   )
   ^- Pascal comment characters!

   If the phrase is to be a null string or a single space, then use
   an underscore character _,  Ie:  ENGLISH _



Tips for restarting a TurboVision application with a new application.

  You may want to allow the user to change the language within the
  application.

  The easiest thing to do is shutdown and restart TurboVision.

  1. Create a boolean variable that will be used to test for the actual exit
     of the application.

  2. Put a while loop using this variable as the test around the application
     init, run and done procedures.

  3. Call the init_language function near the beginning of the program.
     Call the end_language function near the end of the program.

  4. Usually object registration for TurboVision is done in the
     application.init procedure.
     Move these registrations to a point before the exit_application loop
     otherwise TurboVision will complain about stream registration when
     init gets call more than once.

  5. Provide menu options for changing the language.
     This may be a user preferences dialog box or submenus etc...

  6. Provide an application event handler point for each language:

    I.e.

    cmLanguageDefault :
      BEGIN
         Load_language(getenv('LANGUAGE'),'MYAPP');
         message(@self,evCommand,cmQUIT,NIL);
      END;
    cmLanguageEnglish :
      BEGIN
         Load_language('ENGLISH','MYAPP');
         message(@self,evCommand,cmQUIT,NIL);
      END;
    cmLanguageFrench  :
      BEGIN
         Load_language('FRENCH','MYAPP');
         message(@self,evCommand,cmQUIT,NIL);
      END;
    cmLanguageSpanish :
      BEGIN
         Load_language('SPANISH','MYAPP');
         message(@self,evCommand,cmQUIT,NIL);
      END;
    cmLanguageItalian :
      BEGIN
         Load_language('ITALIAN','MYAPP');
         message(@self,evCommand,cmQUIT,NIL);
      END;

  7. When you actually want to exit the program with cmQUIT, set
     exit_application to TRUE:

      cmExit_MyApp :
       BEGIN
          exit_application := TRUE;
          message(@self,evCommand,cmQUIT,NIL);
       END;

  8. To use a phrase translation simply call tranlate() with the phrase_Id
     Ie.
     Writeln(translate(L_mouse),' (',translate(L_Not_available),')');

I.e. The main module of the program MYAPP would look something like this:

BEGIN

  init_language(getenv('LANGUAGE'),'MYAPP'); <- To get the default language
                                                From the DOS environment
                                                variable LANGUAGE, set before
                                                running the program

  RegisterObjects;
  RegisterViews;
  RegisterMenus;
  RegisterDialogs;
  RegisterApp;
  RegisterHelpFile;

  exit_application := FALSE;                  <- global variable
  WHILE NOT exit_application DO
  BEGIN
     theapplication.Init;
     theapplication.Run;
     theapplication.Done;
  END;

  end_language;
END.


The function program_path is implemented as follows:

FUNCTION program_path : STRING;
VAR
   directory : DirStr;
   Name      : NameStr;
   ext       : ExtStr;
BEGIN
   FSplit(ParamStr(0),directory,name,ext);
   program_path := directory;
END;

The function upcase_str is implemented as follows:

FUNCTION upcase_str(the_string : STRING) : STRING;
VAR i : INTEGER;
BEGIN
   FOR i := 1 to length(the_string) DO
      the_string[i] := upcase(the_string[i]);
   upcase_str := the_string;
END;

The function strpos is implemented as follows:

FUNCTION strpos(str1, str2 : STRING) : INTEGER;
VAR
   I,J : INTEGER;
BEGIN
   J := 0;
   strpos := 0;
   FOR I := 1 TO LENGTH(str1) DO
         IF str1[i] = str2[j+1] THEN
         BEGIN
           INC(J);
           IF J = LENGTH(STR2) THEN strpos :=i-j;
         END
         ELSE
         BEGIN
            j  := 0;
            i := i-j;
         END;
END;

Please note that the translate function could be enhanced by using
a search tree (which would also require balancing the phrase list), 
however, since the phrases list is ordered by phraseID,
the linear search should suffice for a few hundred phrases.

}

INTERFACE

USES DOS,cs_glob,objects;

TYPE
    phrases = ({$I PHRASES.LNG} END_PHRASES);

PROCEDURE init_language(Language_Name : STRING; program_name : STRING);
PROCEDURE load_language(Language_Name : STRING; program_name : STRING);
FUNCTION translate(phrase_ID : phrases) : STRING;
PROCEDURE end_language;

IMPLEMENTATION

TYPE

    translation_node_ptr = ^translation_node;
    translation_node = RECORD
        phrase_ID : phrases;
        phrase    : Pstring;
        right     : translation_node_ptr;
    END;

VAR
    translation_list : translation_node_ptr;

FUNCTION program_path : STRING;
VAR
   directory : DirStr;
   Name      : NameStr;
   ext       : ExtStr;
BEGIN
   FSplit(ParamStr(0),directory,name,ext);
   program_path := directory;
END;



PROCEDURE clear_translation_list(node : translation_node_ptr);
BEGIN
    IF (node <> NIL) THEN
    WITH node^ DO
    BEGIN
{      clear_translation_list(left); }
       clear_translation_list(right);
       DisposeStr(phrase);
       Dispose(node)
    END;
END;

PROCEDURE load_language(Language_Name: STRING; program_name : STRING);
VAR
   phrases_file  : TEXT;
   phrases_filename : STRING;
   node : translation_node_ptr;
   phrase_ID : phrases;
   last_node : translation_node_ptr;
   phrase : STRING;
   used_by : STRING;

   FUNCTION read_phrase : BOOLEAN;
   VAR  phrase_ID_str : STRING;
        language_name_in : STRING;
        line_in : STRING;
        read_complete : BOOLEAN;
        phrase_in : STRING;

        PROCEDURE split_line(line : STRING; VAR lang : STRING;
                             VAR phrase : STRING);
        VAR Line_ndx : INTEGER;
            linelen  : INTEGER;
            langlen  : INTEGER;
            phraselen: INTEGER;
        BEGIN

            Line_ndx := 0;
            linelen := length(line);
            langlen := 0;
            REPEAT
               INC(line_ndx);
               INC(langlen);
               lang[langlen] := line[line_ndx];
            UNTIL (line[line_ndx+1] = ' ') OR (line_ndx = linelen);
            lang[0] := char(langlen);
            INC(line_ndx);
            phraselen := 0;
            REPEAT
               INC(line_ndx);
               INC(phraselen);
               phrase[phraselen] := line[line_ndx];
            UNTIL (line_ndx = linelen);
            phrase[0] := CHAR(phraselen);
        END;

   BEGIN
      read_phrase := TRUE;
      IF eof(phrases_file) THEN
         read_phrase := FALSE
      ELSE
      BEGIN
         phrase := '';
         readln(phrases_file,phrase_ID_str);  { phrases ID Not used}
         IF (phrase_ID_str = '') OR (eof(phrases_file))
            THEN
            read_phrase := FALSE
         ELSE
         BEGIN
            readln(phrases_file,used_by);
            read_complete := FALSE;
            REPEAT
                readln(phrases_file,line_in);

                IF (line_in[1] = '}') THEN
                   read_complete := TRUE
                ELSE
                BEGIN
                   split_line(line_in,language_name_in,phrase_in);
                   IF language_name_in = language_name THEN
                      phrase := phrase_in
                   ELSE IF (language_name_in = 'ENGLISH') AND  
                           (phrase = '') THEN
                      { Use english if translation not provided}
                      phrase := phrase_in;

                END
            UNTIL read_complete;
         END;
      END;
   END;

BEGIN
   IF (translation_list <> NIL) THEN
      clear_translation_list(translation_list);
   translation_list := NIL;
   IF language_name = '' THEN
     language_name := 'ENGLISH';

   phrase_ID := L_LANGUAGE;
   phrases_filename := program_path + 'PHRASES.LNG';
   ASSIGN(phrases_file,phrases_filename);
   RESET(phrases_file);
   last_node := NIL;
   FOR phrase_ID := L_LANGUAGE TO PRED(END_PHRASES) DO
      BEGIN
         IF NOT read_phrase THEN halt(0);
         IF strpos(upcase_str(used_by),upcase_str(program_name)) <> 0 THEN
         BEGIN
            new(node);
            IF translation_list = NIL THEN
               translation_list := node;
            node^.phrase_ID := phrase_ID;
            node^.phrase := NewStr(phrase);
            node^.right := NIL;
            IF (last_node <> NIL) THEN
               last_node^.right := node;
            last_node := node;
         END;
      END;
   CLOSE(phrases_file);
END;

FUNCTION translate(phrase_ID : phrases) : STRING;
VAR
   curr : translation_node_ptr;
   translation : STRING;
BEGIN
   curr := translation_list;
   WHILE ((curr <> NIL) AND (curr^.phrase_ID <> phrase_ID)) DO
      curr := curr^.right;
   IF (curr <> NIL) THEN
      translation := curr^.phrase^
   ELSE
      translation := 'Unable to translate';
   IF translation = '_' THEN
      translate := ' '
   ELSE
      translate := translation;
END;

PROCEDURE init_language(language_name : STRING; program_name : STRING);
BEGIN
   IF language_name = '' THEN
     language_name := 'ENGLISH';
   translation_list := NIL;
   load_language(Language_name,program_name);
END;

PROCEDURE end_language;
BEGIN
   clear_translation_list(translation_list);
END;

END.
---Cut Here----->8----->8----->8----->8----->8----->8----->8----->8-----

begin 644 phrases.lng
M4F5P;&%C92!-64%04"!W:71H('EO=7(@<')O9W)A;2!N86UE*',I+@H*+2TM
M0W5T($AE<F4M+2TM+3@\+2TM+2TX/"TM+2TM.#PM+2TM+3@\+2TM+2TX/"TM
M+2TM.#PM+2TM+3@\+2TM+2TX/"TM+2TM.#PM+2T*3%],04Y'54%'12P*>R!-
M64%04`I%3D=,25-(($5N9VQI<V@*1E)%3D-(($9R86YC86ES"DE404Q)04X@
M271A;&EA;F\*4U!!3DE32"!%<W!A;F]L"GT*3%]!8F]U="P*>R!-64%04`I%
M3D=,25-(($%B;W5T"D9214Y#2"!!=71O=7(*251!3$E!3B!2:6=U87)D;PI3
M4$%.25-(($%C97)C82!D90I]"DQ?07!R+`I[($U905!0"D5.1TQ)4T@@07!R
M"D9214Y#2"!!=G(*251!3$E!3B!!<'(*4U!!3DE32"!!8G(*?0I,7T%P<FEL
M+`I[($U905!0"D5.1TQ)4T@@07!R:6P*1E)%3D-(($%V<FEL"DE404Q)04X@
M07!R:6QE"E-004Y)4T@@06)R:6P*?0I,7T%U9RP*>R!-64%04`I%3D=,25-(
M($%U9PI&4D5.0T@@06]T"DE404Q)04X@06=T"E-004Y)4T@@06=O"GT*3%]!
M=6=U<W0L"GL@35E!4%`*14Y'3$E32"!!=6=U<W0*1E)%3D-(($%O%G0*251!
M3$E!3B!!9V]S=&\*4U!!3DE32"!!9V]S=&\*?0I,7T-H86YG95]$:7)E8W1O
M<GDL"GL@35E!4%`*14Y'3$E32"!#:&%N9V4@1&ER96-T;W)Y"D9214Y#2"!#
M:&%N9V5R('("<&5R=&]I<F4*251!3$E!3B!#86UB:6\@9&D@9&ER96-T;W)Y
M"E-004Y)4T@@0V%M8FEA<B!D:7)E8W1O<FEO"GT*3%]#:&5C:U]P871H7V]R
M7W-P96QL:6YG+`I[($U905!0"D5.1TQ)4T@@0VAE8VL@=&AE('!A=&@@;W(@
M<W!E;&QI;F<N"D9214Y#2"!0975T+0AT<F4@97)R975R('-E;G1I97(@;W4@
M`G!E;&QA=&EO;BX*251!3$E!3B!697)I9FEC87)E(&EL('!E<F-A<G-O(&\@
M:6P@;F]M92X*4U!!3DE32"!697)I9FEQ=64@;&$@<G5T82!O(&QA(&]R=&]G
M<F%F(6$N"GT*3%]#;&]S92P*>R!-64%04`I%3D=,25-(($-L;W-E"D9214Y#
M2"!&97)M97(*251!3$E!3B!#:&EU9&D*4U!!3DE32"!#97)R87(*?0I,7T-U
M<G)E;G1?9&ER96-T;W)Y+`I[($U905!0"D5.1TQ)4T@@0W5R<F5N="!$:7)E
M8W1O<GD*1E)%3D-((%("<&5R=&]I<F4@0V]U<F%N=`I)5$%,24%.($1I<F5C
M=&]R>2!#;W)R96YT90I34$%.25-(($1I<F5C=&]R:6\@8V]R<FEE;G1E"GT*
M3%]#7V%?<V-A9&4L"GL@35E!4%`*14Y'3$E32"!#?F%^<V-A9&4*1E)%3D-(
M($-^87YS8V%D90I)5$%,24%.($9I;F5S=')E(&EN('Y3?F]V<F%P<&]S:7II
M;VYE"E-004Y)4T@@0WYA?G-C861A"GT*3%]$871E+`I[($U905!0"D5.1TQ)
M4T@@1&%T90I&4D5.0T@@1&%T90I)5$%,24%.($1A=&$*4U!!3DE32"!&96-H
M80I]"DQ?1&%T97-?9F]R7W!R;V9I;&5?;W5T<'5T+`I[($U905!0"D5.1TQ)
M4T@@1&%T97,@9F]R(')E<&]R=&EN9R!S;VEL('!R;V9I;&4@=F%R:6%B;&5S
M"D9214Y#2"!$871E<R!P;W5R(&PG;W5T<'5T(&1E<R!H;W)I>F]N<PI)5$%,
M24%.($1A=&4@<&5R(&PG;W5T<'5T(&1E;&QA('1A=F]L82!D96P@<W5O;&\*
M4U!!3DE32"!&96-H87,@<&%R82!R97!O<G1A<B!V87)I86)L97,@9&5L('!E
M<F9I;"!D92!S=65L;PI]"DQ?1&%Y+`I[($U905!0"D5.1TQ)4T@@1&%Y"D92
M14Y#2"!*;W5R"DE404Q)04X@1VEO<FYO"E-004Y)4T@@1"%A"GT*3%]$87ES
M+`I[($U905!0"D5.1TQ)4T@@1&%Y<PI&4D5.0T@@2F]U<G,*251!3$E!3B!'
M:6]R;FD*4U!!3DE32"!$(6%S"GT*3%]$87E?;V9?;6]N=&@L"GL@35E!4%`*
M14Y'3$E32"!$87D@;V8@=&AE(&UO;G1H"D9214Y#2"!*;W5R(&1U(&UO:7,*
M251!3$E!3B!);"!G:6]R;F\@9&5L(&UE<V4*4U!!3DE32"!$(6$@9&5L(&UE
M<PI]"DQ?1&5C+`I[($U905!0"D5.1TQ)4T@@1&5C"D9214Y#2"!$96,*251!
M3$E!3B!$:6,*4U!!3DE32"!$96,*?0I,7T1E8V5M8F5R+`I[($U905!0"D5.
M1TQ)4T@@1&5C96UB97(*1E)%3D-(($1E8V5M8G)E"DE404Q)04X@1&EC96UB
M<F4*4U!!3DE32"!$:6-I96UB<F4*?0I,7V1E9F%U;'0L"GL@35E!4%`*14Y'
M3$E32"!D969A=6QT"D9214Y#2"!087(@9`)F875T"DE404Q)04X@<')E9&5F
M:6YI=&\*4U!!3DE32"!S=&%N9&%R9`I]"DQ?1&5L971E+`I[($U905!0"D5.
M1TQ)4T@@1&5L971E"D9214Y#2"!3=7!P<FEM97(*251!3$E!3B!#86YC96QL
M80I34$%.25-((%-U<')I;6ER"GT*3%]%;G1E<BP*>R!-64%04`I%3D=,25-(
M($5N=&5R"D9214Y#2"!%;G1R90I)5$%,24%.($EN=')O9'5R<F4*4U!!3DE3
M2"!%;G1R90I]"DQ?17AI="P*>R!-64%04`I%3D=,25-(($5X:70*1E)%3D-(
M(%%U:71T97(*251!3$E!3B!%<V-I"E-004Y)4T@@4V%L:7(*?0I,7T5X=&5N
M<VEO;E]M=7-T7VYO=%]S<&5C:69I960L"GL@35E!4%`*14Y'3$E32"!4:&4@
M97AT96YS:6]N(&UU<W0@;F]T(&)E('-P96-I9FEE9"X*1E)%3D-(($5X=&5N
M<VEO;B!N)V5S="!P87,@;F5C97-S86ER92X*251!3$E!3B!,)V5S=&5N<VEO
M;F4@;F]N(&1E=F4@97-S97)E('-P96-I9FEC871A+@I34$%.25-(($QA(&5X
M=&5N<VEO;B!N;R!D96)E(&5S<&5C:69I8V%R<V4N"GT*3%]%7WA?:70L"GL@
M35E!4%`*14Y'3$E32"!%?GA^:70*1E)%3D-(('Y1?G5I='1E<@I)5$%,24%.
M($5^<WYC:0I34$%.25-(('Y3?F%L:7(*?0I,7T9E8BP*>R!-64%04`I%3D=,
M25-(($9E8@I&4D5.0T@@1F5V"DE404Q)04X@1F5B"E-004Y)4T@@1F5B"GT*
M3%]&96)R=6%R>2P*>R!-64%04`I%3D=,25-(($9E8G)U87)Y"D9214Y#2"!&
M979R:65R"DE404Q)04X@1F5B8G)A:6\*4U!!3DE32"!&96)R97)O"GT*3%](
M96QP+`I[($U905!0"D5.1TQ)4T@@2&5L<`I&4D5.0T@@06ED90I)5$%,24%.
M($%I=71O"E-004Y)4T@@07EU9&$*?0I,7TAO=7)S+`I[($U905!0"D5.1TQ)
M4T@@2&]U<G,*1E)%3D-((&AE=7)E<PI)5$%,24%.($]R90I34$%.25-((&AO
M<F%S"GT*3%]);G-E<G0L"GL@35E!4%`*14Y'3$E32"!);G-E<G0*1E)%3D-(
M($EN<V5R97(*251!3$E!3B!);G-E<FES8VD*4U!!3DE32"!);G-E<G1A<@I]
M"DQ?2F%N+`I[($U905!0"D5.1TQ)4T@@2F%N"D9214Y#2"!*86X*251!3$E!
M3B!'96X*4U!!3DE32"!%;G(*?0I,7TIA;G5A<GDL"GL@35E!4%`*14Y'3$E3
M2"!*86YU87)Y"D9214Y#2"!*86YV:65R"DE404Q)04X@1V5N;F%I;PI34$%.
M25-(($5N97)O"GT*3%]*=6PL"GL@35E!4%`*14Y'3$E32"!*=6P*1E)%3D-(
M($IU;`I)5$%,24%.($QU9PI34$%.25-(($IU;`I]"DQ?2G5L>2P*>R!-64%0
M4`I%3D=,25-(($IU;'D*1E)%3D-(($IU:6QL970*251!3$E!3B!,=6=L:6\*
M4U!!3DE32"!*=6QI;PI]"DQ?2G5N+`I[($U905!0"D5.1TQ)4T@@2G5N"D92
M14Y#2"!*=6X*251!3$E!3B!':74*4U!!3DE32"!*=6X*?0I,7TIU;F4L"GL@
M35E!4%`*14Y'3$E32"!*=6YE"D9214Y#2"!*=6EN"DE404Q)04X@1VEU9VYO
M"E-004Y)4T@@2G5N:6\*?0I,7TQI;F5S7W!E<E]P86=E+`I[($U905!0"D5.
M1TQ)4T@@3&EN97,@<&5R('!A9V4*1E)%3D-(($QI9VYE<R!P87(@<&%G90I)
M5$%,24%.(%)I9VAE('!E<B!P86=I;F$*4U!!3DE32"!,(6YE87,@<&]R('`@
M9VEN80I]"DQ?3&EN95]W:61T:"P*>R!-64%04`I%3D=,25-(($QI;F4@=VED
M=&@*1E)%3D-(($QO;F=U975R(&1E(&QI;F=E<PI)5$%,24%.($QA<F=H97IZ
M82!R:6=A"E-004Y)4T@@06YC:&\@9&4@;&$@;"%N96$*?0I,7TQO860L"GL@
M35E!4%`*14Y'3$E32"!,;V%D"D9214Y#2"!,96-T=7)E"DE404Q)04X@0V%R
M:6-A"E-004Y)4T@@06)R:7(*?0I,7TQO861?0W)E871E+`I[($U905!0"D5.
M1TQ)4T@@3&]A9"]#<F5A=&4*1E)%3D-(($-H87)G97(O0W("97(*251!3$E!
M3B!#87)I8V$O0W)E80I34$%.25-(($%B<FER+V-R96%R"GT*3%]-87(L"GL@
M35E!4%`*14Y'3$E32"!-87(*1E)%3D-(($UA<@I)5$%,24%.($UA<@I34$%.
M25-(($UA<@I]"DQ?36%R8V@L"GL@35E!4%`*14Y'3$E32"!-87)C:`I&4D5.
M0T@@36%R<PI)5$%,24%.($UA<GIO"E-004Y)4T@@36%R>F\*?0I,7TUA>2P*
M>R!-64%04`I%3D=,25-(($UA>0I&4D5.0T@@36%I"DE404Q)04X@36%G9VEO
M"E-004Y)4T@@36%Y;PI]"DQ?36]U<V4L"GL@35E!4%`*14Y'3$E32"!-;W5S
M90I&4D5.0T@@4V]U<FES"DE404Q)04X@36]U<V4*4U!!3DE32"!2870B;@I]
M"DQ?3F5X=%]W:6YD;W<L"GL@35E!4%`*14Y'3$E32"!.97AT('=I;F1O=PI&
M4D5.0T@@1F5N"'1R92!S=6EV86YT"DE404Q)04X@4')O<W-I;6$@9FEN97-T
M<F$*4U!!3DE32"!696YT86YA(%-I9W5I96YT90I]"DQ?3F]T7T%V86EL86)L
M92P*>R!-64%04`I%3D=,25-(($YO="!!=F%I;&%B;&4*1E)%3D-(($YO;B!$
M:7-P;VYI8FQE"DE404Q)04X@3F]N($1I<W!O;FEB:6QE"E-004Y)4T@@3F\@
M9&ES<&]N:6)L90I]"DQ?3F]T7V5N;W5G:%]M96UO<GE?=&]?8V]M<&QE=&5?
M;W!E<F%T:6]N+`I[($U905!0"D5.1TQ)4T@@3F]T(&5N;W5G:"!M96UO<GD@
M879A:6QA8FQE('1O(&-O;7!L971E(&]P97)A=&EO;BX*1E)%3D-(($T";6]R
M:64@;F]N(&1I<W!O;FEB;&4N($]P`G)A=&EO;B!N;VX@8V]M<&QE="X*251!
M3$E!3B!-96UO<FEA(&1I<W!O;FEB:6QE(&EN<W5F9FEC:65N=&4@<&5R(&-O
M;7!L971A<F4@;"=O<&5R87II;VYE+@I34$%.25-(($YO(&AA>2!S=69I8VEE
M;G1E(&UE;6]R:6$@<&%R82!C;VUP;&5T87(@;&$@;W!E<F%C:2)N+@I]"DQ?
M3F]T7W5S960L"GL@35E!4%`*14Y'3$E32"!.;W0@57-E9`I&4D5.0T@@26YU
M=&EL:7,""DE404Q)04X@3F]N(%5T:6QI>GIA=&\*4U!!3DE32"!.;R!S92!U
M<V$*?0I,7TYO=BP*>R!-64%04`I%3D=,25-(($YO=@I&4D5.0T@@3F]V"DE4
M04Q)04X@3F]V"E-004Y)4T@@3F]V"GT*3%].;W9E;6)E<BP*>R!-64%04`I%
M3D=,25-(($YO=F5M8F5R"D9214Y#2"!.;W9E;6)R90I)5$%,24%.($YO=F5M
M8G)E"E-004Y)4T@@3F]V:65M8G)E"GT*3%]/8W0L"GL@35E!4%`*14Y'3$E3
M2"!/8W0*1E)%3D-(($]C=`I)5$%,24%.($]T=`I34$%.25-(($]C=`I]"DQ?
M3V-T;V)E<BP*>R!-64%04`I%3D=,25-(($]C=&]B97(*1E)%3D-(($]C=&]B
M<F4*251!3$E!3B!/='1O8G)E"E-004Y)4T@@3V-T=6)R90I]"DQ?3W!E;BP*
M>R!-64%04`I%3D=,25-(($]P96X*1E)%3D-(($]U=G)I<@I)5$%,24%.($%P
M<FD*4U!!3DE32"!!8G)I<@I]"DQ?3W!E;E]A7T9I;&4L"GL@35E!4%`*14Y'
M3$E32"!/<&5N(&$@1FEL90I&4D5.0T@@3W5V<FER('5N92!F:6-H:65R"DE4
M04Q)04X@07!R:2!U;B!&:6QE"E-004Y)4T@@06)R:7(@=6X@87)C:&EV;PI]
M"DQ?3U]+7RP*>R!-64%04`I%3D=,25-(($]^2WX*1E)%3D-(($]^2WX*251!
M3$E!3B!^17YS96=U:0I34$%.25-(('Y'?G5A<F1A<@I]"DQ?4&%G:6YA=&EO
M;BP*>R!-64%04`I%3D=,25-((%!A9VEN871I;VX*1E)%3D-((%!A9VEN871I
M;VX*251!3$E!3B!);7!A9VEN87II;VYE"E-004Y)4T@@4&%G:6YA8VDB;@I]
M"DQ?4&QE87-E7W=A:70L"GL@35E!4%`*14Y'3$E32"!0;&5A<V4@5V%I="XN
M+@I&4D5.0T@@071T96YD97HN+BX*251!3$E!3B!0<F5G;R!A='1E;F1E<F4N
M+BX*4U!!3DE32"!%<W!E<F4L('!O<B!F879O<BXN+@I]"DQ?4')E<W-?4D54
M55).7W1O7V-O;G1I;G5E+`I[($U905!0"D5.1TQ)4T@@4')E<W,@6U)E='5R
M;ET@=&\@8V]N=&EN=64N"D9214Y#2"!487!E<B!;(#Q$1%D@72!P;W5R(&-O
M;G1I;G5E<BX*251!3$E!3B!0<F5M97)E(%M);G9I;UT@<&5R(&-O;G1I;G5A
M<F4N"E-004Y)4T@@4')E<VEO;F4@6T5N=')A<ET@<&%R82!C;VYT:6YU87(N
M"GT*3%]0<F5V7W=I;F1O=RP*>R!-64%04`I%3D=,25-((%!R978@=VEN9&]W
M"D9214Y#2"!&96X"=')E('!R`F-E9`(*251!3$E!3B!&:6YE<W1R82!P<F5C
M+@I34$%.25-((%9E;G1A;F$@86YT97)I;W(*?0I,7U-A=F4L"GL@35E!4%`*
M14Y'3$E32"!3879E"D9214Y#2"!3875V97(*251!3$E!3B!386QV"E-004Y)
M4T@@1W5A<F1A<@I]"DQ?4V5L96-T7V%?1FEL92P*>R!-64%04`I%3D=,25-(
M(%-E;&5C="!A($9I;&4*1E)%3D-(($-H;VES:7(@=6X@9FEC:&EE<@I)5$%,
M24%.(%-E;&5Z:6]N82!U;B!S:6QE"E-004Y)4T@@4V5L96-C:6]N92!U;B!A
M<F-H:79O"GT*3%]397!T96UB97(L"GL@35E!4%`*14Y'3$E32"!397!T96UB
M97(*1E)%3D-((%-E<'1E;6)R90I)5$%,24%.(%-E='1E;6)R90I34$%.25-(
M(%-E<'1I96UB<F4*?0I,7U-P="P*>R!-64%04`I%3D=,25-((%-P=`I&4D5.
M0T@@4W!T"DE404Q)04X@4V5T"E-004Y)4T@@4W!T"GT*3%]4>7!E7T58251?
M=&]?<F5T=7)N+`I[($U905!0"D5.1TQ)4T@@5'EP92!%6$E4('1O(')E='5R
M;BXN+@I&4D5.0T@@5&%P97H@15A)5"`%(')E=&]U<FYE<BXN+@I)5$%,24%.
M($EN=FEA(&EL(&-O;6%N9&\@15A)5"!P97(@<FET;W)N87)E+BXN"E-004Y)
M4T@@17-C<FEB82!%6$E4('!A<F$@<F5T;W)N87(N+BX*?0I,7UEE87(L"GL@
M35E!4%`*14Y'3$E32"!996%R"DE404Q)04X@06YN;PI34$%.25-(($$D;PI&
M4D5.0T@@06YN90(*?0I,7UIO;VTL"GL@35E!4%`*14Y'3$E32"!:;V]M"D92
M14Y#2"!:;V]M"DE404Q)04X@6F]O;0I34$%.25-((%IO;VT*?0I,7U]!7W!P
M96YD+`I[($U905!0"D5.1TQ)4T@@?D%^<'!E;F0*1E)%3D-(('Y!?FIO=71E
M<@I)5$%,24%.('Y!?F=G:75N9VD*4U!!3DE32"!^07YG<F5G87(*?0I,7U]#
M7V%N8V5L+`I[($U905!0"D5.1TQ)4T@@?D-^86YC96P*1E)%3D-(('Y!?FYN
M=6QE<@I)5$%,24%.($%^;GYN=6QL80I34$%.25-(('Y#?F%N8V5L87(*?0I,
M7U]#7VAD:7(L"GL@35E!4%`*14Y'3$E32"!^0WYH1&ER"D9214Y#2"!^0WYH
M86YG97(*251!3$E!3B!^0WYA;6)I80I34$%.25-(('Y#?F%M8FEA<@I]"DQ?
M7T-?;&]S92P*>R!-64%04`I%3D=,25-(('Y#?FQO<V4*1E)%3D-(('Y&?F5R
M;65R"DE404Q)04X@?D-^:&EU9&D*4U!!3DE32"!^0WYE<G)A<@I]"DQ?7T1?
M96QE=&4L"GL@35E!4%`*14Y'3$E32"!^1'YE;&5T90I&4D5.0T@@?E-^=7!P
M<FEM97(*251!3$E!3B!^0WYA;F-E;&QA"E-004Y)4T@@?E-^=7!R:6UI<@I]
M"DQ?7T1?:7)E8W1O<GDL"GL@35E!4%`*14Y'3$E32"!^1'YI<F5C=&]R>0I&
M4D5.0T@@?E)^`G!E<G1O:7)E"DE404Q)04X@?D1^:7)E8W1O<GD*4U!!3DE3
M2"!^1'YI<F5C=&]R:6\*?0I,7U]$7T]37W-H96QL+`I[($U905!0"D5.1TQ)
M4T@@?D1^3U,@<VAE;&P*1E)%3D-(('Y$?D]3('-H96QL"DE404Q)04X@?D1^
M3U,@<VAE;&P*4U!!3DE32"!^1'Y/4R!S:&5L;`I]"DQ?7T5?>&ET+`I[($U9
M05!0"D5.1TQ)4T@@?D5^>&ET"D9214Y#2"!^47YU:71T97(*251!3$E!3B!^
M17YS8VD*4U!!3DE32"!^4WYA;&ER"GT*3%]?1E]I;&4L"GL@35E!4%`*14Y'
M3$E32"!^1GYI;&4*1E)%3D-(('Y&?FEC:&EE<@I)5$%,24%.('Y&?FEL90I3
M4$%.25-(('Y&?FEC:&5R;PI]"DQ?7TE?;G-E<G0L"GL@35E!4%`*14Y'3$E3
M2"!^27YN<V5R=`I&4D5.0T@@?DE^;G-E<F5R"DE404Q)04X@?DE^;G-E<FES
M8VD*4U!!3DE32"!^27YN<V5R=&%R"GT*3%]?3%]O860L"GL@35E!4%`*14Y'
M3$E32"!^3'YO860*1E)%3D-(('Y,?F5C='5R90I)5$%,24%.('Y#?F%R:6-A
M"E-004Y)4T@@?D%^8G)I<@I]"DQ?7TY?86UE+`I[($U905!0"D5.1TQ)4T@@
M?DY^86UE"D9214Y#2"!^3GYO;0I)5$%,24%.('Y.?F]M90I34$%.25-(('Y.
M?F]M8G)E"GT*3%]?3E]E>'1?=VEN9&]W+`I[($U905!0"D9214Y#2"!^1GYE
M;@AT<F4@<W5I=F%N=`I%3D=,25-(('Y.?F5X="!W:6YD;W<*251!3$E!3B!^
M4'YR;W-S:6UA(&9I;F5S=')A"E-004Y)4T@@5F5N=&%N82!^4WYI9W5I96YT
M90I]"DQ?7T]?<&5N+`I[($U905!0"D5.1TQ)4T@@?D]^<&5N"D9214Y#2"!^
M3WYP96X*251!3$E!3B!^07YP<FD*4U!!3DE32"!^07YB<FER"GT*3%]?3U]R
M:6=I;BP*>R!-64%04`I%3D=,25-(('Y/?G)I9VEN"D9214Y#2"!/<FEG:6YE
M"DE404Q)04X@?D]^<FEG:6YE"E-004Y)4T@@?D]^<FEG:6YA;`I]"DQ?7T]?
M=F5R=W)I=&4L"GL@35E!4%`*14Y'3$E32"!^3WYV97)W<FET90I&4D5.0T@@
M?E)^96UP;&%C97(*251!3$E!3B!^4GYI<V-R:79I"E-004Y)4T@@?D-^86UB
M:6%R"GT*3%]?4%]R:6YT"GL@35E!4%`*14Y'3$E32"!^4'YR:6YT"D9214Y#
M2"!^27YM<')I;65R:64*251!3$E!3B!^4WYT86UP80I34$%.25-(('Y)?FUP
M<FEM:7(*?0I,7U]27V5S:7IE7VUO=F4L"GL@35E!4%`*14Y'3$E32"!^4GYE
M<VEZ92]M;W9E"D9214Y#2"!^0WYA;&EB<F%G90I)5$%,24%.('Y2?FED:6UE
M;G-I;VYA+VUU;W9I"E-004Y)4T@@0V%M8FEA<B!^5'YA;6$D;R]M;W9E<@I]
M"DQ?7U)?=6YT:6UE7V=R87!H+`I[($U905!0"D5.1TQ)4T@@?E)^=6YT:6UE
M($=R87!H"D9214Y#2"!^1WYR87!H:7%U90I)5$%,24%.('Y'?G)A9FEC:2!V
M<R!T96UP;PI34$%.25-(('Y'?G(@9FEC;W,*?0I,7U]37V%V92P*>R!-64%0
M4`I%3D=,25-(('Y3?F%V90I&4D5.0T@@?E-^875V97(*251!3$E!3B!^4WYA
M;'9A"E-004Y)4T@@?D=^=6%R9&%R"GT*3%]?5%]I;&4L"GL@35E!4%`*14Y'
M3$E32"!^5'YI;&4*1E)%3D-(('Y#?A-T92`%(&,3=&4*251!3$E!3B!^07YF
M9FEA;F-A;65N=&\@9&5L;&4@9FEN97-T<F4*4U!!3DE32"!^5GYE;G1A;F%S
M(&-O<W1A9&\@82!C;W-T861O"GT*3%]?5E]I9&5O7VUO9&5?,C5?-3`L"GL@
M35E!4%`*14Y'3$E32"!^5GYI9&5O(&UO9&4@,C4O-3`*1E)%3D-(('Y6?FED
M96\@;6]D92`R-2\U,`I)5$%,24%.('Y3?F-H97)M;R!I;B!-;V1A;&ET!2`R
M-2\U,`I34$%.25-((&UO9&$@9&5L('Y6?FED96\@,C4O-3`*?0I,7U]77VEN
M9&]W+`I[($U905!0"D5.1TQ)4T@@?E=^:6YD;W<*1E)%3D-(('Y&?F5N"'1R
M90I)5$%,24%.('Y&?FEN97-T<F$*4U!!3DE32"!^5GYE;G1A;F$*?0I,7U]:
M7V]O;2P*>R!-64%04`I&4D5.0T@@?EI^;V]M"D5.1TQ)4T@@?EI^;V]M"DE4
M04Q)04X@?EI^;V]M"E-004Y)4T@@?EI^;V]M"GT*3%]$87E?;V9?>65A<BP*
M>R!-64%04`I%3D=,25-(($1A>2!O9B!T:&4@>65A<CL*1E)%3D-(($IO=7(@
M9&4@;"=A;FX"93L*251!3$E!3B!':6]R;F\@9&5L;"=A;FYO"E-004Y)4T@@
M1"%A(&1E;"!A)&\["GT*3%]D:7-A8FQE9"P*>R!-64%04`I%3D=,25-((&1I
M<V%B;&5D"D9214Y#2"!N;VX@:&%B:6QI=`(*251!3$E!3B!D:7-A8FEL:71A
M=&D*4U!!3DE32"!D97-H86)I;&ET861O"GT*3%]E;F%B;&5D+`I[($U905!0
M"D5.1TQ)4T@@96YA8FQE9`I&4D5.0T@@:&%B:6QI=`(*251!3$E!3B!A8FEL
M:71A=&D*4U!!3DE32"!H86)I;&ET861O"GT*3%]&04E,140L"GL@35E!4%`*
M14Y'3$E32"!&04E,140*1E)%3D-((!!#2$5#"DE404Q)04X@1D%,3$E43PI3
M4$%.25-(($9204-!4T$*?0I,7VYO=%]V86QI9"P*>R!-64%04`I%3D=,25-(
M(&YO="!V86QI9`I&4D5.0T@@;F]N('9A;&%B;&4N"DE404Q)04X@;F]N('9A
M;&ED;PI34$%.25-((&YO(&5S('8@;&ED;PI]"DQ?4$%34T5$+`I[($U905!0
M"D5.1TQ)4T@@4$%34T5$"D9214Y#2"!005-3$`I)5$%,24%.(%!!4U-!5$\*
M4U!!3DE32"!%6$E43U-/"GT*3%]686QI9&%T:6YG+`I[($U905!0"D5.1TQ)
M4T@@5F%L:61A=&EN9PI&4D5.0T@@5F%L:61A=&EO;B!E;B!C;W5R<PI)5$%,
M24%.(%9A;&ED87II;VYE(&EN(&%T=&\*4U!!3DE32"!686QI9&%N9&\*?0I,
M7U9A;&ED871I;VXL"GL@35E!4%`*14Y'3$E32"!686QI9&%T:6]N"D9214Y#
M2"!686QI9&%T:6]N"DE404Q)04X@5F%L:61A>FEO;F4*4U!!3DE32"!686QI
M9&%C:2)N"GT*3%]697)I9GEI;F=?97AI<W1A;F-E7V]F7V9I;&4L"GL@35E!
M4%`*14Y'3$E32"!697)I9GEI;F<@97AI<W1E;F-E(&]F(&9I;&4*1E)%3D-(
M(%8"<FEF:6-A=&EO;B!D92!L)P)X:7-T96YC92!D=2!F:6-H:65R"DE404Q)
M04X@5F5R:69I8V$@9&5L;"=E<VES=&5N>F$@9&5L(&9I;&4@:6X@871T;PI3
M4$%.25-((%9E<FEF:6-A;F1O(&5X:7-T96YC:6$@9&5L(&%R8VAI=F\*?0HM
M+2U#=70@2&5R92TM+2TM/C@M+2TM+3XX+2TM+2T^."TM+2TM/C@M+2TM+3XX
<+2TM+2T^."TM+2TM/C@M+2TM+3XX+2TM+2T*"BT^
`
end
Newsgroups: comp.os.msdos.programmer