home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / PLIST.ZIP / PLIST.PAS
Encoding:
Pascal/Delphi Source File  |  1984-12-23  |  25.6 KB  |  756 lines

  1. program PLIST;
  2. (*
  3.   Written by: Rick Schaeffer
  4.               E. 13611 26th Av.
  5.               Spokane, Wa.  99216
  6.  
  7.   modifications (7/8/84  by Len Whitten, CIS: [73545,1006])
  8.      1) added error handling if file not found
  9.      2) added default extension of .PAS to main & include files
  10.      3) added "WhenCreated" procedure to extract file
  11.         creation date & time from TURBO FIB
  12.      4) added demarcation of where include file ends
  13.      5) added upper char. conversion to include file
  14.      6) increased left margin to 5 spaces (80 char. line just fits @ 10cpi)
  15.      7) added listing control: {.L-} turns it off, {.L+} turns it back on,
  16.         must be in column 1
  17.      
  18.   further modifications (7/12/84 by Rick Schaeffer)
  19.      1) cleaned up the command line parsing routines and put them in
  20.         separate procedures.  Now permits any number of command line
  21.         arguments, each argument separated with at least one space.
  22.      2) added support for an optional second command line parameter
  23.         which specifies whether include files will be listed or not.
  24.         The command is invoked by placing "/i" on the command line
  25.         at least one space after the file name to be listed.  For
  26.         instance, to list MYPROG.PAS as well as any "included" files,
  27.         the command line would be: PLIST MYPROG /I
  28.  
  29.    further modification (8/28/84) by Jay Kadashaw)
  30.       1) Restored filedate and filetime after listing an included
  31.          file.
  32.       2) Added comment counter and begin/end counter.
  33.       3) Output can be routed to either the printer or console.
  34.       4) After listing first file the user is prompted for next
  35.          file if any.
  36.  
  37.    Still more modifications! (10/30/84) by Michael Roberts
  38.          1) Cleaned Up various problems I encountered
  39.          2) Removed Comment counter in order to add line numbers
  40.          3) Added Cross-Referencing facility
  41.             a) IMPORTANT!! Make sure when you create COM file you assign
  42.                The minimum segment sizes given in a MEM compile
  43.                (Particularly allow a minimum Stack Size Of 1300)
  44.             b) The file 'TURBOPAS.RES' contains the reserved words for
  45.                the TURBO Pascal compiler release 2.0.  If new reserved
  46.                words are implemented in future releases, add the new
  47.                words to this file.
  48.  
  49.             Please let me know if you run into any problems!
  50.                    Michael Roberts  [CIS 74226,3045]
  51.                    3103 Glenview
  52.                    Royal Oak, MI 48073
  53.  
  54. *)
  55.  
  56. (* Supported pseudo operations:
  57.     1) Listing control: {.L-} turns it off, {.L+} turns it back on,
  58.        must be in column 1
  59.     2. Page ejection: {.PAGE}, must be in column 1.
  60.     *)
  61.  
  62.  { When program is first run will check for a file
  63.    name passed by DOS, and will try to open that file.  If no name is
  64.    passed, will ask operator for a file name to open.  Proc will tell
  65.    operator if file doesn't exist and will allow multiple retrys.
  66.  
  67.    Included files will be expanded only if the program is invoked as
  68.    follows:
  69.      pretty filename /i
  70.    The default is not to expand included files.
  71.  
  72.    On 2nd and later executions, proc will not check for DOS passed file
  73.    name.  In all cases, proc will assume a file type of .PAS if file
  74.    type is not specified.
  75.    PROGRAM EXIT from this proc when a null string is encountered in
  76.    response to a file name request. }
  77. const monthmask = $000F;
  78.   daymask = $001F;
  79.   minutemask = $003F;
  80.   secondmask = $001F;
  81.   First   : boolean = true;    {true when prog is run}
  82.  
  83. { to customize code for your printer - adjust the next item }
  84.  
  85.   maxline = 58;
  86.  
  87.   cr = #13;
  88.   lf = #10;
  89.   ff = #12;
  90. type
  91.    ResWordPtr = ^ResWordRec;
  92.    ResWordRec = Record
  93.                 ResWord: String[20];
  94.                 Next   : ResWordPtr;
  95.                 end;
  96.    XrefWordptr = ^XrefwordRec;
  97.    XrefNumPtr  = ^XrefNumRec;
  98.    XrefWordRec = Record
  99.                  XrefWord: string[20];
  100.                  FirstXrefNum: XrefNumPtr;
  101.                  LastXrefNum : XrefNumPtr;
  102.                  NextXrefWord: XrefwordPtr;
  103.                  end;
  104.    XrefNumRec  = record
  105.                  XrefNum : Integer;
  106.                  NextXrefNum:XrefNumPtr;
  107.                  end;
  108.    alfa = string[15];
  109.    two_letters = string[2];
  110.    dtstr = string[8];
  111.    fnmtype = string[14];
  112.    instring = string[135];
  113.    regpack = record
  114.       ax,bx,cx,dx,bp,si,di,ds,es,flags : integer;
  115.    end;
  116.  
  117. Var
  118.   answer    : char;
  119.   Buff1     : instring;          {input line buffer}
  120.   FirstResWord, LastResWord, NewResWord, SrchResWord: ResWordPtr;
  121.   FirstxRefWord, NewxRefWord, PrevXrefWord, SrchxRefWord: XRefWordPtr;
  122.   NewXRefnum, SrchXRefNum: XRefNumPtr;
  123.   ResWord   : string[20];
  124.   XrefWord  : string[20];
  125.   XrefNum   : Integer;
  126.   wordchk   : alfa;
  127.   heaptop   : ^Integer;
  128.   listfil   : text;              {FIB for LST: or CON: output}
  129.   infile    : text;              {FIB for input file}
  130.   initfile  : text;              {FIB for reserved word file}
  131.   fnam      : fnmtype;           {in file name}
  132.   bcount    : integer;           {begin/end counter}
  133.   kcount    : integer;           {comment counter}
  134.   linect    : integer;           {output file line counter}
  135.   linecnt   : integer;
  136.   pageno    : integer;
  137.   offset    : integer;
  138.   print     : boolean;           (* {.L-} don't print *)
  139.                                  (* {.L+} print       *)
  140.   print_head : boolean;
  141.   Print_Xref : boolean;
  142.   Word_switch: Boolean;
  143.   c         : char;
  144.   month, day, year,
  145.   hour, minute, second : two_letters;
  146.   sysdate, systime,
  147.   filedate, filetime : dtstr;
  148.   expand_includes    : boolean;
  149.   holdarg            : instring;
  150.   allregs : regpack;
  151. {.page}
  152.  
  153. Function Find_in_Reserve(var kword: alfa) : boolean;
  154. Begin
  155.     SrchResWord := firstresword;
  156.     while ((kword > srchresword^.resword) and (srchresword <> nil)) do
  157.           srchresword := srchresword^.next;
  158.     if srchresword = nil then
  159.        Find_in_Reserve := FALSE
  160.     else
  161.         if kword = srchresword^.resword then
  162.            Find_in_reserve := true
  163.         else
  164.             Find_in_reserve := False;
  165. End;
  166.  
  167.  
  168.  
  169. PROCEDURE Initialize;
  170. BEGIN
  171.      assign(initfile,'TURBOPAS.RES');
  172.      reset(initfile);
  173.      FirstResWord := nil;
  174.      while not eof(initfile) do
  175.      begin
  176.           readln(initfile,ResWord);
  177.           if length(ResWord) <> 0 then
  178.              begin
  179.                   New(NewResWord);
  180.                   NewResWord^.ResWord := Resword;
  181.                   if FirstResWord = nil then
  182.                      FirstResWord := NewResWord
  183.                   else
  184.                      LastResWord^.next := NewResWord;
  185.                   LastResWord := NewResWord;
  186.                   LastResWord^.Next := Nil;
  187.              end;
  188.      end;
  189. END; {of Initialize}
  190.  
  191. procedure getchar(var char_value : char);
  192.    begin
  193.      allregs.ax := $0000;
  194.      intr($16, allregs);
  195.      char_value := chr(ord(lo(allregs.ax)));
  196.    end; {getchar}
  197.  
  198. procedure fill_blanks (var line: dtstr);
  199.   var
  200.     i : integer;
  201. begin
  202.   for i:= 1 to 8 do if line[i] = ' ' then line[i]:= '0';
  203. end;  {fill_blanks}
  204.  
  205. procedure getdate(var date : dtstr);
  206.  
  207. begin
  208.    allregs.ax := $2A * 256;
  209.    MsDos(allregs);
  210.    str((allregs.dx div 256):2,month);
  211.    str((allregs.dx mod 256):2,day);
  212.    str((allregs.cx - 1900):2,year);
  213.    date := month + '/' + day + '/' + year;
  214.    fill_blanks (date);
  215. end;  {getdate}
  216.  
  217. procedure gettime(var time : dtstr);
  218.  
  219. begin
  220.    allregs.ax := $2C * 256;
  221.    MsDos(allregs);
  222.    str((allregs.cx div 256):2,hour);
  223.    str((allregs.cx mod 256):2,minute);
  224.    str((allregs.dx div 256):2,second);
  225.    time := hour + ':' + minute + ':' + second;
  226.    fill_blanks (time);
  227. end;  {gettime}
  228.  
  229. procedure WhenCreated (var date, time: dtstr; var infile: text);
  230.  
  231. var fulltime,fulldate: integer;
  232.  
  233. begin
  234.  
  235. {fulldate gets the area of the FIB which corresponds to bytes 20-21
  236.  of the FCB. Format is: bits 0 - 4: day of month
  237.                              5 - 8: month of year
  238.                              9 -15: year - 1980                     }
  239.  
  240.     fulldate:= memw [seg(infile):ofs(infile)+31];
  241.     str(((fulldate shr 9) + 80):2,year);
  242.     str(((fulldate shr 5) and monthmask):2,month);
  243.     str((fulldate and daymask):2,day);
  244.     date:= month + '/' + day + '/' + year;
  245.     fill_blanks(date);
  246.  
  247. {fulltime gets the area of the FIB which corresponds to bytes 22-23
  248.  of the FCB. Format is: bits 0 - 4: seconds/2
  249.                              5 -10: minutes
  250.                              11-15: hours                          }
  251.  
  252.     fulltime:= memw [seg(infile):ofs(infile)+33];
  253.     str((fulltime shr 11):2,hour);
  254.     str(((fulltime shr 5) and minutemask):2,minute);
  255.     str(((fulltime and secondmask) * 2):2,second);
  256.     time:= hour + ':' + minute + ':' + second;
  257.     fill_blanks (time);
  258. end;  {WhenCreated}
  259.  
  260. Procedure BuildXref;
  261. Begin
  262.      if ((FirstXrefWord = nil) or (FirstXrefWord^.XrefWord > wordchk)) then
  263.         begin
  264.              new(newxrefword);
  265.              NewXrefWord^.NextXrefWord := FirstXrefWord;
  266.              FirstXrefWord := NewXrefWord;
  267.              FirstXrefWord^.XrefWord := wordchk;
  268.              new(NewXrefNum);
  269.              FirstXrefWord^.FirstXrefNum := NewXrefNum;
  270.              FirstXrefWord^.LastXrefNum := NewXrefNum;
  271.              NewXrefNum^.NextXrefNum := nil;
  272.              NewXrefNum^.XrefNum := linecnt;
  273.          end
  274.      else
  275.      begin
  276.           If firstXrefWord^.xrefword = wordchk then
  277.           begin
  278.                New(NewXrefNum);
  279.                FirstXrefWord^.LastXrefNum^.NextXrefNum := NewXrefNum;
  280.                FirstXrefWord^.LastXrefNum := NewXrefnum;
  281.                NewXrefNum^.NextXrefNum := Nil;
  282.                NewXrefNum^.XrefNum := linecnt;
  283.           end
  284.           else
  285.           Begin
  286.                SrchXrefWord := FirstXrefword^.NextXrefWord;
  287.                PrevXrefWord := FirstXrefWord;
  288.                While ((SrchXrefWord <> Nil) and
  289.                (SrchXrefWord^.XrefWord < WordChk)) do
  290.                begin
  291.                     PrevXrefWord := SrchXrefWord;
  292.                     SrchXrefWord := SrchXrefWord^.NextXrefWord;
  293.                end;
  294.                If ((SrchXrefWord = nil) and
  295.                   (PrevXrefWord^.XrefWord < wordchk)) then
  296.                   Begin
  297.                        new(newxrefword);
  298.                        NewXrefWord^.NextXrefWord := Nil;
  299.                        PrevXrefWord^.NextXrefWord := NewXrefWord;
  300.                        NewXrefWord^.XrefWord := wordchk;
  301.                        new(NewXrefNum);
  302.                        NewXrefWord^.FirstXrefNum := NewXrefNum;
  303.                        NewXrefWord^.LastXrefNum := NewXrefNum;
  304.                        NewXrefNum^.NextXrefNum := nil;
  305.                        NewXrefNum^.XrefNum := linecnt;
  306.                   end
  307.                   else
  308.                       if SrchXrefWord^.XrefWord > Wordchk Then
  309.                       Begin
  310.                            new(newxrefword);
  311.                            NewXrefWord^.NextXrefWord := SrchXrefWord;
  312.                            PrevXrefWord^.NextXrefWord := NewXrefWord;
  313.                            NewXrefWord^.XrefWord := wordchk;
  314.                            NewXrefWord^.LastXrefNum := Nil;
  315.                            new(NewXrefNum);
  316.                            NewXrefWord^.FirstXrefNum := NewXrefNum;
  317.                            NewXrefWord^.LastXrefNum := NewXrefNum;
  318.                            NewXrefNum^.NextXrefNum := nil;
  319.                            NewXrefNum^.XrefNum := linecnt;
  320.                       end
  321.                       else
  322.                       begin
  323.                            SrchXrefWord := SrchXrefWord^.NextXrefWord;
  324.                            New(NewXrefNum);
  325.                            SrchXrefWord^.LastXrefNum^.NextXrefNum := NewXrefNum;
  326.                            SrchXrefWord^.LastXrefNum := NewXrefnum;
  327.                            NewXrefNum^.NextXrefNum := Nil;
  328.                            NewXrefNum^.XrefNum := linecnt;
  329.                       end
  330.           end;
  331.      end;
  332. end;
  333.  
  334. procedure print_heading(filename : fnmtype);
  335.  
  336. var offset_inc: integer;
  337.  
  338. begin
  339.    if print then
  340.      begin
  341.        pageno := pageno + 1;
  342.        write(listfil, ff);  {top of form}
  343.        writeln(listfil);
  344.        write(listfil,'     TURBO Pascal Program Lister');
  345.        writeln(listfil,' ':8,'Printed: ',sysdate,'  ',
  346.                systime,'   Page ',pageno:4);
  347.        if filename <> fnam then begin
  348.           offset_inc:= 14 - length (filename);
  349.           write(listfil,'     Include File: ',filename,' ':offset_inc,
  350.              'Created: ',filedate,'  ',filetime);
  351.        end
  352.        else write(listfil,'     Main File: ',fnam,' ':offset,
  353.              'Created: ',filedate,'  ',filetime);
  354.        writeln(listfil); writeln(listfil);
  355.        If Print_Xref then
  356.           Writeln(Listfil,' ':32,'CROSS-REFERENCE')
  357.        else
  358.            writeln(listfil, '      B');
  359.        writeln(listfil);
  360.        linect := 6;
  361.      end; {check for print}
  362. end;  {print_heading}
  363.  
  364. procedure printline(iptline : instring; filename : fnmtype);
  365. begin
  366.    if print then
  367.      begin
  368.        if linect < 56 then
  369.          begin
  370.           writeln(listfil,'     ',iptline);
  371.           linect := linect + 1;
  372.          end
  373.           else
  374.            begin
  375.              print_heading(filename);
  376.            end;
  377.      end; {check for print}
  378. end;  {printline}
  379. {.page}
  380. function chkinc(var iptline : instring; var incflname : fnmtype) : boolean;
  381. var
  382.    done : boolean;
  383.    i, j : integer;
  384. begin
  385.    i := 4; j := 1; incflname := '';
  386.    if copy(iptline, 1, 3) = '{$I' then begin
  387.       i := 4; j := 1; incflname := '';
  388.       while (iptline[i] = ' ') and (i <= length(iptline)) do i := i + 1;
  389.       done := false;
  390.       while not done do begin
  391.          if i <= length(iptline) then begin
  392.             if not (iptline[i] in [' ','}','+','-']) then begin
  393.                incflname[j] := iptline[i];
  394.                i := i + 1; j := j + 1;
  395.             end else done := true;
  396.          end else done := true;
  397.          if j > 14 then done := true;
  398.       end;
  399.       incflname[0] := chr(j - 1);
  400.    end;
  401.    if incflname <> '' then
  402.      begin
  403.           chkinc := true;
  404.           for i := 1 to length(Incflname) do
  405.               incflname[i] := upcase(incflname[i]);
  406.      end
  407.      else
  408.          chkinc := false;
  409. end;  {chkinc}
  410.  
  411. function parse_cmd(argno : integer) : instring;
  412. var
  413.    i,j : integer;
  414.    wkstr : instring;
  415.    done : boolean;
  416.    cmdline : ^instring;
  417. begin
  418.    cmdline := ptr(CSEG,$0080);
  419.    wkstr := '';
  420.    done := false; i := 1; j := 0;
  421.    if length(cmdline^) < i then done := true;
  422.    repeat
  423.       while ((cmdline^[i] = ' ') and (not done)) do begin
  424.          i := i + 1;
  425.          if i > length(cmdline^) then done := true;
  426.       end;
  427.       if not done then j := j + 1;
  428.       while ((cmdline^[i] <> ' ') and (not done)) do begin
  429.          wkstr := wkstr + cmdline^[i];
  430.          i := i + 1;
  431.          if i > length(cmdline^) then done := true;
  432.       end;
  433.       if (j <> argno) then wkstr := '';
  434.    until (done or (j = argno));
  435.    for i := 1 to length(wkstr) do
  436.       wkstr[i] := upcase(wkstr[i]); {all arguments forced to upper case}
  437.    parse_cmd := wkstr;
  438. end;
  439.  
  440.  PROCEDURE GET_IN_FILE;     {GETS INPUT FILE NAME }
  441.    var
  442.     existing : boolean;
  443.     i        : integer;
  444.   begin
  445.     repeat             {until file exists}
  446.       holdarg := parse_cmd(1); {get command line argument # 1}
  447.       if (length(holdarg) in [1..14]) and first then
  448.         fnam := holdarg  {move possible file name to fnam}
  449.       else
  450.         begin
  451.           writeln;
  452.           write(' ENTER FILE NAME TO LIST or <cr> to EXIT  ');
  453.           readln(fnam);
  454.           if fnam <> '' then
  455.              begin
  456.                   writeln;write(' EXPAND INCLUDES? (Y/N) ');
  457.                   readln(answer);
  458.                   if upcase(answer) = 'Y' then
  459.                      expand_includes := true
  460.                   else
  461.                       expand_includes := false
  462.              end
  463.         end;
  464.  
  465.      for i := 1 to length(fnam) do
  466.          fnam[i] := upcase(fnam[i]);
  467.  
  468.      if fnam = '' then HALT;         {***** EXIT *****}
  469.      if pos('.',fnam) = 0 then       {file type given?}
  470.        fnam := concat(fnam,'.PAS');  {file default to .PAS type}
  471.  
  472.      {get optional command line argument # 2}
  473.      if (length(holdarg) in [1..14]) and first then
  474.        begin
  475.          holdarg := parse_cmd(2);
  476.          if holdarg = '/I' then expand_includes := true
  477.             else expand_includes := false;
  478.        end;
  479.  
  480.      first := false;                 {get passed file name only once}
  481.      assign( infile, fnam);
  482.        {$I-}
  483.      reset( infile );                {check for existence of file}
  484.        {$I+}
  485.      existing := (ioresult = 0);     {true if file found}
  486.      if not existing then
  487.        begin
  488.         writeln;
  489.         writeln(' FILE DOESN''T EXIST'); {tell operator the sad news}
  490.        end;
  491.     until existing;                     {until file exists}
  492.  end; {GET_IN_FILE}
  493.  
  494. { GET_OUT_FILE procedure asks operator to select output to console
  495.   device or list device, and then assigns and resets a file control
  496.   block to the appropriate device.  'C' or 'P' is only correct
  497.   response, and multiple retrys are allowed. }
  498.  
  499. Procedure Get_Out_File;
  500.   var
  501.     c : char;
  502.   begin
  503.     repeat    {until good selection}
  504.       writeln; write(' OUTPUT LISTING TO (C)ONSOLE OR (P)RINTER ?  ');
  505.       getchar(c);
  506.       c := upcase(c); write(c);
  507.    until c in ['C', 'P'];
  508.  
  509.    writeln;
  510.    if c = 'C' then
  511.       assign (listfil, 'CON:')
  512.    else
  513.       assign (listfil, 'LST:');
  514.  
  515.    reset(listfil);
  516.  end;  {GET_OUT_FILE}
  517.  
  518. Procedure ListIt(filename : fnmtype); forward;
  519. {.page}
  520. { SCAN_LINE procedure scans one line of Turbo Pascal source code
  521.   looking for BEGIN/END pairs, CASE/END pairs, LITERAL fields
  522.   and COMMENT fields.  BCOUNT is begin/end and case/end counter.
  523.   KCOUNT is comment counter.  Begin/case/ends are only valid
  524.   outside of comment fields and literal constant fields (KCOUNT = 0
  525.   and NOT LITERAL).
  526.   Some of the code in the SCAN_LINE procedure appears at first glance
  527.   to be repitive and/or redundant, but was added to speed up the
  528.   process of scanning each line of source code.}
  529.  
  530. Procedure SCAN_LINE;
  531.   var
  532.     literal : boolean;          { true if in literal field}
  533.     tmp     : string[7];        { tmp work area }
  534.     i       : integer;          {loop variable index}
  535.     buff2   : instring;         {working line buffer}
  536.     incflname : fnmtype;        {in file name}
  537.     filedate_save : dtstr;
  538.     filetime_save : dtstr;
  539.   begin
  540.     literal := false;
  541.  
  542.     buff2[0] := buff1[0];  {copy input buffer to working buffer}
  543.     for i := 1 to length(buff1) do
  544.      buff2[i] := upcase(buff1[i]);  {and translate to upper case}
  545.  
  546.     if chkinc(buff2, incflname) and expand_includes then
  547.        begin
  548.        for i := 1 to length(incflname) do
  549.            incflname[i] := upcase(incflname[i]);
  550.           if pos('.',incflname) = 0 then incflname := incflname + '.PAS';
  551.           printline('*************************************',incflname);
  552.           printline('    Including "'+incflname+'"', incflname);
  553.           printline('*************************************',incflname);
  554.           filedate_save := filedate;  {save filedate & filetime for}
  555.           filetime_save := filetime;  {main file                   }
  556.           listit(incflname);
  557.           filedate := filedate_save;  {restore}
  558.           filetime := filetime_save;
  559.           printline('*************************************',incflname);
  560.           printline('    End of    "'+incflname+'"', incflname);
  561.           printline('*************************************',incflname);
  562.           linecnt := linecnt - 1;
  563.          end;  {include file check}
  564.  
  565.     if copy(buff2,1,5) = '{.L-}' then
  566.        begin
  567.             print := false;
  568.             if length(buff2) = 5 then
  569.                linecnt := linecnt - 1;
  570.        end;
  571.  
  572.     if copy(buff2,1,5) = '{.L+}' then
  573.        begin
  574.             print := true;
  575.             if length(buff2) = 5 then
  576.                linecnt := linecnt - 1;
  577.        end;
  578.  
  579.     if copy(buff2,1,7) = '{.PAGE}' then
  580.        begin
  581.             print_head := true;
  582.             if length(buff2) = 7 then
  583.                linecnt := linecnt - 1;
  584.        end;
  585.  
  586.     if length(buff2) > 0 then
  587.        linecnt := linecnt + 1;
  588.  
  589.     buff2 := concat('  ', buff2, '      ');  {add on some working space}
  590.     for i := 1 to length(buff2) - 6 do
  591.       begin
  592.         tmp := copy(buff2, i, 7);
  593.         if not literal then   {possible to find comment delim}
  594.           begin
  595.            {determine if comment area delim}
  596.            if tmp[1] in ['{', '}', '(', '*'] then
  597.              begin
  598.                if (tmp[1] = '{') or (copy(tmp,1,2)='(*') then
  599.                  kcount := succ(kcount);  {count comment opens}
  600.                if (tmp[1] = '}') or (copy(tmp,1,2)='*)') then
  601.                  kcount := pred(kcount);  {un-count comment closes}
  602.              end;
  603.           end;
  604.  
  605.          if kcount = 0 then  {we aren't in a comment area}
  606.            begin
  607.             if tmp[1] = chr(39) then
  608.               literal := not literal;   {toggle literal flag}
  609.             if not literal then
  610.             begin
  611.               if ((not Word_switch) and
  612.                  (buff2[i] in ['A'..'Z','a'..'z'])) then
  613.                            Begin
  614.                                 Word_switch := true;
  615.                                 wordchk := '';
  616.                            end;
  617.               if word_switch then
  618.                  if (buff2[i] in ['A'..'Z','a'..'z','0'..'9','_']) then
  619.                     wordchk := concat(wordchk,upcase(Buff2[i]))
  620.                  else
  621.                  begin
  622.                       word_switch := false;
  623.                       if not find_in_reserve(wordchk) then
  624.                          BuildXref;
  625.                  end;
  626.               end;
  627.            if not literal and (tmp[2] in ['B','C','E']) then
  628.              begin
  629.                if (tmp = ' BEGIN ') or (copy(tmp,1,6) = ' CASE ') then
  630.                 begin
  631.                  bcount := succ(bcount);  {count BEGIN}
  632.                  i := i + 5;              {skip rest of begin}
  633.                 end;
  634.                if (copy(tmp,1,4) = ' END') and
  635.                   (tmp[5] in ['.', ' ', ';']) and
  636.                    (bcount > 0) then
  637.                 begin
  638.                  bcount := pred(bcount);   {un-count for END}
  639.                  i := i + 4;
  640.                 end;
  641.  
  642.               end;  {if not literal}
  643.            end;  { if kcount = 0 }
  644.         end;  { for i := }
  645.     end;  {SCAN_LINE}
  646. {.page}
  647. Procedure ListIt;
  648.   var
  649.     infile : text;
  650.   begin
  651.      assign(infile, filename);
  652.    {$I-} reset(infile) {$I+} ;
  653.    if IOresult <> 0 then begin
  654.       writeln ('File ',filename,' not found.');
  655.       halt;
  656.    end;
  657.      WhenCreated (filedate,filetime,infile);
  658.          print_heading(filename);
  659.          while not eof(infile) do
  660.            begin
  661.             readln(infile, buff1);
  662.             scan_line;
  663.             if print_head then
  664.                 print_heading(filename);
  665.             if print and (not print_head) then
  666.               begin
  667.                 if length(buff1) > 0 then
  668.                    writeln(listfil,linecnt : 4, bcount : 3, ' ', buff1)
  669.                 else
  670.                    writeln(listfil,'        ',buff1);
  671.                 linect := succ(linect);
  672.                 if linect > maxline then
  673.                   begin
  674.                     print_heading(filename);
  675.                   end;
  676.               end;
  677.             print_head := false;
  678.          end;     {while not eof}
  679.   end; {ListIt}
  680.  
  681. Procedure ListXref;
  682. Const
  683.      blnk = ' ';
  684. Var
  685.    x, y: Integer;
  686.  
  687. Begin
  688.      Print_Xref := True;
  689.      Print_heading(fnam);
  690.      Srchxrefword := Firstxrefword;
  691.      while SrchXrefWord <> Nil Do
  692.      Begin
  693.           x := 20 - Length(SrchXrefWord^.XrefWord);
  694.           for y := 1 to x do
  695.               SrchXrefWord^.XrefWord := concat(SrchXrefWord^.XrefWord,blnk);
  696.           Write(listfil,srchxrefword^.XrefWord);
  697.           x := 0;
  698.           SrchXrefNum := SrchXrefWord^.FirstXrefNum;
  699.           while SrchXrefNum <> Nil do
  700.           begin
  701.                if X < 10 then
  702.                begin
  703.                     Write(listfil,SrchXrefNum^.XrefNum:5);
  704.                     x := X + 1;
  705.                end
  706.                else
  707.                begin
  708.                     Writeln(listfil);
  709.                     Linect := linect + 1;
  710.                     if linect > maxline then Print_heading(fnam);
  711.                     Write(listfil,blnk:20,SrchxrefNum^.XrefNum:5);
  712.                     x := 0;
  713.                end;
  714.                SrchXrefNum := SrchXrefNum^.NextXrefNum;
  715.           end;
  716.           writeln(listfil);
  717.           Linect := linect+1;
  718.           if linect > Maxline then Print_heading(fnam);
  719.           SrchXrefWord := SrchXrefWord^.NextXrefWord;
  720.      end;
  721. end;
  722. {.page}
  723.   begin {main procedure}
  724.      getdate(sysdate);
  725.      gettime(systime);
  726.      expand_includes := false;       {default settings}
  727.      print := true;
  728.      initialize;
  729.      Mark(heaptop);
  730.  
  731.    repeat {forever}
  732.      Release(heaptop);
  733.      FirstXrefWord := nil;
  734.      ClrScr;
  735.      GotoXY(2, 2);
  736.      writeln('TURBO Pascal Formatted Listing');
  737.      GotoXY(2, 4);
  738.      get_in_file;      {file to list}
  739.      offset := 24 - length(fnam);
  740.      get_out_file;     {where to list it}
  741.      pageno := 0;
  742.      linect := 1;      {output line counter}
  743.      kcount := 0;
  744.      linecnt := 0;
  745.      bcount := 0;
  746.      print_head := false;
  747.      Print_xref := False;
  748.      word_switch:= False;
  749.      listit(fnam);
  750.      Listxref;
  751.     write(cr, lf, 'HIT ANY KEY TO CONTINUE ');  {allow op to see end
  752.                                                  of listing}
  753.     getchar(c);
  754.     until false {repeat forever - exit is in GET_IN_FILE PROCEDURE}
  755.  end.  {main procedure}
  756.