home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / INFO / TURBOPAS / TURBOPR2.ZIP / TURBOPR2.PAS < prev   
Encoding:
Pascal/Delphi Source File  |  1985-11-06  |  31.8 KB  |  876 lines

  1. program TurboPr2;
  2. (*                                                                          *)
  3. (*  THIS PROGRAM is intended to print listings of Turbo Pascal programs.    *)
  4. (*  It was developed using Turbo Pascal version 3.0.                        *)
  5. (*  It shows LINE NUMBERS which match the record numbers in the source      *)
  6. (*    program so notes made on the listing can be moved to the code easily. *)
  7. (*  It shows the nesting level of BEGIN/END and CASE/END pairs.             *)
  8. (*  It will print a CROSS REFERENCE list after the program list if desired. *)
  9. (*  It will list INCLUDED FILES if desired.                                 *)
  10. (*  It provides print controlling PSEUDO-OPS to start and stop printing and *)
  11. (*    to eject a page.                                                      *)
  12. (*  It provides some support for the Hewlett-Packard LaserJet printer.      *)
  13. (*                                                                          *)
  14. (*  Rewritten by :  Don Mackenzie            11/6/85                        *)
  15. (*                  11065 La Paloma Dr.                                     *)
  16. (*                  Cupertino, CA  95014                                    *)
  17. (*                                                                          *)
  18. (*  with considerable help from others who came before:                     *)
  19. (*    This is based on program named PLIST originally written by Rick       *)
  20. (*    Shaeffer, E. 13611 26th Av, Spokane, Wa.  99216.                      *)
  21. (*    That program was modified by Len Whitten, CIS: [73545,1006] on 7/8/84.*)
  22. (*    Rick Schaeffer again made changes on 7/12/84.                         *)
  23. (*    On 8/28/84, Jay Kadashaw added several features.                      *)
  24. (*    Michael Roberts, [CIS 74226,3045], 3103 Glenview, Royal Oak, MI 48073 *)
  25. (*    added the Cross Referencing facility on 10/30/84.                     *)
  26. (*    The code in WhenCreated was written by Steve Griffen, dated 4/22/85,  *)
  27. (*    and was moved here from another version of the same root program.     *)
  28. (*                                                                          *)
  29. (*  I have removed most of their notes because later changes have undone    *)
  30. (*  some of what earlier contributors did, and it seemed time for a cleanup.*)
  31. (*  All of the earlier notes are in the file TURBOPR2.DOC.                  *)
  32. (*                                                                          *)
  33. (*  EXECUTING THE PROGRAM:                                                  *)
  34. (*    The program prints only one program per execution.  The file to print *)
  35. (*    and the parameters must be specified on the command line (or Option   *)
  36. (*    Parameters within Turbo Pascal).                                      *)
  37. (*        TURBOPR2 [d:][path]filename[.ext] [C] [P] [HP] [NI] [I] [X] [NX]  *)
  38. (*      If [.ext] is omitted, .PAS is assumed.                              *)
  39. (*      Parameters after the filename may be specified in any order.        *)
  40. (*      C  ( default ) specifies output on the Console.                     *)
  41. (*      P  specifies output on a 'normal' printer.                          *)
  42. (*      HP specifies output on a Hewlett Packard LaserJet printer.          *)
  43. (*      NI ( default ) specifies Included files are not to be listed.       *)
  44. (*      I  specifies Included files are to be listed.                       *)
  45. (*      X  ( default ) specifies a Cross-Reference listing is to be shown.  *)
  46. (*      NX specifies the Cross-Reference listing is to be skipped.          *)
  47. (*                                                                          *)
  48. (*    Three pseudo-ops are recognized.  Each must be on a line by itself    *)
  49. (*    and must begin in column 1.  They will be recognized even if embedded *)
  50. (*    in a comment field.  Upper or lower case is the same.                 *)
  51. (*      {.L-}   Causes that line and following lines to not be printed.     *)
  52. (*              All other functions, such as cross-referencing and          *)
  53. (*              begin/end counting do continue.                             *)
  54. (*      {.L+}   Restarts the printing of lines.                             *)
  55. (*      {.PAGE} Causes that line to be printed at the top of a new page.    *)
  56. (*                                                                          *)
  57. (*    The file TURBOPAS.RES must be in the current directory when the       *)
  58. (*    program is run.  This file contains the Turbo 3.0 reserved words.     *)
  59. (*                                                                          *)
  60. (*                                                                          *)
  61. (*  NOTES:                                                                  *)
  62. (*    Finding the File Creation Date:                                       *)
  63. (*         The routine WhenCreated may have problems under DOS 3.x if the   *)
  64. (*         codes for successful completion of the requested operations      *)
  65. (*         have been changed.  This has not been tested.                    *)
  66. (*    LaserJet support:                                                     *)
  67. (*         When HP is selected, printing is attempted with Line Printer     *)
  68. (*         font in Portrait mode at 8 lines per inch with a 10 column       *)
  69. (*         left margin.  This may be changed using constants HPMaxLine      *)
  70. (*         and HPSetupStr.                                                  *)
  71. (*    Normal Printer support:                                               *)
  72. (*         If you want to send special characters for font selection, etc., *)
  73. (*         change constants NormMaxLine, NormSetupStr, and NormEndStr.      *)
  74. (*                                                                          *)
  75. (*                                                                          *)
  76. {.page}
  77.  
  78.   const
  79.        { to customize code for your printer - adjust the next items }
  80.  
  81.     NormMaxLine   = 60;  { Used for Console and Normal Printer }
  82.     HPMaxLine     = 78;  { Used for HP LaserJet Printer        }
  83.  
  84.     HPSetupStr    = #27'E'#27'(s16H'#27'&l8D'#27'&a10L';
  85.     NormSetupStr  = '';
  86.  
  87.     HPEndStr      = #27'E';
  88.     NormEndStr    = #12;    { Form Feed }
  89.  
  90.     cr = #13;
  91.     lf = #10;
  92.     ff = #12;
  93.  
  94.   type
  95.  
  96.     HeadingType = ( Normal, Include, Xref );
  97.  
  98.     OutputType = (C,P,HP);  {Output Types are Console        }
  99.                             {                 Normal Printer }
  100.                             {                 HP LaserJet    }
  101.  
  102.  
  103.       { Following are used for the Cross Reference Listing system }
  104.     ResWordPtr = ^ResWordRec;
  105.     ResWordRec = Record
  106.                 ResWord: String[20];
  107.                 Next   : ResWordPtr;
  108.                 end;
  109.     XrefWordptr = ^XrefwordRec;
  110.     XrefNumPtr  = ^XrefNumRec;
  111.     XrefWordRec = Record
  112.                  XrefWord: string[20];
  113.                  FirstXrefNum: XrefNumPtr;
  114.                  LastXrefNum : XrefNumPtr;
  115.                  NextXrefWord: XrefwordPtr;
  116.                  end;
  117.     XrefNumRec  = record
  118.                  XrefNum : Integer;
  119.                  NextXrefNum:XrefNumPtr;
  120.                  end;
  121.  
  122.  
  123.     Str2   = string[  2];
  124.     Str8   = string[  8];
  125.     Str20  = string[ 20];
  126.     Str76  = string[ 76];   { maximum file name }
  127.     Str80  = string[ 80];
  128.     Str127 = string[127];   { maximum length of input line }
  129.     Str135 = string[135];   { input line with extra room }
  130.     Str255 = string[255];   { max length string for use as a parameter }
  131.     regpack = record
  132.       ax,bx,cx,dx,bp,si,di,ds,es,flags : integer;
  133.     end;
  134. {.page}
  135.  
  136.   var
  137.     MaxLine   : integer;    { Maximum lines allowed on a page. }
  138.     Buff1     : Str127;          {input line buffer}
  139.     Buff2     : Str135;           {working line buffer}
  140.  
  141.     FirstResWord, LastResWord, NewResWord, SrchResWord: ResWordPtr;
  142.     FirstxRefWord, NewxRefWord, PrevXrefWord, SrchxRefWord: XRefWordPtr;
  143.     NewXRefnum, SrchXRefNum: XRefNumPtr;
  144.     XrefWord  : string[20];
  145.     XrefNum   : Integer;
  146.  
  147.     ListFile    : text;              {FIB for LST: or CON: output}
  148.     MainFile    : text;              {FIB for Main input file}
  149.     InclFile    : text;              {FIB for Include input file}
  150.  
  151.     MainFileDate  : Str8;
  152.     MainFileTime  : Str8;
  153.  
  154.     InclFileDate  : Str8;
  155.     InclFileTime  : Str8;
  156.  
  157.     InclFileName   : Str76;         {Filename of Included file }
  158.  
  159.        { Following are parameters set in Command Line }
  160.     MainFileName   : Str76;         {input file name}
  161.     OutputDevice   : OutputType;    {Output file type indicator}
  162.     PrintXref      : boolean;       {Print/Don't Print Xref      }
  163.     ExpandIncludes : boolean;       {Expand/Don't Includes       }
  164.  
  165.     bcount    : integer;           {begin/end counter}
  166.     kcount    : integer;           {comment counter}
  167.     linect    : integer;           {output file line counter}
  168.     pageno    : integer;           {output page counter}
  169.     Print         : boolean;           (*  turned on/off by {.L+},{.L-}   *)
  170.     ForceHead     : boolean;     { Print a Header, irrespective of line count }
  171.     IncludeActive : boolean;    { true if printing an Included file }
  172.  
  173.     MainLineCnt  : integer;  { Count of Main File input lines }
  174.     InclLineCnt  : integer;  { Count of Incl File input lines }
  175. {.page}
  176.  
  177.   function UpCaseStr( StrX : Str255 ) : Str255;
  178.     { Converts StrX to all Upper Case. }
  179.     var
  180.       I : integer;
  181.     begin
  182.       UpCaseStr[0] := StrX[0];
  183.       for I := 1 to length(StrX) do
  184.         UpCaseStr[I] := UpCase(StrX[I]);
  185.     end;
  186.  
  187.   procedure FillBlanks (var line: Str8);
  188.     var
  189.       i : integer;
  190.     begin
  191.       for i:= 1 to 8 do
  192.         if line[i] = ' ' then
  193.           line[i]:= '0';
  194.     end;  {FillBlanks}
  195.  
  196.   function SysDate : Str8;
  197.     var
  198.       AllRegs : RegPack;
  199.       Month   : Str2;
  200.       Day     : Str2;
  201.       Year    : Str2;
  202.       Date    : Str8;
  203.     begin
  204.       AllRegs.ax := $2A * 256;
  205.       MsDos(AllRegs);
  206.       with AllRegs do
  207.       begin
  208.         str((dx div 256):2,Month);
  209.         str((dx mod 256):2,Day);
  210.         str((cx -  1900):2,Year);
  211.       end;
  212.       Date := Month + '/' + Day + '/' + Year;
  213.       FillBlanks (Date);
  214.       SysDate := Date;
  215.     end;  {GetDate}
  216.  
  217.   function SysTime : Str8;
  218.     var
  219.       AllRegs : RegPack;
  220.       Hour    : Str2;
  221.       Minute  : Str2;
  222.       Second  : Str2;
  223.       Time    : Str8;
  224.     begin
  225.       allregs.ax := $2C * 256;
  226.       MsDos(allregs);
  227.       with AllRegs do
  228.       begin
  229.         str((cx div 256):2,Hour);
  230.         str((cx mod 256):2,Minute);
  231.         str((dx div 256):2,Second);
  232.       end;
  233.       Time := Hour + ':' + Minute + ':' + Second;
  234.       FillBlanks (Time);
  235.       SysTime := Time;
  236.     end;  {GetTime}
  237. {.page}
  238.   function RsrvWordListOk : boolean;
  239.     var
  240.       RsrvFile    : text;              {FIB for reserved word file}
  241.       ResWord     : string[20];
  242.     begin
  243.       assign(RsrvFile,'TURBOPAS.RES');
  244.       {$I-}
  245.       reset(RsrvFile);
  246.       {$I+}
  247.       if IOResult = 0 then
  248.       begin
  249.         FirstResWord := nil;
  250.         while not eof(RsrvFile) do
  251.         begin
  252.           readln(RsrvFile,ResWord);
  253.           if length(ResWord) <> 0 then
  254.           begin
  255.             New(NewResWord);
  256.             NewResWord^.ResWord := Resword;
  257.             if FirstResWord = nil then
  258.               FirstResWord := NewResWord
  259.             else
  260.               LastResWord^.next := NewResWord;
  261.             LastResWord := NewResWord;
  262.             LastResWord^.Next := Nil;
  263.           end;
  264.         end;
  265.         Close(RsrvFile);
  266.         RsrvWordListOk := true;
  267.       end
  268.       else
  269.       begin
  270.         writeln(' Reserved Word List File TURBOPAS.RES Not Found. ');
  271.         RsrvWordListOk := false;
  272.       end;
  273.     end;   { RsrvWordListOk }
  274.  
  275.   function MainFileOk : boolean;
  276.     begin
  277.       assign( MainFile, MainFileName);
  278.       {$I-}
  279.       reset( MainFile );                {check for existence of file}
  280.       {$I+}
  281.       if IOResult = 0 then
  282.         MainFileOk := true
  283.       else
  284.       begin
  285.         writeln;
  286.         writeln('Input File ', MainFileName, ' DOESN''T EXIST');
  287.         MainFileOk := false
  288.       end;
  289.     end; {MainFileOk}
  290.  
  291.   function InclFileOk : boolean;
  292.     begin
  293.       assign( InclFile, InclFileName);
  294.       {$I-}
  295.       reset( InclFile );                {check for existence of file}
  296.       {$I+}
  297.       if IOResult = 0 then
  298.         InclFileOk := true
  299.       else
  300.         InclFileOk := false;
  301.     end; {InclFileOk}
  302.  
  303.   Procedure SetUpListFile;
  304.     begin
  305.       case OutputDevice of
  306.          C: begin
  307.               assign(ListFile,'CON:');
  308.               reset(ListFile);
  309.             end;
  310.          P: begin
  311.               assign(ListFile,'LST:');
  312.               reset(ListFile);
  313.               write(ListFile,NormSetupStr);
  314.             end;
  315.         HP: begin
  316.               assign(ListFile,'LST:');
  317.               reset(ListFile);
  318.               write(ListFile,HPSetupStr);
  319.             end;
  320.       end;
  321.     end;  {SetUpListFile}
  322.  
  323.   procedure ParseCommandLine;
  324.     var
  325.       Parameter : Str2;
  326.       I         : integer;
  327.     begin
  328.       MainFileName := '';            { Set Defaults Inputs }
  329.       ExpandIncludes := false;
  330.       PrintXref := true;
  331.       OutputDevice := C;
  332.  
  333.       if ParamCount >= 1 then
  334.       begin
  335.         MainFileName := ParamStr(1);
  336.         MainFileName := UpCaseStr(MainFileName);
  337.         if Pos('.',MainFileName) = 0 then
  338.           MainFileName := MainFileName + '.PAS';
  339.       end;
  340.       for I := 2 to ParamCount do
  341.       begin
  342.         Parameter := ParamStr(I);
  343.         Parameter := UpCaseStr(Parameter);
  344.         if      Parameter = 'I'  then ExpandIncludes := true
  345.         else if Parameter = 'NI' then ExpandIncludes := false
  346.         else if Parameter = 'X'  then PrintXref := true
  347.         else if Parameter = 'NX' then PrintXref := false
  348.         else if Parameter = 'HP' then OutputDevice := HP
  349.         else if Parameter = 'P'  then OutputDevice := P
  350.         else if Parameter = 'C'  then OutputDevice := C;
  351.       end;
  352.       if OutputDevice = HP then
  353.       begin
  354.         MaxLine := HPMaxLine;
  355.       end
  356.       else
  357.       begin
  358.         MaxLine := NormMaxLine;
  359.       end
  360.     end;   { ParseCommandLine }
  361.  
  362. {.page}
  363.   procedure WhenCreated (var date, time: Str8; filename: Str76);
  364.  
  365.     const
  366.       MonthMask  = $000F;
  367.       DayMask    = $001F;
  368.       MinuteMask = $003F;
  369.       SecondMask = $001F;
  370.  
  371.     type
  372.       FilRec = Record                          (* DTA layout        *)
  373.         file_ForD   : array[1..21]of byte;    (* reserved for DOS  *)
  374.         file_Attr   : byte;                   (* file attribute    *)
  375.         file_Time   : integer;                (* file time         *)
  376.         file_Date   : integer;                (* file date         *)
  377.         file_Size   : array[1..4] of byte;    (* file size         *)
  378.         file_Name   : array[1..13] of Char;   (* file name         *)
  379.         file_Fill   : array[1..85] of byte;   (* filler - ?????    *)
  380.       end;
  381.     var
  382.       AllRegs : RegPack;
  383.       fulltime,fulldate,DTAds,DTAdx: integer;
  384.       FileFCB    : FilRec;
  385.       filesearch : Str76;
  386.       Year       : Str2;
  387.       Month      : Str2;
  388.       Day        : Str2;
  389.       Hour       : Str2;
  390.       Minute     : Str2;
  391.       Second     : Str2;
  392.     begin         (* Get file date and time through DOS calls       *)
  393.                   (* to make program independent of Turbo versions. *)
  394.  
  395.                   (* Get current DTA and save location              *)
  396.       allregs.ax := $2F00;
  397.       Intr($21,allregs);
  398.       DTAds := allregs.es;
  399.       DTAdx := allregs.bx;
  400.  
  401.                   (* Set up DTA to recieve FCB of file.             *)
  402.       allregs.ax := $1A00;
  403.       allregs.dx := ofs(filefcb);
  404.       allregs.ds := seg(filefcb);
  405.       Intr($21,allregs);
  406.  
  407.                   (* Search for file to print.                      *)
  408.       allregs.ax := $4E00;
  409.       allregs.cx := $37;
  410.       filesearch := filename + chr(0);
  411.       allregs.dx := ofs(filesearch) + 1;
  412.       allregs.ds := Seg(filesearch);
  413.       Intr($21,allregs);
  414.       if Lo(allregs.ax) <> 0 then    (* Note that PCDOS 3.x uses a    *)
  415.                                   (* different flag for successful *)
  416.                                   (* file search, I believe.       *)
  417.       begin
  418.         writeln('          File ',filename,' not found.');
  419.         if Lo(allregs.ax) = 2 Then
  420.           Writeln('          Drive not ready.');
  421.         if Lo(allregs.ax) = 18 Then
  422.           Writeln('Program Error -- No file by that name');
  423.         HALT;
  424.       End;
  425.  
  426.              (* Restore DTA to previous location.               *)
  427.       allregs.ax := $1A00;
  428.       allregs.dx := DTAdx;
  429.       allregs.ds := DTAds;
  430.       Intr($21,allregs);
  431.  
  432.        {fulldate  corresponds to bytes 20-21
  433.         of the FCB.                 Format is: bits 0 - 4: day of month
  434.                                                     5 - 8: month of year
  435.                                                     9 -15: year - 1980     }
  436.  
  437.       with filefcb do
  438.         fulldate := file_Date;
  439.       str(((fulldate shr 9) + 80):2,year);
  440.       str(((fulldate shr 5) and monthmask):2,month);
  441.       str((fulldate and daymask):2,day);
  442.       date:= month + '/' + day + '/' + year;
  443.       FillBlanks(date);
  444.  
  445.         {fulltime  corresponds to bytes 22-23
  446.          of the FCB.                     Format is: bits 0 - 4: seconds/2
  447.                                                          5 -10: minutes
  448.                                                          11-15: hours         }
  449.  
  450.       with filefcb do
  451.         fulltime := file_Time;
  452.       str((fulltime shr 11):2,hour);
  453.       str(((fulltime shr 5) and minutemask):2,minute);
  454.       str(((fulltime and secondmask) * 2):2,second);
  455.       time:= hour + ':' + minute + ':' + second;
  456.       FillBlanks (time);
  457.     end;  {WhenCreated}
  458. {.page}
  459.  
  460.   procedure PrintHeading( Head : HeadingType);
  461.     { Checks conditions and prints a page heading if appropriate.   }
  462.     const
  463.       Space24 = '                          ';
  464.     var
  465.       PrintFileName : string[24];
  466.     begin
  467.       if print and (ForceHead or (LineCt > MaxLine) )then
  468.       begin
  469.         pageno := pageno + 1;
  470.         if LineCt > 0 then
  471.           write(ListFile, ff);  {top of form}
  472.         write(ListFile,'     TURBO Pascal Program Lister');
  473.         writeln(ListFile,' ':8,'Printed: ',sysdate,'  ',
  474.                             systime,'   Page ',pageno:4);
  475.         if Head = Include then
  476.           if length(InclFileName) > 20 then
  477.             PrintFileName := copy(InclFileName,length(InclFileName)-19,20)
  478.           else
  479.             PrintFileName := InclFileName
  480.                             + copy(Space24,1,20-length(InclFileName))
  481.         else
  482.           if length(MainFileName) > 23 then
  483.             PrintFileName := copy(MainFileName,length(MainFileName)-22,23)
  484.           else
  485.             PrintFileName := MainFileName
  486.                             + copy(Space24,1,23-length(MainFileName));
  487.  
  488.         if Head = Include then
  489.         begin
  490.           writeln(ListFile,'     Include File: ',PrintFileName,
  491.                  ' Created: ',InclFileDate,'  ',InclFileTime);
  492.         end
  493.         else  { Main or Xref type heading }
  494.         begin
  495.           writeln(ListFile,'     Main File: ',PrintFileName,
  496.                 ' Created: ',MainFileDate,'  ',MainFileTime);
  497.         end;
  498.         writeln(ListFile);
  499.         if Head = Xref then
  500.           writeln(ListFile,' ':32,'CROSS-REFERENCE')
  501.         else  { Main or Include type heading }
  502.           writeln(ListFile,'      B');
  503.         writeln(ListFile);
  504.         linect := 6;
  505.       end; {check for print}
  506.       ForceHead := false;
  507.     end;  {PrintHeading}
  508.  
  509. {.page}
  510.   Procedure BuildXref( Word:Str20; LineNo:integer );
  511.     Begin
  512.       if ((FirstXrefWord = nil) or (FirstXrefWord^.XrefWord > word)) then
  513.       begin              { Add Word at beginning of list }
  514.         new(newxrefword);
  515.         NewXrefWord^.NextXrefWord := FirstXrefWord;
  516.         FirstXrefWord := NewXrefWord;
  517.         FirstXrefWord^.XrefWord := word;
  518.         new(NewXrefNum);
  519.         FirstXrefWord^.FirstXrefNum := NewXrefNum;
  520.         FirstXrefWord^.LastXrefNum := NewXrefNum;
  521.         NewXrefNum^.NextXrefNum := nil;
  522.         NewXrefNum^.XrefNum := lineno;
  523.       end
  524.       else
  525.       begin              { Add reference to first word in list }
  526.         If firstXrefWord^.xrefword = word then
  527.         begin
  528.           New(NewXrefNum);
  529.           FirstXrefWord^.LastXrefNum^.NextXrefNum := NewXrefNum;
  530.           FirstXrefWord^.LastXrefNum := NewXrefnum;
  531.           NewXrefNum^.NextXrefNum := Nil;
  532.           NewXrefNum^.XrefNum := lineno;
  533.         end
  534.         else
  535.         Begin          { Look for Word in list }
  536.           SrchXrefWord := FirstXrefword^.NextXrefWord;
  537.           PrevXrefWord := FirstXrefWord;
  538.           While ((SrchXrefWord <> Nil) and
  539.                 (SrchXrefWord^.XrefWord < Word)) do
  540.           begin
  541.             PrevXrefWord := SrchXrefWord;
  542.             SrchXrefWord := SrchXrefWord^.NextXrefWord;
  543.           end;
  544.           If ((SrchXrefWord = nil) and
  545.              (PrevXrefWord^.XrefWord < word)) then
  546.           Begin      { Add Word at end of list }
  547.             new(newxrefword);
  548.             NewXrefWord^.NextXrefWord := Nil;
  549.             PrevXrefWord^.NextXrefWord := NewXrefWord;
  550.             NewXrefWord^.XrefWord := word;
  551.             new(NewXrefNum);
  552.             NewXrefWord^.FirstXrefNum := NewXrefNum;
  553.             NewXrefWord^.LastXrefNum := NewXrefNum;
  554.             NewXrefNum^.NextXrefNum := nil;
  555.             NewXrefNum^.XrefNum := lineno;
  556.           end
  557.           else
  558.             if SrchXrefWord^.XrefWord > Word Then
  559.             Begin    { Add Word in middle of list }
  560.               new(newxrefword);
  561.               NewXrefWord^.NextXrefWord := SrchXrefWord;
  562.               PrevXrefWord^.NextXrefWord := NewXrefWord;
  563.               NewXrefWord^.XrefWord := word;
  564.               NewXrefWord^.LastXrefNum := Nil;
  565.               new(NewXrefNum);
  566.               NewXrefWord^.FirstXrefNum := NewXrefNum;
  567.               NewXrefWord^.LastXrefNum := NewXrefNum;
  568.               NewXrefNum^.NextXrefNum := nil;
  569.               NewXrefNum^.XrefNum := lineno;
  570.             end
  571.             else
  572.             begin    { Add reference to an existing word }
  573.               New(NewXrefNum);
  574.               SrchXrefWord^.LastXrefNum^.NextXrefNum := NewXrefNum;
  575.               SrchXrefWord^.LastXrefNum := NewXrefnum;
  576.               NewXrefNum^.NextXrefNum := Nil;
  577.               NewXrefNum^.XrefNum := lineno;
  578.             end
  579.         end;
  580.       end;
  581.     end;   { BuildXref }
  582.  
  583.   function ReservedWord(var kword: Str20) : boolean;
  584.     Begin
  585.       SrchResWord := firstresword;
  586.       while ((kword > srchresword^.resword) and (srchresword <> nil)) do
  587.         srchresword := srchresword^.next;
  588.       if srchresword = nil then
  589.         ReservedWord := FALSE
  590.       else
  591.         if kword = srchresword^.resword then
  592.           ReservedWord := true
  593.         else
  594.           ReservedWord := false;
  595.     end;   { ReservedWord }
  596. {.page}
  597.  
  598.   procedure CheckIncludes;
  599.     var
  600.       i : integer;
  601.     begin
  602.       InclFileName := '';
  603.       if copy(Buff2, 1, 3) = '{$I' then
  604.       begin
  605.         i := 4;
  606.         while (Buff2[i] = ' ') and (i <= length(Buff2)) do
  607.           i := i + 1;
  608.         while (length(InclFileName) < 76)
  609.         and   (I <= length(Buff2))
  610.         and   not (Buff2[I] in [' ','}','+','-']) do
  611.         begin
  612.           InclFileName := InclFileName + UpCase(Buff2[i]);
  613.           i := i + 1;
  614.         end;
  615.       end;
  616.       if InclFileName <> '' then
  617.       begin
  618.         if pos('.',InclFileName) = 0 then
  619.           InclFileName := InclFileName + '.PAS';
  620.         IncludeActive := true;
  621.       end;
  622.     end;  {CheckIncludes}
  623.  
  624. {.page}
  625.   Procedure ScanLine;
  626.     { SCAN_LINE procedure scans one line of Turbo Pascal source code
  627.       looking for BEGIN/END pairs, CASE/END pairs, LITERAL fields
  628.       and COMMENT fields.  BCOUNT is begin/end and case/end counter.
  629.       KCOUNT is comment counter.  Begin/case/ends are only valid
  630.       outside of comment fields and literal constant fields (KCOUNT = 0
  631.       and NOT LITERAL).
  632.       Some of the code in the SCAN_LINE procedure appears at first glance
  633.       to be repitive and/or redundant, but was added to speed up the
  634.       process of scanning each line of source code.}
  635.  
  636.     var
  637.       Literal    : boolean;          { true if in literal field}
  638.       tmp        : string[7];        { tmp work area }
  639.       i          : integer;          {loop variable index}
  640.       IncFlName  : Str76;            {local include file name}
  641.       WordSwitch : boolean;       {if assembling an identifier}
  642.       WordCheck  : Str20;         {Identifier being assembled}
  643.     begin  { ScanLine }
  644.       Literal := false;
  645.       WordSwitch := false;
  646.       buff2[0] := buff1[0];  {copy input buffer to working buffer}
  647.       for i := 1 to length(buff1) do
  648.         buff2[i] := upcase(buff1[i]);  {and translate to upper case}
  649.  
  650.       if ExpandIncludes and not IncludeActive then
  651.         CheckIncludes;
  652.  
  653.       if copy(buff2,1,5) = '{.L-}' then
  654.         print := false;
  655.  
  656.       if copy(buff2,1,5) = '{.L+}' then
  657.         print := true;
  658.  
  659.       if copy(buff2,1,7) = '{.PAGE}' then
  660.         ForceHead := true;
  661.  
  662.  
  663.       buff2 := concat('  ', buff2, '      ');  {add on some working space}
  664.       for i := 1 to length(buff2) - 6 do
  665.       begin
  666.         tmp := copy(buff2, i, 7);
  667.         if not literal then   {possible to find comment delim}
  668.         begin
  669.           {determine if comment area delim}
  670.           if tmp[1] in ['{', '}', '(', '*'] then
  671.           begin
  672.             if (tmp[1] = '{') or (copy(tmp,1,2)='(*') then
  673.               kcount := succ(kcount);  {count comment opens}
  674.             if (tmp[1] = '}') or (copy(tmp,1,2)='*)') then
  675.               kcount := pred(kcount);  {un-count comment closes}
  676.           end;
  677.         end;
  678.  
  679.         if kcount = 0 then  {we aren't in a comment area}
  680.         begin
  681.           if tmp[1] = chr(39) then
  682.             Literal := not Literal;   {toggle literal flag}
  683.           if PrintXref and not Literal then
  684.           begin
  685.             if ((not WordSwitch) and
  686.                (buff2[i] in ['A'..'Z','a'..'z'])) then
  687.             Begin
  688.               WordSwitch := true;
  689.               WordCheck := '';
  690.             end;
  691.             if WordSwitch then
  692.               if (buff2[i] in ['A'..'Z','a'..'z','0'..'9','_']) then
  693.                 WordCheck := WordCheck + upcase(Buff2[i])
  694.               else
  695.               begin
  696.                 WordSwitch := false;
  697.                 if not ReservedWord(WordCheck) then
  698.                   if IncludeActive then
  699.                     BuildXref(WordCheck,InclLineCnt)
  700.                   else
  701.                     BuildXref(WordCheck,MainLineCnt);
  702.               end;
  703.           end; { PrintXref and not Literal }
  704.           if not literal and (tmp[2] in ['B','C','E']) then
  705.           begin
  706.             if (tmp = ' BEGIN ') or (copy(tmp,1,6) = ' CASE ') then
  707.             begin
  708.               bcount := succ(bcount);  {count BEGIN}
  709.               i := i + 5;              {skip rest of begin}
  710.             end;
  711.             if (copy(tmp,1,4) = ' END') and
  712.                (tmp[5] in ['.', ' ', ';']) and
  713.                (bcount > 0) then
  714.              begin
  715.                bcount := pred(bcount);   {un-count for END}
  716.                i := i + 4;
  717.              end;
  718.           end;  { if not literal and B, C or E }
  719.         end;  { if kcount = 0 }
  720.       end;  { for i := }
  721.     end;  {ScanLine}
  722. {.page}
  723.  
  724.   procedure ListInclFile;
  725.     const
  726.       Space8 = '        ';
  727.     begin  { ListInclFile }
  728.       InclFileDate := Space8;
  729.       InclFileTime := Space8;
  730.       if LineCt + 4 > MaxLine then   { be sure at least some of the  }
  731.         ForceHead := true;           { included file is on same page }
  732.       PrintHeading(Include);
  733.       writeln(ListFile,'*************************************');
  734.       writeln(ListFile,'    Including "'+InclFileName+'"');
  735.       writeln(ListFile,'*************************************');
  736.       LineCt := LineCt + 3;
  737.       if InclFileOk then
  738.       begin
  739.         WhenCreated (InclFileDate,InclFileTime,InclFileName);
  740.         InclLineCnt := 0;
  741.         while not eof(InclFile) do
  742.         begin
  743.           readln(InclFile, buff1);
  744.           InclLineCnt := succ(InclLineCnt);
  745.           ScanLine;
  746.           PrintHeading(Include);
  747.           if print then
  748.           begin
  749.             if length(buff1) > 0 then
  750.               writeln(ListFile,InclLineCnt : 4, bcount : 3, ' ', buff1)
  751.             else
  752.               writeln(ListFile,'        ',buff1);
  753.             linect := succ(linect);
  754.           end;
  755.         end; {while not eof}
  756.       end
  757.       else
  758.       begin
  759.         writeln(ListFile,'File ',InclFileName,' Not Found.');
  760.         LineCt := succ(LineCt);
  761.       end;
  762.       if LineCt + 3 > MaxLine then
  763.         ForceHead := true;
  764.       PrintHeading(Include);
  765.       writeln(ListFile,'*************************************');
  766.       writeln(ListFile,'    End of    "'+InclFileName+'"');
  767.       writeln(ListFile,'*************************************');
  768.       IncludeActive := false;
  769.     end; {ListInclFile}
  770.  
  771.   Procedure ListMainFile;
  772.     begin  { ListMainFile }
  773.       if MainFileOk then
  774.       begin
  775.         WhenCreated (MainFileDate,MainFileTime,MainFileName);
  776.         ForceHead := true;
  777.         MainLineCnt := 0;
  778.         while not eof(MainFile) do
  779.         begin
  780.           readln(MainFile, Buff1);
  781.           MainLineCnt := succ(MainLineCnt);
  782.           ScanLine;
  783.           PrintHeading(Normal);
  784.           if print then
  785.           begin
  786.               if length(buff1) > 0 then
  787.                 writeln(ListFile,MainLineCnt : 4, bcount : 3, ' ', buff1)
  788.               else
  789.                 writeln(ListFile,'        ',buff1);
  790.               linect := succ(linect);
  791.               if IncludeActive then
  792.                 ListInclFile;
  793.           end; {if print}
  794.         end; {while not eof}
  795.       end; {MainFileOk}
  796.     end; {ListMainFile}
  797.  
  798.   Procedure ListXref;
  799.     Const
  800.       blnk = ' ';
  801.     Var
  802.       x, y: Integer;
  803.  
  804.     Begin  { ListXref }
  805.       ForceHead := true;
  806.       PrintHeading(Xref);
  807.       Srchxrefword := Firstxrefword;
  808.       while SrchXrefWord <> Nil Do
  809.       Begin
  810.         x := 20 - Length(SrchXrefWord^.XrefWord);
  811.         for y := 1 to x do
  812.           SrchXrefWord^.XrefWord := concat(SrchXrefWord^.XrefWord,blnk);
  813.         Write(ListFile,srchxrefword^.XrefWord);
  814.         x := 0;
  815.         SrchXrefNum := SrchXrefWord^.FirstXrefNum;
  816.         while SrchXrefNum <> Nil do
  817.         begin
  818.           if X < 10 then
  819.           begin
  820.             Write(ListFile,SrchXrefNum^.XrefNum:5);
  821.             x := X + 1;
  822.           end
  823.           else
  824.           begin
  825.             Writeln(ListFile);
  826.             Linect := linect + 1;
  827.             PrintHeading(Xref);
  828.             Write(ListFile,blnk:20,SrchxrefNum^.XrefNum:5);
  829.             x := 0;
  830.           end;
  831.           SrchXrefNum := SrchXrefNum^.NextXrefNum;
  832.         end;
  833.         writeln(ListFile);
  834.         Linect := linect+1;
  835.         PrintHeading(Xref);
  836.         SrchXrefWord := SrchXrefWord^.NextXrefWord;
  837.       end;
  838.     end;   { ListXref }
  839.  
  840. {.page}
  841.   begin {main procedure}
  842.     if RsrvWordListOk then
  843.     begin
  844.       FirstXrefWord := nil;
  845.       ClrScr;
  846.       GotoXY(2, 2);
  847.       writeln('TURBO Pascal Formatted Listing');
  848.       GotoXY(2, 4);
  849.       ParseCommandLine;
  850.       if MainFileName <> '' then
  851.         if MainFileOk then
  852.         begin
  853.           SetUpListFile;
  854.  
  855.           pageno := 0;
  856.           linect := 0;      {output line counter}
  857.           kcount := 0;
  858.           bcount := 0;
  859.           ForceHead := true;
  860.           IncludeActive := false;
  861.           print := true;
  862.           ListMainFile;
  863.           if PrintXref then
  864.             ListXref;
  865.           if OutputDevice = HP then
  866.             write(ListFile,HPEndStr)
  867.           else
  868.             write(ListFile,NormEndStr);
  869.         end
  870.         else
  871.       else
  872.         writeln(
  873.               'File Name and Optional Parameters not found on Command Line.');
  874.     end;
  875.   end.  {main procedure}
  876.