home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 2 / crawlyvol2.bin / program / pascal / forest2 / forest2.pas next >
Encoding:
Pascal/Delphi Source File  |  1989-01-16  |  23.1 KB  |  696 lines

  1.  
  2.  
  3.  
  4. PROGRAM Forest2;   {Tab size = 2}
  5. {A program to indicate the overall structure of a Pascal program. 
  6.  AUTHOR      : Merlin L. Hanson
  7.  VERSION     : 2.0             DATE  : 1/15/89
  8.  COMPILED BY : Personal Pascal Version 2.00
  9. }
  10.  
  11.   {$I GEMSUBS.PAS}
  12.   CONST
  13.     TAB      = 9;    ESC     =   27;
  14.     NoBorder = 0;    MyBlack = $180;
  15.   TYPE
  16.     PathChars = PACKED ARRAY [1..80] OF char;
  17.   VAR
  18.     MyInFile      : {FILE OF} text;           {Pascal source file}
  19.     CRT           : {FILE OF} text;           {OUTPUT file may be redirected}
  20.     TextLine      : ARRAY [1..170] OF char;   {The current line}
  21.     TextUpperCase : ARRAY [1..170] OF char;   {and its' equivalent}
  22.     FileName      : Path_Name;                {Used for both files}
  23.     Path          : Path_Name;                {Used for both files}
  24.     NbrCharInLine : integer;                  {length of text line}
  25.     ch            : char;                     {A general purpose character}
  26.     LineNbr       : integer;                  {The line number, 1..n}
  27.     Choice        : (Monitor,Printer,FileX);  {possible destinations}
  28.     NbrTab        : integer;                  {Change each tab char to number tab spaces}
  29.     PrinterModeChanged : boolean;             {Remember to reset the printer}
  30.     ReservedWord  : ARRAY[1..10]OF string;    {These are the 'magic' words}
  31.     TextStrUpper  : string[255];              {An upper case string version of current line}
  32.   (*$I AUXSUBS.PAS (some of the VT-52 stuff is used)*)
  33.  
  34.   FUNCTION GetSkipFlag:long_integer;
  35.     {Return the value of a constant encoded here. If the value is
  36.     $AAAAAAAA then set skip perforations on the printer.  If it is 
  37.     any other value, the printer settings will not be changed for 
  38.     this purpose alone. Since this function is early in the program 
  39.     it is relatively easy to find and change the value with 
  40.     a sector editor.}
  41.     BEGIN
  42.       GetSkipFlag := $AAAAAAAA;
  43.     END {marker};
  44.             
  45.   PROCEDURE DisplayExitBox;
  46.     VAR  Box : dialog_ptr;  OK : integer;
  47.     BEGIN
  48.       Box := New_Dialog(2,  70,21,8,3);
  49.       OK  := Add_DItem(Box,G_Button,
  50.                        Selectable |Exit_Btn | Default,
  51.                        2,1,4,1,   NoBorder,MyBlack);
  52.       Set_DText(Box,OK,' OK ',System_Font,TE_Left);
  53.       OK := Do_Dialog(Box,0);
  54.       End_Dialog(Box);
  55.       ClrScr;                 
  56.     END {displayexitbox};
  57.             
  58.     PROCEDURE SetUp;
  59.  
  60.     PROCEDURE DisplayCoverSheet;
  61.       CONST
  62.         w = 39;
  63.         h = 16;
  64.       VAR
  65.         s   : ARRAY [1..12] OF string[35];
  66.         Box : dialog_ptr;
  67.         OK  : integer;
  68.  
  69.       PROCEDURE MakeText
  70.                   (Box : dialog_ptr;
  71.                      X : integer;
  72.                      Y : integer;
  73.                  NChar : integer;
  74.                      S : string);
  75.         VAR  junk : integer;
  76.         BEGIN {maketext}
  77.           junk := Add_DItem(Box,G_String,None,
  78.                             X,Y,NChar,1,    NoBorder,MyBlack);
  79.           Set_DText(Box,junk,S,System_Font,TE_Left);
  80.         END {maketext};
  81.   
  82.       PROCEDURE DrawBox;
  83.         VAR
  84.           i, x, y : integer;
  85.         BEGIN
  86.         s[1] := '              FOREST     ';
  87.         s[2] := '           Version 2.0   ';
  88.         s[3] := '               by        ';
  89.         s[4] := '         Merlin L. Hanson';
  90.         s[5] := '          Genie Address: ';
  91.         s[6] := '            M.L.HANSON   '; 
  92.         s[7] := '                         ';
  93.         s[8] := '                         ';
  94.         s[9] := '  Portions of this product are';
  95.         s[10] := 'Copyright  1986, 1987 OSS and CCD.';
  96.         INSERT    (CHR(189),s[10],11           );
  97.         s[11] := '   Used by Permission of OSS.';
  98.         s[12] :=             ' OK ';
  99.         Box := New_Dialog(12,    0,0,w,h);
  100.         x := 3;  y := 1;
  101.         FOR i := 1 TO 11 DO
  102.           MakeText(Box,x,y + i, 34,    s[i]);
  103.         OK := Add_DItem(Box,G_Button,
  104.                   Selectable | Exit_Btn | Default,
  105.                   17,14,4,1,     NoBorder,MyBlack);
  106.         Set_DText(Box,OK,s[12],System_Font,TE_Left);
  107.         END {drawbox};
  108.  
  109.       begin  {displaycoversheet}
  110.         Clear_Screen;
  111.         DrawBox;
  112.         Center_Dialog(Box);
  113.         OK := Do_Dialog(Box,0);
  114.         End_Dialog(Box);
  115.         Delete_Dialog(Box);
  116.         Clear_Screen;
  117.       END {displaycoversheet};
  118.     
  119.       PROCEDURE OfferHelp;
  120.         VAR Choice : integer;
  121.         
  122.         PROCEDURE DisplayHelpScreen;
  123.           BEGIN 
  124.             Hide_Mouse;
  125.           CRTExit; {reset the CRT}
  126.           CRTInit; {automatic word wrap on.}
  127.             ClrScr;
  128.                 GoToXY(1,36);
  129.             WriteLn('FOREST.PRG');
  130.             GoToXY(2,35);
  131.             WriteLn('June 20,1988');
  132.                 GoToXY(3,14);
  133.             WriteLn('A program to show the structure of a Pascal program.');
  134.                 WriteLn; 
  135.             Write('The INPUT file should be a file that would be acceptible to a Pascal compiler,');
  136.                 WriteLn('  although it does not need a file extension of .PAS.');
  137.                 WriteLn;
  138.             Write('Text lines that declare PROCEDUREs, FUNCTIONs,');
  139.             Write(' Includes ( {$I, (*$I  ), and mostlines that have');
  140.             Write(' BEGIN followed by a comment will be displayed ');
  141.                 WriteLn('along with the    line number in the file.');
  142.                 WriteLn;
  143.                 WriteLn('Key words can be upper or lower case. The comment delimiter can be { or (*.');
  144.                 WriteLn;
  145.             WriteLn('The construct: ''BEGIN {\ comment}'' will NOT be printed.');
  146.                 WriteLn;
  147.                 Write('You will be asked for a tab setting.');
  148.             Write('  If your file doesn''t use tabs, the answer');
  149.             WriteLn(' must be a digit; but its'' value is immaterial.');         
  150.             Show_Mouse;
  151.                 DisplayExitBox;
  152.                 ClrScr;
  153.           END {displayhelpscreen};
  154.           
  155.         BEGIN {offerhelp}
  156.           Choice := Do_Alert(
  157.              '[2][  Do you want help?  ][ HELP | Who, ME? ]',2);
  158.           IF Choice = 1 THEN
  159.             DisplayHelpScreen;   
  160.         END {offerhelp};
  161.         
  162.     PROCEDURE GetInputFile;
  163.  
  164.       PROCEDURE GetDriveAndPath(VAR S:string);
  165.         {A procedure that returns a Pascal string containing the current drive,
  166.         current path and all punctuation.  Simply append a raw file name.}
  167.         VAR
  168.           i : integer;
  169.           T : string;
  170.           Path : string;
  171.           DriveString : string;
  172.  
  173.         FUNCTION CurrentDisk:integer;
  174.           {Returns an integer specifying the current drive. 0 specifies A, etc.}
  175.           GEMDOS($19);
  176.  
  177.         PROCEDURE GetDir(VAR Ptr:string; DriveID:integer);
  178.           {Puts a C string defining the folders currently open on DriveID
  179.           into S.  DriveID of 0 specifies the current drive.}
  180.           GEMDOS($47);
  181.  
  182.         BEGIN {getdriveandpath}
  183.           DriveString := CONCAT(CHR(ORD('A')+CurrentDisk),':');
  184.           GetDir(Path,0);
  185.           {Convert from C to Pascal.}
  186.           i := 0;
  187.           WHILE Path[i] <> CHR(0) DO
  188.             BEGIN
  189.               T[i+1] := Path[i];
  190.               i := i+1;
  191.             END;
  192.           {Set the length}
  193.           T[0] := CHR(i);
  194.           S := CONCAT(DriveString,T,'\');
  195.         END {getdriveandpath};
  196.  
  197.       BEGIN
  198.         GoToXY(3,34);
  199.         InverseVideo;
  200.         WriteLn('  Input File ');
  201.         NormVideo;
  202.         GetDriveAndPath(Path);
  203.         FileName := CONCAT('________.PAS',CHR(0));
  204.         IF Get_In_File(Path,FileName)
  205.           THEN RESET(MyInFile,FileName)
  206.           ELSE HALT; {user cancel}
  207.         ClrScr;             
  208.       END {getinputfile};
  209.  
  210.         PROCEDURE GetDestinationChoice;
  211.       VAR
  212.         Box            : dialog_ptr;
  213.         Pushed         : Tree_Index;
  214.         S              : string[20];
  215.         Index, BoxText : integer;
  216.         Item           : ARRAY [1..3] OF integer;
  217.         ObjectFlag     : ARRAY [1..3] OF integer;
  218.   
  219.       procedure IdentifyTheButton;
  220.         {returns with Pushed in the range 1..3}
  221.         VAR i : integer;
  222.           Find : boolean;
  223.         BEGIN
  224.           i := 1;
  225.           Find := FALSE;
  226.           REPEAT
  227.             IF Item[i] = Pushed
  228.               THEN Find := TRUE
  229.               ELSE i    := i+1;
  230.           UNTIL Find;
  231.           Pushed := i;
  232.         END {identifythebutton};
  233.   
  234.       BEGIN {getdestinationchoice};
  235.         ClrScr;
  236.         Box     := New_Dialog(5,0,0,40,14);
  237.         BoxText := Add_DItem(Box,G_String,None,
  238.                              5,3,40,1,
  239.                              NoBorder,MyBlack);
  240.         Set_DText(Box,BoxText,
  241.                   'Where do you want the output?',
  242.                   System_Font,TE_Center);
  243.         ObjectFlag[1] := Radio_Btn|Selectable|Exit_Btn;
  244.         ObjectFlag[2] := ObjectFlag[1] + Default;
  245.         ObjectFlag[3] := ObjectFlag[1];
  246.         FOR Index := 1 TO 3 DO
  247.           BEGIN
  248.             Item[Index] := Add_DItem(Box,G_Button,
  249.                                      ObjectFlag[Index],
  250.                                      5 + 11 * (Index - 1),7,    9,1,
  251.                                      NoBorder,MyBlack);
  252.             CASE Index OF
  253.               1 : S := 'Monitor';
  254.               2 : S := 'Printer';
  255.               3 : S := 'File';
  256.             END {case};
  257.             Set_DText(Box,Item[Index],S,System_Font,TE_Center);
  258.           END {do};
  259.         Center_Dialog(Box);
  260.         Pushed := Do_Dialog(Box,0);
  261.         IdentifyTheButton;
  262.         End_Dialog(Box);
  263.         CASE Pushed OF
  264.           1 : Choice := Monitor;
  265.           2 : Choice := Printer;
  266.           3 : Choice := FileX;
  267.         END {case};
  268.         ClrScr;
  269.       END {getdestinationchoice};
  270.   
  271.     PROCEDURE DrawEmptyBox;
  272.       VAR  Box : dialog_ptr;  
  273.       BEGIN
  274.         Box := New_Dialog(1,0,0,30,4);
  275.         Center_Dialog(Box);
  276.         Show_Dialog(Box,0);
  277.         GoTOXY(13,32);
  278.         Write(CRT,'Line Number:');
  279.       END {drawemptybox};
  280.       
  281.       PROCEDURE GetTabSetting;
  282.         LABEL 100;
  283.         VAR
  284.           Box : dialog_ptr;
  285.           S   : str255;     
  286.           junk,OK,TabN,Choice : integer;
  287.         BEGIN
  288. 100:
  289.           Hide_Mouse;
  290.           Clear_Screen;
  291.           Box := New_Dialog(3,0,0,30,7);
  292.  {LINE 1}
  293.           junk := Add_DItem(Box,G_Text,None,2,2,28,1,
  294.                              NoBorder,MyBlack);
  295.           Set_DText(Box,junk,'What is the Tab Size?',
  296.                     System_font,TE_Center);
  297.  {LINE 2}
  298.           TabN := Add_DItem(Box,G_FText,
  299.                             Editable,
  300.                             15,3,   1,1,  NoBorder,MyBlack);                  
  301.           Set_DEdit(Box,TabN,'_','9','2',System_Font,TE_Center);
  302.  {LINE 3}
  303.           OK := Add_DItem(Box,G_Button,
  304.                             Default|Selectable|Exit_Btn,
  305.                             13,5,  4,1,   NoBorder,MyBlack);
  306.           Set_DText(Box,OK,' OK ', System_Font,TE_Center); 
  307.                  
  308.           Center_Dialog(Box);
  309.           Show_Mouse;
  310.           junk := Do_Dialog(Box,TabN);
  311.           Get_DEdit(Box,TabN,S);
  312.           {convert digit to Binary}
  313.           NbrTab := ORD(S[1]) - 48;
  314.           {GEM allows invalid exit, e.g., <Backspace> or <Esc>.
  315.           Have to trap this case.}
  316.           IF (NbrTab < 0) OR (NbrTab > 9) THEN
  317.             GoTo 100;
  318.        END {gettabsetting};
  319.        
  320.     PROCEDURE SetUpPrinter;
  321.       VAR PrinterStatus, Choice : integer;
  322.  
  323.       function PtrStatus : integer;
  324.         GEMDOS($11);
  325.  
  326.       BEGIN {setupprinter}
  327.         PrinterStatus := PtrStatus;
  328.         WHILE PrinterStatus = 0 DO
  329.           BEGIN  
  330.             Choice := Do_Alert(
  331.              '[0][   Please turn the   |     printer on][ Abort | OK ]',2);
  332.             PrinterStatus := PtrStatus;
  333.             IF Choice = 1 THEN
  334.               HALT;
  335.           END;
  336.         {Printer is ready to go.}  
  337.         Choice := Do_Alert(
  338.             '[2][Change pitch on Epson|    printer?][ Yes | No ]',2);
  339.         IF Choice = 1 THEN 
  340.           BEGIN   {\change the pitch} 
  341.             {Note suppression on printing of above line by '\'}
  342.             Choice := Do_Alert(
  343.               '[0][ Characters per line ][ 80 | 132 | 160 ]',0);
  344.             WriteLn(CHR(ESC),'@');               {reset printer}
  345.             CASE Choice OF
  346.               1 :                 ;              {Pica draft} 
  347.               2 : WriteLn(CHR(15));              {compressed}
  348.               3 : WriteLn(CHR(ESC),'M',CHR(15)); {compressed Elite}
  349.             END {case};
  350.             PrinterModeChanged := TRUE;
  351.           END {choice = 1};
  352.         IF (Choice = 1) OR (GetSkipFlag = $AAAAAAAA)
  353.           THEN
  354.             BEGIN  
  355.               {Set form length to 11 inches.}
  356.               WriteLn(CHR(ESC),'C',CHR(0),CHR(11));
  357.               {Skip 6 line at the perforations.}
  358.               WriteLn(CHR(ESC),'N',CHR(6));     
  359.             END;  
  360.       END {setupprinter};             
  361.        
  362.     PROCEDURE InitializeReservedWords;
  363.       BEGIN
  364.         ReservedWord[1] := 'PROGRAM';
  365.         ReservedWord[2] := 'PROCEDURE';
  366.         ReservedWord[3] := 'FUNCTION';
  367.         ReservedWord[4] := '(*$I';
  368.         ReservedWord[5] := '(*$i';
  369.         ReservedWord[6] := '{$I';
  370.         ReservedWord[7] := '{$i';
  371.         ReservedWord[8] := 'BEGIN';
  372.       END {initializereservedwords};
  373.  
  374.     PROCEDURE PrintDate;  
  375.       {The file name has already been put on this line.  Add the date
  376.       at the right side of the paper and do a physical print.}
  377.       VAR m,d,y:integer;
  378.       BEGIN
  379.         Get_Date(m,d,y);
  380.         WriteLn(m:80-(LENGTH(FileName)+12), '/',d:2, '/',y:4);
  381.         WriteLn;
  382.       END {printdate};
  383.  
  384.     BEGIN {setup}
  385.       LineNbr := 0;
  386.       PrinterModeChanged := FALSE;
  387.       Init_Mouse;
  388.       DisplayCoverSheet;
  389.       OfferHelp;
  390.       GetInputFile;
  391.       GetTabSetting;  
  392.       GetDestinationChoice;
  393.       {Process the choice.}
  394.       CASE Choice OF
  395.         Monitor : BEGIN
  396.                     Hide_Mouse;
  397.                     ClrScr;
  398.                   END;  
  399.         Printer : BEGIN
  400.                     Rewrite(OUTPUT,'PRN:');
  401.                     SetUpPrinter;  
  402.                     Write(FileName);
  403.                     PrintDate;
  404.                   END;
  405.         FileX   : BEGIN
  406.                     GoToXY(3,35);
  407.                     InverseVideo;
  408.                     WriteLn(' Output File ');
  409.                     NormVideo;
  410.                     FileName := CONCAT('STRUCT  .TXT',CHR(0));
  411.                     {Bad procedure name, actually getting an output file.}
  412.                     IF Get_In_File(Path,FileName)
  413.                       THEN Rewrite(OUTPUT,FileName)
  414.                       ELSE HALT;
  415.                     ClrScr;
  416.                     REWRITE(CRT,'CON:');    
  417.                     DrawEmptyBox;  {Will hold line numbers}
  418.                   END;
  419.       END {case};
  420.       InitializeReservedWords;
  421.     END {setup};
  422.  
  423.   PROCEDURE Compute;
  424.  
  425.     PROCEDURE GetLine;
  426.       LABEL  100;
  427.       VAR
  428.         i, j : integer;    TextString : string[170];
  429.         ch : char;    Done : boolean;
  430.   
  431.       FUNCTION UpperCase(ch : char) : char;
  432.         BEGIN
  433.           IF (ch >= 'a') AND (ch <= 'z')
  434.             THEN UpperCase := CHR(ORD(ch) - 32{'a' - 'A'})
  435.             ELSE UpperCase := ch;
  436.         END {uppercase};
  437.  
  438.       PROCEDURE ChangeTabToSpaces;
  439.         VAR  k : integer;
  440.         BEGIN
  441.           {NbrCharInLine will be used by the WriteLine procedure.} 
  442.           NbrCharInLine := NbrCharInLine + (NbrTab - 1);
  443.           FOR k := 1 TO NbrTab DO
  444.             BEGIN
  445.               TextLine[j] := ' ';
  446.               TextUpperCase[j] := ' ';
  447.               j := j + 1;
  448.             END {do};             
  449.         END {changetabtospaces};
  450.  
  451.          
  452.       BEGIN {getline}
  453.         Done := FALSE;
  454.         REPEAT
  455.           IF EOF(MyInFile) 
  456.             THEN GoTo 100;
  457.           ReadLn(MyInFile,TextString);
  458.           IF LENGTH(TextString) = 0 
  459.             THEN LineNbr := LineNbr + 1
  460.             ELSE    Done := TRUE;
  461.         UNTIL Done;
  462.         NbrCharInLine := LENGTH(TextString);
  463.         j := 1;  
  464.         FOR i := 1 TO NbrCharInLine DO
  465.           BEGIN
  466.             IF TextString[i] = CHR(Tab)
  467.               THEN ChangeTabToSpaces
  468.               ELSE
  469.                 BEGIN
  470.                   TextLine[j] := TextString[i];
  471.                   TextUpperCase[j] := UpperCase(TextLine[j]);
  472.                   j := j + 1;
  473.                 END; 
  474.           END;
  475.         (*FOR i := 1 TO NbrCharInLine DO
  476.           Write(TextUpperCase[i]);
  477.         WriteLn;*)
  478.         LineNbr := LineNbr + 1;
  479. 100:
  480.       END {getline};
  481.   
  482.     PROCEDURE AnalyzeLine;
  483.       VAR  i : integer; Token : integer;
  484.   
  485.       PROCEDURE WriteLine;
  486.         VAR  i : integer;  AllBlank : boolean;
  487.     
  488.         PROCEDURE PrintBar;
  489.           BEGIN
  490.             IF i MOD 2 <> 0
  491.               THEN Write('|')
  492.               ELSE Write(' ');
  493.           END {printbar};
  494.     
  495.         PROCEDURE MeldStrings;
  496.           VAR i, j : integer;
  497.           BEGIN
  498.             i := 1;
  499.             WHILE TextLine[i] = ' ' DO
  500.               BEGIN
  501.                 IF i MOD 2 = 0 THEN
  502.                   TextLine[i] := '|';
  503.                 i := i + 1;
  504.               END;
  505.           END {meldstrings};
  506.     
  507.         BEGIN    {writeline}
  508.           Write(LineNbr:5,' ');
  509.           MeldStrings;
  510.           FOR i := 1 TO NbrCharInLine DO
  511.             Write(TextLine[i]);
  512.           WriteLn;
  513.         END {writeline};
  514.  
  515.       FUNCTION ReservedIsFirst(Index:integer):boolean;    
  516.         {The reserved word at Index is on the line, but it's not
  517.         necessarily the first token on the line.  Return TRUE if it
  518.         is the first, otherwise return FALSE.  All reserved words 
  519.         have at least three characters, base the decision on that.}
  520.         VAR i,j:integer; Match:boolean; S:string[255];
  521.         BEGIN
  522.           i := 1;
  523.           WHILE TextUpperCase[i] = ' ' DO
  524.             i := i+1;
  525.           {Assert: i points at the first non-blank.}
  526.           S := ReservedWord[Index];
  527.           Match := TRUE;
  528.           FOR j := 1 TO 3 DO
  529.             BEGIN
  530.               IF S[j] <> TextUpperCase[i]
  531.                 THEN Match := FALSE;
  532.               i := i+1;
  533.             END;  
  534.           ReservedIsFirst := Match;
  535.         END {reservedisfirst};
  536.  
  537.         FUNCTION PrintBegin:boolean;
  538.           {We know that 'begin' is on the line as the first text.
  539.           See if it is followed by a comment.  If it is and the printing 
  540.           of the comment is not suppressed, return TRUE, otherwise
  541.           return FALSE.}
  542.           VAR 
  543.             i,j :integer; 
  544.             Find:boolean;
  545.             S   : string;
  546.           BEGIN 
  547.             i := POS('N',TextStrUpper);
  548.             i := i+1;
  549.             WHILE (TextStrUpper[i] = ' ') 
  550.             AND (i < LENGTH(TextStrUpper)) DO
  551.               i := i+1;
  552.             Find := FALSE;  
  553.             {Assert: i points at the first non-blank after BEGIN.}
  554.             IF (LENGTH(TextStrUpper) - 5) < 0
  555.               THEN {get out of here. not enuf room for a comment}
  556.               ELSE
  557.                 BEGIN
  558.                   {Printing is suppressed iff '{\' or '(*\'}
  559.                   S := COPY(TextStrUpper,i,4);
  560.                   i := POS('{',S);
  561.                   j := POS('(*',S);
  562.                   IF (i > 0) AND (S[i+1] <> '\')
  563.                   OR
  564.                   ( (j > 0) AND (S[j+2] <> '\'))  
  565.                         THEN Find := TRUE;
  566.                 END;        
  567.             PrintBegin := Find;      
  568.           END {printbegin};
  569.  
  570.       BEGIN {analyzeline}
  571.         IF NbrCharInLine > 0
  572.           THEN
  573.             BEGIN
  574.               FOR i := 1 TO NbrCharInLine DO
  575.                 TextStrUpper[i+1] :=  TextUpperCase[i];
  576.               TextStrUpper[0] := CHR(NbrCharInLine);
  577.               (*WriteLn(TextStrUpper);*)
  578.               FOR Token := 1 TO 8 DO
  579.                 IF POS(ReservedWord[Token],TextStrUpper) <> 0
  580.                   THEN 
  581.                     IF ReservedIsFirst(Token)
  582.                       THEN 
  583.                         IF (Token < 8) 
  584.                         OR ((Token = 8) AND (PrintBegin))
  585.                           THEN WriteLine;
  586.             END;      
  587.       END {analyzeline};
  588.   
  589.     PROCEDURE DisplayLineNbr;
  590.       BEGIN
  591.         IF Choice = FileX
  592.           THEN
  593.             BEGIN   (*\ Don't print this line.*)
  594.               GoToXY(13,44);
  595.               Write(CRT,LineNbr:5);
  596.             END;
  597.       END {displaylinenbr};
  598.   
  599.     BEGIN {compute}
  600.       GetLine;
  601.       WHILE NOT EOF(MyInFile) DO
  602.         BEGIN
  603.           AnalyzeLine;
  604.           DisplayLineNbr;
  605.           GetLine;
  606.         END;
  607.     END {compute};
  608.  
  609.   PROCEDURE CleanUp;
  610.     BEGIN {cleanup}
  611.       IF Choice = FileX THEN
  612.         BEGIN
  613.           CLOSE(Output);
  614.           REWRITE(OUTPUT,'CON:');
  615.           GoToXY(17,20);
  616.           WriteLn('Output file sucessfully written and closed.');
  617.           ReadLn;
  618.         END;
  619.       Hide_Mouse;
  620.       Init_Mouse;
  621.       IF Choice = Monitor
  622.         THEN
  623.           DisplayExitBox;
  624.       ClrScr;
  625.       IF PrinterModeChanged THEN
  626.         WriteLn(CHR(ESC),'@');        {reset the printer}
  627.       {Next line logically shouldn't be needed; but mouse
  628.       handling is a black art on the ST.}
  629.       Show_Mouse;
  630.     END {cleanup};
  631.  
  632.   BEGIN             {main}
  633.     ClrScr;
  634.     IF Init_Gem >= 0 THEN
  635.       BEGIN
  636.         NbrTab := 2;
  637.         SetUp;
  638.         Set_Mouse(M_Bee);
  639.         Compute; 
  640.         CleanUp;
  641.         Exit_Gem;
  642.       END {GEM block};
  643.   END {program}.
  644. (*                         TABLE OF CONTENTS
  645.  
  646.     4 PROGRAM Forest2;   {Tab size = 2}
  647.    11  |{$I GEMSUBS.PAS}
  648.    32  |(*$I AUXSUBS.PAS (some of the VT-52 stuff is used)*)
  649.    34  |FUNCTION GetSkipFlag:long_integer;
  650.    45  |PROCEDURE DisplayExitBox;
  651.    58  |PROCEDURE SetUp;
  652.    60  | |PROCEDURE DisplayCoverSheet;
  653.    69  | | |PROCEDURE MakeText
  654.    76  | | | |BEGIN {maketext}
  655.    82  | | |PROCEDURE DrawBox;
  656.   109  | | |begin  {displaycoversheet}
  657.   119  | |PROCEDURE OfferHelp;
  658.   122  | | |PROCEDURE DisplayHelpScreen;
  659.   155  | | |BEGIN {offerhelp}
  660.   162  | |PROCEDURE GetInputFile;
  661.   164  | | |PROCEDURE GetDriveAndPath(VAR S:string);
  662.   173  | | | |FUNCTION CurrentDisk:integer;
  663.   177  | | | |PROCEDURE GetDir(VAR Ptr:string; DriveID:integer);
  664.   182  | | | |BEGIN {getdriveandpath}
  665.   210  | |PROCEDURE GetDestinationChoice;
  666.   219  | | |procedure IdentifyTheButton;
  667.   234  | | |BEGIN {getdestinationchoice};
  668.   271  | |PROCEDURE DrawEmptyBox;
  669.   281  | | |PROCEDURE GetTabSetting;
  670.   320  | |PROCEDURE SetUpPrinter;
  671.   323  | | |function PtrStatus : integer;
  672.   326  | | |BEGIN {setupprinter}
  673.   362  | |PROCEDURE InitializeReservedWords;
  674.   374  | |PROCEDURE PrintDate;  
  675.   384  | |BEGIN {setup}
  676.   423  |PROCEDURE Compute;
  677.   425  | |PROCEDURE GetLine;
  678.   431  | | |FUNCTION UpperCase(ch : char) : char;
  679.   438  | | |PROCEDURE ChangeTabToSpaces;
  680.   452  | | |BEGIN {getline}
  681.   482  | |PROCEDURE AnalyzeLine;
  682.   485  | | |PROCEDURE WriteLine;
  683.   488  | | | |PROCEDURE PrintBar;
  684.   495  | | | |PROCEDURE MeldStrings;
  685.   507  | | | |BEGIN    {writeline}
  686.   515  | | |FUNCTION ReservedIsFirst(Index:integer):boolean;    
  687.   537  | | | |FUNCTION PrintBegin:boolean;
  688.   570  | | |BEGIN {analyzeline}
  689.   589  | |PROCEDURE DisplayLineNbr;
  690.   599  | |BEGIN {compute}
  691.   609  |PROCEDURE CleanUp;
  692.   610  | |BEGIN {cleanup}
  693.   632  |BEGIN             {main}
  694.                                   *)
  695.  
  696.