home *** CD-ROM | disk | FTP | other *** search
/ Programmer 7500 / MAX_PROGRAMMERS.iso / PASCAL / TURBOPRT.ZIP / TURBOPRT.PAS
Encoding:
Pascal/Delphi Source File  |  1986-03-09  |  35.0 KB  |  1,003 lines

  1. {$U+,R+}
  2. program TurboPrt;
  3.  
  4. (* 
  5.                         Version 1.5 
  6.  
  7.                        for PC/MS-DOS
  8.  
  9.  
  10.   Written by: Michael Roberts
  11.               3103 Glenview
  12.               Royal Oak, Mi 48073
  13.               Compuserve : 74226,3045
  14.  
  15.             This program is built on a listing program by Rick Schaeffer.
  16.  
  17.  
  18.   Modified by: Earl Hall
  19.                5619 N. Spaulding #3
  20.                Chicago, IL  60659
  21.                CompuServe : 72746,3244
  22.  
  23.             Please let me know if you run into any problems or have any
  24.             suggestions.  This program is currently going through major
  25.             revisions (see revision history below), so stay tuned!
  26.  
  27.                   ========    Revision History   =======
  28.  
  29.     9/18/85 -  Changes due to the use of DOS file handles in Turbo 3.x:
  30.    (ver 1.1)     1.   Changed WhenCreated procedure to use DOS function 57h
  31.                       to get date/time from file handle.
  32.                       (Probably means that it won't work with older
  33.                         versions of the Turbo compiler. Oh, well.)
  34.                  2.   Added file close to ListIt procedure.
  35.                       Otherwise, program would run out of file handles.
  36.  
  37.             -  Fixed problem where program was printing the last line of
  38.                an included file twice.
  39.             -  Include REPEATs in the count of block levels ('B' column).
  40.             -  Changed filename of reserved words to TURBOPRT.RES.
  41.             -  Include blank lines, and those with supported psuedo
  42.                operations ($I,$L+,$L-,.PAGE), in line count (like Turbo's
  43.                editor and compiler do).  ($L+,$L-, and .PAGE lines are
  44.                still not printed.)
  45.             -  Fixed PrintLine procedure; was failing to print if heading
  46.                had to be printed first.
  47.             -  Added check for position on paper to avoid {.PAGE} directive
  48.                causing an extra skip to top of form.
  49.  
  50.     9/19/85 -  Add printer control codes for Gemini 10x printer.  Original
  51.    (ver 1.2)   printer codes remain (commented out).  "Compressed" mode
  52.                on Gemini means to use Elite (12 cpi) font.
  53.             -  Clean-up of printer forms positioning.  Actions specified by
  54.                "maxline" and "top_margin" constants are exact.  In all
  55.                cases, lines are printed and then linect is compared to
  56.                maxline.  Deleted extra formfeeds.  Program now assumes
  57.                that paper is initially positioned at top-of-form and will
  58.                skip to top-of-form at end of listing.
  59.             -  Fixed Cross-Reference problem which caused 2nd and subsequent
  60.                print lines of line numbers for an entry to list 11
  61.                line numbers (instead of 10).
  62.             -  Fixed bug that disallowed counting of REPEATs in "B" column.
  63.  
  64.     9/21/85 -  Changed output to use the same font for the entire line;
  65.    (ver 1.3)   switching from normal to compressed in mid-line caused
  66.                the printer to print in "one-direction" mode.
  67.             -  Added (commented out) printer codes for the Epson FX-series
  68.                printers.  I have a Star Gemini-10x, so they haven't
  69.                been tested.
  70.             -  Changed Comment indicator from a number to a 'C'. Program was
  71.                not correctly picking up the end of comments if 2 or more
  72.                begin-comments of the same type were used before an end-
  73.                comment of that type (Turbo doesn't nest comments).
  74.             -  Fixed problem where program was not recognising BEGINs, ENDs,
  75.                etc. if they were immediately followed by a comment.
  76.             -  Minor attempt at optimisation of Scan_Line procedure.
  77.             -  An 'I' will now be printed in front of the line number while
  78.                expanding Include files (like Turbo's compiler).
  79.             -  Changed program so that all printed lines will be numbered.
  80.                Also changed logic of file reads so that the line
  81.                numbering will be exactly like Turbo's (CR/LF followed
  82.                by CTRL-Z is considered another line).
  83.                (Well, almost exactly!  Turbo stops looking at the text
  84.                when it sees an "END.", while this program will continue
  85.                to list the file past the end of program.)
  86.  
  87.     9/23/85 -  Added the Reserved Word list to the program, as a string array,
  88.    (ver 1.4)   removing the requirement for the TURBOPRT.RES file.
  89.             -  Changed the Reserved Word lookup to a binary search on the
  90.                string array.  Speeds up the program a bit.
  91.             -  Modified the program to use the Turbo ParamCount, ParamStr
  92.                functions and Read(Kbd,..).
  93.             -  Changed the program to print variables up to 25 characters in
  94.                length without truncation.
  95.  
  96.     9/28/85 -  Changed structure of Xref word records from a linked
  97.    (ver 1.5)   list to a B-tree.  Records storing line numbers now contain
  98.                multiple occurances of line numbers.
  99.             -  More optimisation in Scan_Line procedure.
  100.  
  101.  
  102.                    ======   Future Desires   ======
  103.                       (for this program, that is)
  104.  
  105.           I want to add some features to this program in the future.  Some
  106.           of them are:
  107.  
  108.            -  More gracefully handle the printing of long (>80 chars) lines,
  109.               which are currently just truncated.
  110.            -  Change the "Console or Printer" output option to allow direction
  111.               to any device.  The Console output is really only useful with
  112.               very small programs or for debugging purposes.
  113.            -  Fix up the command line parsing so the program can be run
  114.               from batch files.  Maybe also allow the use of wildcards for
  115.               specifying what programs to list.
  116.  
  117.           Then, some biggies:
  118.  
  119.            -  Lex-level analysis of procedures and variables, so that variables
  120.               of the same name declared in different procedures will be
  121.               handled properly.  I'd like this to include some kind of
  122.               "level" indication on the program listing, also, so you could
  123.               easily spot procedures within procedures, etc.
  124.            -  Inclusion of procedures in the cross-reference.  This would
  125.               include detection of redefinition of Standard Turbo Pascal
  126.               identifiers.  It would also have to include forward references.
  127.            -  Listing of identifier type (integer, real, etc.) in the cross-
  128.               reference and of what procedure.
  129.            -  Retain, in the cross-reference, the use of upper/lower case
  130.               letters as used when the indentifier was declared.
  131.  
  132.               Put these all together and we get something like:
  133.  
  134.             ListIt               833    Procedure, of TurboPrt; forward at 688
  135.                                  728   950
  136.             monthmask            398    Constant, of WhenCreated
  137.                                  415
  138.             MoreRefs             431    RefsPtr, of BuildXref
  139.                                  453   454   455   456   458   460   461
  140.             MoreRefs             884    RefsPtr, of ListXref
  141.                                  891   895   896   898   908   911
  142.             RefsPtr              228    Type, of TurboPrt
  143.                                  234   240   431   884
  144.  
  145. *)
  146. {.page}
  147. (* 
  148.  
  149.    Supported pseudo operations:
  150.  
  151.      1. Listing control: {.L-} turns it off, {.L+} turns it back on.
  152.         Must be in column 1 and only entry on the line.
  153.  
  154.      2. Page ejection: {.PAGE}, must be in column 1 and only entry
  155.         on the line.
  156.  
  157.    When program is first run will check for a file name passed by DOS, and
  158.    will try to open that file.  If no name is passed, will ask operator for
  159.    a file name to open.  Proc will tell operator if file doesn't exist and
  160.    will allow multiple retrys.
  161.  
  162.    Optionally the file name can be passed via the command line.  Typing an
  163.    "/I" after the filename will expand includes. Examples:
  164.  
  165.      TurboPrt  -  Will invoke program and ask for file name to be listed.
  166.  
  167.      TurboPrt MyProg.pas  - Will list file "MYPROG.PAS" and not expand
  168.                              includes.
  169.  
  170.      TurboPrt MyProg /i  -  Will list file "MYPROG.PAS" and will expand
  171.                             includes.
  172.  
  173.    On 2nd and later executions, program will not check for DOS passed file
  174.    name.  In all cases, the program will assume a file type of .PAS if file
  175.    type is not specified.  Program will exit when a null string is
  176.    encountered in response to a file name request.
  177.  
  178. *)
  179. {.page}
  180. const
  181.   maxline       = 64;          {last line on page to print}
  182.   top_margin    = 1;           {lines to skip after top-of-form}
  183.  
  184.   header_length = 5;           {number of lines taken up by page header}
  185.  
  186.  
  187. { to customize code for your printer - adjust the next items }
  188.  
  189. { The following codes are for a Gemini 10x - "Compressed" is Elite print }
  190.  
  191.   cp = #27#66#2;         {Elite font}
  192.   rp = #27#66#1;         {regular (Pica) font }
  193.  
  194. { The following codes should work on an Epson FX-series printer }
  195. (*
  196.   cp = #27#77;           {Elite font}
  197.   rp = #27#80;           {regular (Pica) font }
  198. *)
  199.  
  200. {  These printer codes were in the original program and are for
  201.    (I assume) the Epson MX/IBM graphics printers. }
  202. (*
  203.   cp = #15;         {compressed print}
  204.   rp = #18;         {regular width }
  205. *)
  206.  
  207.   cr = #13;
  208.   lf = #10;
  209.   ff = #12;
  210.  
  211. Type
  212.    two_letters = string[2];
  213.    dtstr       = string[8];
  214.    fnmtype     = string[40];
  215.    instring    = string[135];
  216.    regpack     = record
  217.       ax,bx,cx,dx,bp,si,di,ds,es,flags : integer;
  218.    end;
  219.  
  220. Var
  221.   First     : boolean;           {true when prog is run}
  222.   answer    : char;
  223.   Buff1     : instring;          {input line buffer}
  224.  
  225.   Wordchk   : string[25];
  226.   heaptop   : ^Integer;
  227.   listfil   : text;              {FIB for LST: or CON: output}
  228.   infile    : text;              {FIB for input file}
  229.   fnam      : fnmtype;            {input file name}
  230.   file_path : fnmtype;           {path to input file}
  231.   bcount    : integer;           {begin/end counter}
  232.   linect    : integer;           {output file line counter}
  233.   RefLine   : integer;           {Line Reference number counter}
  234.   pageno    : integer;           {page counter}
  235.   offset    : integer;
  236.   print     : boolean;           (* {.L-} don't print *)
  237.                                  (* {.L+} print       *)
  238.   print_head    : boolean;
  239.   Print_Xref    : boolean;
  240.   path_found    : boolean;
  241.   Word_switch   : boolean;
  242.   skip_this_line: boolean;
  243.   comment_brace : boolean;
  244.   comment_paren : boolean;
  245.  
  246.   c, Print_opt : char;
  247.   comment_char : char;
  248.   include_char : char;
  249.  
  250.   month, day, year,
  251.   hour, minute, second : two_letters;
  252.  
  253.   sysdate, systime,
  254.   filedate, filetime : dtstr;
  255.  
  256.   expand_includes    : boolean;
  257.   holdarg            : instring;
  258.   allregs            : regpack;
  259.  
  260. {.page}
  261. {                 Xref stuff begins here                        }
  262.  
  263. const
  264.   RefsPerRec = 10;
  265.   NumReservedWords    = 244;
  266.   BiggestReservedWord = 15;
  267.  
  268. type
  269.    ReservedWord = String[BiggestReservedWord];
  270.    XrefPtr = ^XrefRec;
  271.    RefsPtr = ^RefsRec;
  272.  
  273.    XrefRec = Record
  274.                  RefWord  : string[25];
  275.                  LeftPtr  : XrefPtr;
  276.                  RightPtr : XrefPtr;
  277.                  NextRefs : RefsPtr;
  278.              end;
  279.  
  280.    RefsRec = record
  281.                  NumRefs  : 0..RefsPerRec;
  282.                  Refs     : Array [1..RefsPerRec] of Integer;
  283.                  NextRefs : RefsPtr;
  284.              end;
  285.  
  286. var
  287.   WordTree          : XRefPtr;
  288.   ReservedWordCheck : ReservedWord;
  289.  
  290. const
  291.   ReservedWordList : array [1..NumReservedWords] of ReservedWord =
  292.  (
  293.   'ABS'                  ,'ABSOLUTE'             ,'ADDR'
  294.  ,'AND'                  ,'APPEND'               ,'ARC'
  295.  ,'ARCTAN'               ,'ARRAY'                ,'ASSIGN'
  296.  ,'AUX'                  ,'AUXINPTR'             ,'AUXOUTPTR'
  297.  ,'BACK'                 ,'BEGIN'                ,'BLACK'
  298.  ,'BLINK'                ,'BLOCKREAD'            ,'BLOCKWRITE'
  299.  ,'BLUE'                 ,'BOOLEAN'              ,'BROWN'
  300.  ,'BUFLEN'               ,'BYTE'                 ,'CASE'
  301.  ,'CHAIN'                ,'CHAR'                 ,'CHDIR'
  302.  ,'CHR'                  ,'CIRCLE'               ,'CLEARSCREEN'
  303.  ,'CLOSE'                ,'CLREOL'               ,'CLRSCR'
  304.  ,'COLORTABLE'           ,'CON'                  ,'CONCAT'
  305.  ,'CONINPTR'             ,'CONOUTPTR'            ,'CONST'
  306.  ,'CONSTPTR'             ,'COPY'                 ,'COS'
  307.  ,'CRTEXIT'              ,'CRTINIT'              ,'CSEG'
  308.  ,'CYAN'                 ,'DARKGRAY'             ,'DELAY'
  309.  ,'DELETE'               ,'DELLINE'              ,'DISPOSE'
  310.  ,'DIV'                  ,'DO'                   ,'DOWNTO'
  311.  ,'DRAW'                 ,'DSEG'                 ,'EAST'
  312.  ,'ELSE'                 ,'END'                  ,'EOF'
  313.  ,'EOLN'                 ,'ERASE'                ,'EXECUTE'
  314.  ,'EXIT'                 ,'EXP'                  ,'EXTERNAL'
  315.  ,'FALSE'                ,'FILE'                 ,'FILEPOS'
  316.  ,'FILESIZE'             ,'FILLCHAR'             ,'FILLPATTERN'
  317.  ,'FILLSCREEN'           ,'FILLSHAPE'            ,'FLUSH'
  318.  ,'FOR'                  ,'FORM'                 ,'FORWARD'
  319.  ,'FRAC'                 ,'FREEMEM'              ,'FUNCTION'
  320.  ,'GETDIR'               ,'GETDOTCOLOR'          ,'GETMEM'
  321.  ,'GETPIC'               ,'GOTO'                 ,'GOTOXY'
  322.  ,'GRAPHBACKGROUND'      ,'GRAPHCOLORMODE'       ,'GRAPHMODE'
  323.  ,'GRAPHWINDOW'          ,'GREEN'                ,'HALT'
  324.  ,'HEADING'              ,'HEAPPTR'              ,'HI'
  325.  ,'HIDETURTLE'           ,'HIRES'                ,'HIRESCOLOR'
  326.  ,'HOME'                 ,'IF'                   ,'IN'
  327.  ,'INLINE'               ,'INPUT'                ,'INSERT'
  328.  ,'INSLINE'              ,'INT'                  ,'INTEGER'
  329.  ,'INTR'                 ,'IORESULT'             ,'KBD'
  330.  ,'KEYPRESSED'           ,'LABEL'                ,'LENGTH'
  331.  ,'LIGHTBLUE'            ,'LIGHTCYAN'            ,'LIGHTGRAY'
  332.  ,'LIGHTGREEN'           ,'LIGHTMAGENTA'         ,'LIGHTRED'
  333.  ,'LN'                   ,'LO'                   ,'LONGFILEPOS'
  334.  ,'LONGFILESIZE'         ,'LONGSEEK'             ,'LOWVIDEO'
  335.  ,'LST'                  ,'LSTOUTPTR'            ,'MAGENTA'
  336.  ,'MARK'                 ,'MAXAVAIL'             ,'MAXINT'
  337.  ,'MEM'                  ,'MEMAVAIL'             ,'MEMW'
  338.  ,'MEMW'                 ,'MKDIR'                ,'MOD'
  339.  ,'MOVE'                 ,'MSDOS'                ,'NEW'
  340.  ,'NIL'                  ,'NORMVIDEO'            ,'NORTH'
  341.  ,'NOSOUND'              ,'NOT'                  ,'NOWRAP'
  342.  ,'ODD'                  ,'OF'                   ,'OFS'
  343.  ,'OR'                   ,'ORD'                  ,'OUTPUT'
  344.  ,'OVERLAY'              ,'OVRPATH'              ,'PACKED'
  345.  ,'PALETTE'              ,'PARAMCOUNT'           ,'PARAMSTR'
  346.  ,'PATTERN'              ,'PENDOWN'              ,'PENUP'
  347.  ,'PI'                   ,'PLOT'                 ,'PORT'
  348.  ,'PORTW'                ,'POS'                  ,'PRED'
  349.  ,'PROCEDURE'            ,'PROGRAM'              ,'PTR'
  350.  ,'PUTPIC'               ,'RANDOM'               ,'RANDOMIZE'
  351.  ,'READ'                 ,'READLN'               ,'REAL'
  352.  ,'RECORD'               ,'RED'                  ,'RELEASE'
  353.  ,'RENAME'               ,'REPEAT'               ,'RESET'
  354.  ,'REWRITE'              ,'RMDIR'                ,'ROUND'
  355.  ,'SEEK'                 ,'SEEKEOF'              ,'SEEKEOLN'
  356.  ,'SEG'                  ,'SET'                  ,'SETHEADING'
  357.  ,'SETPENCOLOR'          ,'SETPOSITION'          ,'SHL'
  358.  ,'SHOWTURTLE'           ,'SHR'                  ,'SIN'
  359.  ,'SIZEOF'               ,'SOUND'                ,'SOUTH'
  360.  ,'SQR'                  ,'SQRT'                 ,'SSEG'
  361.  ,'STR'                  ,'STRING'               ,'SUCC'
  362.  ,'SWAP'                 ,'TEXT'                 ,'TEXTBACKGROUND'
  363.  ,'TEXTCOLOR'            ,'TEXTMODE'             ,'THEN'
  364.  ,'TO'                   ,'TRM'                  ,'TRUE'
  365.  ,'TRUNC'                ,'TRUNCATE'             ,'TURNLEFT'
  366.  ,'TURNRIGHT'            ,'TURTLETHERE'          ,'TURTLEWINDOW'
  367.  ,'TYPE'                 ,'UNTIL'                ,'UPCASE'
  368.  ,'USR'                  ,'USRINPTR'             ,'USROUTPTR'
  369.  ,'VAL'                  ,'VAR'                  ,'WEST'
  370.  ,'WHEREX'               ,'WHEREY'               ,'WHILE'
  371.  ,'WHITE'                ,'WINDOW'               ,'WITH'
  372.  ,'WRAP'                 ,'WRITE'                ,'WRITELN'
  373.  ,'XCOR'                 ,'XOR'                  ,'YCOR'
  374.  ,'YELLOW'
  375. );
  376.  
  377. function Reserved(var w : ReservedWord ) : boolean;
  378. var
  379.   low, high, mid : integer;
  380.   done : boolean;
  381. begin
  382.   Reserved := False;
  383.   done := False;
  384.   low := 1;
  385.   high := NumReservedWords;
  386.   while (low <= high) and not done do
  387.     begin
  388.       mid := (low + high) div 2;
  389.       if w < ReservedWordList[mid] then
  390.         high := mid - 1
  391.       else
  392.       if w > ReservedWordList[mid] then
  393.         low := mid + 1
  394.       else
  395.         begin
  396.           Reserved := true;
  397.           done := True;
  398.         end;
  399.     end;
  400. end;
  401. {.page}
  402. procedure fill_blanks (var line: dtstr);
  403.   var
  404.     i : integer;
  405. begin
  406.   for i:= 1 to 8 do
  407.       if line[i] = ' ' then
  408.           line[i]:= '0';
  409. end;  {fill_blanks}
  410.  
  411. procedure getdate(var date : dtstr);
  412.  
  413. begin
  414.    allregs.ax := $2A * 256;
  415.    MsDos(allregs);
  416.    str((allregs.dx div 256):2,month);
  417.    str((allregs.dx mod 256):2,day);
  418.    str((allregs.cx - 1900):2,year);
  419.    date := month + '/' + day + '/' + year;
  420.    fill_blanks (date);
  421. end;  {getdate}
  422.  
  423. procedure gettime(var time : dtstr);
  424.  
  425. begin
  426.    allregs.ax := $2C * 256;
  427.    MsDos(allregs);
  428.    str((allregs.cx div 256):2,hour);
  429.    str((allregs.cx mod 256):2,minute);
  430.    str((allregs.dx div 256):2,second);
  431.    time := hour + ':' + minute + ':' + second;
  432.    fill_blanks (time);
  433. end;  {gettime}
  434.  
  435. procedure WhenCreated (var date, time: dtstr; var infile: text);
  436.  
  437. const
  438.   monthmask  = $000F;
  439.   daymask    = $001F;
  440.   minutemask = $003F;
  441.   secondmask = $001F;
  442.  
  443. var
  444.   fulltime,fulldate: integer;
  445.  
  446. begin
  447.  
  448.     allregs.ax := $57 * 256;
  449.     allregs.bx := memw [seg(infile):ofs(infile)];
  450.     MsDos(allregs);
  451.     fulldate := allregs.dx;
  452.     fulltime := allregs.cx;
  453.  
  454.     str(((fulldate shr 9) + 80):2,year);
  455.     str(((fulldate shr 5) and monthmask):2,month);
  456.     str((fulldate and daymask):2,day);
  457.     date:= month + '/' + day + '/' + year;
  458.     fill_blanks(date);
  459.  
  460.     str((fulltime shr 11):2,hour);
  461.     str(((fulltime shr 5) and minutemask):2,minute);
  462.     str(((fulltime and secondmask) * 2):2,second);
  463.     time:= hour + ':' + minute + ':' + second;
  464.     fill_blanks (time);
  465. end;  {WhenCreated}
  466.  
  467.  
  468. Procedure BuildXref (var TreePtr : XrefPtr);
  469.  
  470. var
  471.   MoreRefs : RefsPtr;
  472.  
  473. Begin
  474.   if TreePtr = nil then
  475.     begin
  476.       New(TreePtr);
  477.       TreePtr^.RefWord  := Wordchk;
  478.       TreePtr^.LeftPtr  := Nil;
  479.       TreePtr^.RightPtr := Nil;
  480.       New(TreePtr^.NextRefs);
  481.       TreePtr^.NextRefs^.NumRefs := 1;
  482.       TreePtr^.NextRefs^.Refs[1] := Refline;
  483.       TReePtr^.NextRefs^.NextRefs := Nil;
  484.     end
  485.   else
  486.     if Wordchk < TreePtr^.RefWord then
  487.         BuildXref(TreePtr^.LeftPtr)
  488.     else
  489.     if Wordchk > TreePtr^.RefWord then
  490.         BuildXref(TreePtr^.RightPtr)
  491.     else
  492.       begin
  493.         MoreRefs := TreePtr^.NextRefs;
  494.         While MoreRefs^.NextRefs <> Nil Do
  495.           MoreRefs := MoreRefs^.NextRefs;
  496.         if MoreRefs^.Refs[MoreRefs^.NumRefs] <> Refline then
  497.           begin
  498.             if MoreRefs^.NumRefs = RefsPerRec then
  499.               begin
  500.                 New(MoreRefs^.NextRefs);
  501.                 MoreRefs := MoreRefs^.NextRefs;
  502.                 MoreRefs^.NumRefs := 0;
  503.                 MoreRefs^.NextRefs := Nil;
  504.               end;
  505.             MoreRefs^.NumRefs := MoreRefs^.NumRefs + 1;
  506.             MoreRefs^.Refs[MoreRefs^.NumRefs] := Refline;
  507.           end;
  508.       end;
  509. end;
  510. procedure print_heading(filename : fnmtype);
  511.  
  512. var offset_inc: integer;
  513.     temp      : integer;
  514.  
  515. begin
  516.    if print then
  517.      begin
  518.        pageno := pageno + 1;
  519.        if not (pageno = 1) then
  520.            write(listfil, ff);  {top of form}
  521.        linect := 0;
  522.        for temp := 1 to top_margin do
  523.           writeln(listfil);
  524.        if print_opt = 'C' then
  525.          write(listfil,rp);
  526.        write(listfil,'TURBO Pascal Program Lister');
  527.        writeln(listfil,' ':13,'Printed: ',sysdate,'  ',
  528.                systime,'   Page ',pageno:4);
  529.        if filename <> fnam then begin
  530.           offset_inc:= 26 - length (filename);
  531.           write(listfil,'Include File: ',filename,' ':offset_inc,
  532.              'Created: ',filedate,'  ',filetime);
  533.        end
  534.        else write(listfil,'Main File: ',fnam,' ':offset,
  535.              'Created: ',filedate,'  ',filetime);
  536.        writeln(listfil); writeln(listfil);
  537.        if print_opt = 'C' then
  538.          write(listfil,cp);
  539.        If Print_Xref then
  540.          begin
  541.            Writeln(Listfil,' ':40,'Cross-Reference');
  542.            writeln(listfil,'------------------------------','  '
  543.              ,'-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+');
  544.          end
  545.        else
  546.          begin
  547.            writeln(listfil,'  line# C B');
  548.            writeln(listfil,'  ----- - -   ---------+---------+---------+'
  549.               +'---------+---------+---------+---------+---------+');
  550.         end;
  551.        linect := top_margin + header_length;
  552.      end; {check for print}
  553. end;  {print_heading}
  554.  
  555. procedure printline(iptline : instring; filename : fnmtype);
  556. begin
  557.    if print then
  558.      begin
  559.        writeln(listfil,'     ',iptline);
  560.        linect := linect + 1;
  561.        if linect >= maxline then
  562.          print_heading(filename);
  563.      end; {check for print}
  564. end;  {printline}
  565.  
  566. {.page}
  567. function chkinc(var iptline : instring; var incflname : fnmtype) : boolean;
  568. var
  569.    done : boolean;
  570.    i, j : integer;
  571. begin
  572.    i := 4; j := 1; incflname := '';
  573.    if ((copy(iptline, 1, 3) = '{$I') or
  574.        (copy(iptline, 1, 4) = '(*$I')) then begin
  575.          if copy(iptline, 1, 4) = '(*$I' then i := 5;
  576.          incflname := '';
  577.          while (iptline[i] = ' ') and (i <= length(iptline)) do i := i + 1;
  578.          done := false;
  579.          while not done do begin
  580.                if i <= length(iptline) then begin
  581.                   if not (iptline[i] in [' ','}','+','-','*']) then begin
  582.                      incflname[j] := iptline[i];
  583.                      i := i + 1; j := j + 1;
  584.                   end else done := true;
  585.               end else done := true;
  586.               if j > 14 then done := true;
  587.          end;
  588.          incflname[0] := chr(j - 1);
  589.    end;
  590.    if incflname <> '' then
  591.      begin
  592.           chkinc := true;
  593.           for i := 1 to length(Incflname) do
  594.               incflname[i] := upcase(incflname[i]);
  595.      end
  596.      else
  597.          chkinc := false;
  598. end;  {chkinc}
  599.  
  600.  
  601.  PROCEDURE GET_IN_FILE;     {GETS INPUT FILE NAME }
  602.    var
  603.     existing : boolean;
  604.     i        : integer;
  605.   begin
  606.     repeat             {until file exists}
  607.       clrscr;
  608.       gotoxy(25,1);
  609.       write('TurboPrt - Release 1.5');
  610.       if first and (ParamCount > 0) then
  611.         fnam := ParamStr(1)
  612.       else
  613.         begin
  614.           gotoxy(1,3);
  615.           write(' Enter Filename to List or <CR> to Exit  ');
  616.           readln(fnam);
  617.           if fnam <> '' then
  618.              begin
  619.                   answer := ' ';
  620.                   writeln;write(' Expand Includes? (Y/N) ');
  621.                   read(Kbd,answer);
  622.                   Answer := UpCase(Answer);
  623.                   if answer = 'Y' then
  624.                      expand_includes := true
  625.                   else
  626.                     begin
  627.                       expand_includes := false;
  628.                       answer := 'N';
  629.                     end;
  630.                   Writeln(answer);
  631.              end
  632.         end;
  633.  
  634.      if fnam = '' then          {***** EXIT *****}
  635.      begin
  636.           clrscr;
  637.           halt;
  638.      end;
  639.  
  640.      for i := 1 to length(fnam) do
  641.          fnam[i] := upcase(fnam[i]);
  642.  
  643.      if pos('.',fnam) = 0 then       {file type given?}
  644.        fnam := concat(fnam,'.PAS');  {file default to .PAS type}
  645.  
  646.      {get optional command line argument # 2}
  647.      if first and (ParamCount > 1) then
  648.        begin
  649.          holdarg := ParamStr(2);
  650.          for i := 1 to Length(holdarg) do
  651.            holdarg[i] := UpCase(holdarg[i]);
  652.          expand_includes := holdarg = '/I';
  653.        end;
  654.  
  655.      assign( infile, fnam);
  656.        {$I-}
  657.      reset( infile );                {check for existence of file}
  658.        {$I+}
  659.      existing := (ioresult = 0);     {true if file found}
  660.      if not existing then
  661.        begin
  662.         writeln;
  663.         writeln(' File Doesn''t Exist!!'); {tell operator the sad news}
  664.         sound(500);
  665.         delay(250);
  666.         nosound;
  667.         delay(2000);
  668.        end;
  669.      if existing then
  670.        begin                             {obtain path for include files}
  671.           I := length(fnam);
  672.           path_found := false;
  673.           while ((I > 0) and Not Path_found) do
  674.              if (fnam[i] in ['\',':']) then Path_found := true
  675.              else I := I - 1;
  676.  
  677.           if Path_found then
  678.           begin
  679.              file_path := copy(fnam,1,I);
  680.              fnam := copy(fnam,(i+1),(length(fnam)));
  681.           end;
  682.        end;
  683.      first := false;        {get passed file name only once}
  684.     until existing;                     {until file exists}
  685.  
  686.  
  687.  end; {GET_IN_FILE}
  688.  
  689. { GET_OUT_FILE procedure asks operator to select output to console
  690.   device or list device, and then assigns and resets a file control
  691.   block to the appropriate device.  'C' or 'P' is only correct
  692.   response, and multiple retrys are allowed. }
  693.  
  694. Procedure Get_Out_File;
  695.   begin
  696.     repeat    {until good selection}
  697.       gotoxy(1,7);
  698.       clreol;
  699.       write(' Output Listing to (C)onsole or (P)rinter ?  ');
  700.       Read(Kbd,c);
  701.       c := upcase(c); write(c);
  702.    until c in ['C', 'P'];
  703.  
  704.    writeln;
  705.    if c = 'C' then
  706.     begin
  707.       assign (listfil, 'CON:');
  708.       print_opt := 'R';
  709.     end
  710.    else
  711.       assign (listfil, 'LST:');
  712.  
  713.    reset(listfil);
  714.    if c = 'P' then begin
  715.      repeat
  716.       gotoxy(1,9);
  717.       clreol;
  718.       Write(' (C)ompressed Print or (R)egular Print ? ');
  719.       Read(Kbd,print_opt);
  720.       print_opt := upcase(print_opt);
  721.       write(print_opt);
  722.     until print_opt in ['C','R'];
  723.     writeln;
  724.     if print_opt = 'R' then write(listfil,rp);
  725.    end;
  726.  end;  {GET_OUT_FILE}
  727. {.page}
  728. Procedure ListIt(filename : fnmtype); forward;
  729.  
  730. Procedure Scan_Line;
  731.  
  732. { Scan_Line procedure scans one line of Turbo Pascal source code
  733.   looking for Begin/End pairs, Case/End pairs, Literal fields
  734.   and Comment fields.  Bcount is begin/end and case/end counter.
  735.   Begin/case/ends are only valid outside of comment fields and
  736.   literal constant fields.
  737.   Some of the code in the Scan_Line procedure appears at first glance
  738.   to be repitive and/or redundant, but was added to speed up the
  739.   process of scanning each line of source code.}
  740.  
  741.   var
  742.     literal : boolean;          { true if in literal field}
  743.     i, j    : integer;          {loop variable index}
  744.     buff2   : instring;         {working line buffer}
  745.     incflname : fnmtype;        {in file name}
  746.     filedate_save : dtstr;
  747.     filetime_save : dtstr;
  748.   begin
  749.     literal := false;
  750.                                         {copy input buffer to working buffer}
  751.     buff2 := concat(buff1, '       ');
  752.  
  753.     for i := 1 to length(buff2) do
  754.       buff2[i] := UpCase(buff2[i]);
  755.  
  756.     RefLine := RefLine + 1;
  757.  
  758.     if chkinc(buff2, incflname) and expand_includes then
  759.        begin
  760.        for i := 1 to length(incflname) do
  761.            incflname[i] := upcase(incflname[i]);
  762.           if pos('.',incflname) = 0 then incflname := incflname + '.PAS';
  763.           printline('                      ******* Including "'
  764.               +incflname+'" *******', incflname);
  765.           filedate_save := filedate;  {save filedate & filetime for}
  766.           filetime_save := filetime;  {main file                   }
  767.           include_char := 'I';
  768.           listit(incflname);
  769.           include_char := ' ';
  770.           filedate := filedate_save;  {restore}
  771.           filetime := filetime_save;
  772.           printline('                      *******   End of  "'
  773.               +incflname+'" *******', incflname);
  774.           skip_this_line := true;
  775.        end  {include file check}
  776.  
  777.    else begin
  778.  
  779.     if ((buff2[1] = '{') and (buff2[2] = '.')) then
  780.       if buff2[3] in ['L','P'] then
  781.         if copy(buff2,1,7) = '{.PAGE}' then
  782.           begin
  783.             if print and (linect > (header_length + top_margin)) then
  784.              begin
  785.               skip_this_line := true;
  786.               print_head := true;
  787.              end;
  788.           end
  789.         else
  790.         if copy(buff2,1,5) = '{.L+}' then
  791.           begin
  792.             skip_this_line := true;
  793.             print := true;
  794.           end
  795.         else
  796.         if copy(buff2,1,5) = '{.L-}' then
  797.           begin
  798.             skip_this_line := true;
  799.             print := false;
  800.           end;
  801.  
  802.     buff2 := concat('  ', buff2);  {add on some working space}
  803.  
  804.     i := 1;
  805.     while buff2[i] = ' ' do
  806.         i := i + 1;
  807.  
  808.     while i <= (length(buff2) - 6) do
  809.       begin
  810.         if not literal then   {possible to find comment delim}
  811.           begin               {determine if comment area delim}
  812.            if buff2[i] in ['{', '}', '(', '*'] then
  813.              begin
  814.                if (buff2[i] = '{') then comment_brace := true
  815.                else
  816.                if (buff2[i] = '}') then comment_brace := false
  817.                else
  818.                if (copy(buff2,i,2)='(*') then comment_paren := true
  819.                else
  820.                if (copy(buff2,i,2)='*)') then comment_paren := false;
  821.              end;
  822.          end
  823.        else
  824.          while buff2[i] <> chr(39) do
  825.            i := i + 1;
  826.  
  827.          if not (comment_brace or comment_paren) then  {in comment area}
  828.            begin
  829.             if buff2[i] = chr(39) then
  830.                 literal := not literal;   {toggle literal flag}
  831.             if not literal then
  832.             begin
  833.               if not Word_switch then
  834.                   if ((buff2[i] in ['A'..'Z']) and
  835.                       (not (buff2[i-1] in ['0'..'9','A'..'Z']))) then
  836.                     Begin
  837.                       Word_switch := true;
  838.                       Wordchk := '';
  839.                     end;
  840.               if word_switch then
  841.                  if (buff2[i] in ['A'..'Z','0'..'9','_']) then
  842.                     Wordchk := concat(Wordchk,Buff2[i])
  843.                  else
  844.                  begin
  845.                       word_switch := false;
  846.                       ReservedWordCheck := Wordchk;
  847.                       if not Reserved(ReservedWordCheck) then
  848.                          BuildXref (WordTree)
  849.                       else
  850.                         begin
  851.                           if ((Wordchk = 'BEGIN') or
  852.                               (Wordchk = 'CASE') or
  853.                               (Wordchk = 'REPEAT')) then
  854.                             bcount := succ(bcount)
  855.                           else
  856.                           if ((Wordchk = 'END') or
  857.                               (Wordchk = 'UNTIL')) then
  858.                             if bcount > 0 then
  859.                               bcount := pred(bcount);
  860.                         end;
  861.                  end;
  862.             end;
  863.            end;  { if in comment }
  864.         i := i + 1;
  865.         end;  { for i := }
  866.       if comment_brace or comment_paren then
  867.           comment_char := 'C'
  868.       else
  869.           comment_char := ' ';
  870.       end;
  871.     end;  {SCAN_LINE}
  872. {.page}
  873. Procedure ListIt;
  874.   var
  875.     infile : text;
  876.     full_filename : fnmtype;
  877.     end_of_it : boolean;
  878.   begin
  879.     if path_found then
  880.        full_filename := concat(file_path,filename)
  881.     else
  882.        Full_filename := filename;
  883.      assign(infile, full_filename);
  884.    {$I-} reset(infile) {$I+} ;
  885.    if IOresult <> 0 then begin
  886.       writeln ('File ',filename,' not found.');
  887.       halt;
  888.    end;
  889.      WhenCreated (filedate,filetime,infile);
  890.      if filename = fnam then
  891.          print_heading(filename);
  892.          end_of_it := false;
  893.          while not end_of_it do
  894.            begin
  895.             buff1 := '';
  896.             read(infile, buff1);
  897.             scan_line;
  898.             if print_head then
  899.              begin
  900.               print_heading(filename);
  901.               print_head := false;
  902.              end;
  903.             if skip_this_line then
  904.               skip_this_line := false
  905.             else
  906.               if print then
  907.                 begin
  908.                 if length(buff1) > 80 then
  909.                   buff1 := copy(buff1,1,80);
  910.                 writeln(listfil,include_char,' ',RefLine:5
  911.                      ,' ',comment_char,bcount:2,'   ',buff1);
  912.                 linect := linect + 1;
  913.                 if linect >= maxline then
  914.                     print_head := true;
  915.                 end;
  916.            end_of_it := eof(infile);
  917.            if not end_of_it then
  918.                readln(infile);
  919.            end;     {while not eof}
  920.          close(infile);
  921.   end; {ListIt}
  922.  
  923. Procedure ListXref (TreePtr : XrefPtr);
  924.  
  925. var
  926.   MoreRefs : RefsPtr;
  927.   i, x : integer;
  928.  
  929. Begin
  930.   if TreePtr <> nil then
  931.     begin
  932.       LIstXref (TreePtr^.LeftPtr);
  933.       MoreRefs := TreePtr^.NextRefs;
  934.       x := 32 - Length(TreePtr^.RefWord);
  935.       Write(listfil,TreePtr^.RefWord,' ':x);
  936.       x := 0;
  937.       MoreRefs := TreePtr^.NextRefs;
  938.       While not (MoreRefs = Nil) do
  939.         begin
  940.           for i := 1 to MoreRefs^.NumRefs do
  941.             begin
  942.               if x = 10 then
  943.                 begin
  944.                   Writeln(listfil);
  945.                   Linect := Linect + 1;
  946.                   if Linect >= maxline then Print_heading(fnam);
  947.                   Write(listfil,' ':32);
  948.                   x := 0;
  949.                 end;
  950.               Write(listfil,MoreRefs^.Refs[i]:6);
  951.               x := x + 1;
  952.             end;
  953.           MoreRefs := MoreRefs^.NextRefs;
  954.         end;
  955.       Writeln(listfil);
  956.       Linect := Linect + 1;
  957.       if Linect >= maxline then Print_heading(fnam);
  958.       ListXref (TreePtr^.RightPtr);
  959.     end;
  960. end;
  961. {.page}
  962.   begin {main procedure}
  963.      lowvideo;
  964.      getdate(sysdate);
  965.      gettime(systime);
  966.      expand_includes := false;       {default settings}
  967.      First := True;
  968.      Mark(heaptop);
  969.  
  970.    repeat {forever}
  971.  
  972.      Print_opt := ' ';
  973.      WordTree := nil;
  974.      ClrScr;
  975.      GotoXY(2, 2);
  976.      get_in_file;      {file to list}
  977.      offset := 29 - length(fnam);
  978.      get_out_file;     {where to list it}
  979.      pageno  := 0;
  980.      linect  := 0;      {output line counter}
  981.      RefLine := 0;
  982.      bcount  := 0;
  983.      print := true;
  984.      skip_this_line := false;
  985.      print_head := false;
  986.      Print_xref := False;
  987.      word_switch:= False;
  988.      comment_brace := false;
  989.      comment_paren := false;
  990.      comment_char := ' ';
  991.      include_char := ' ';
  992.      listit(fnam);
  993.      Print_Xref := True;
  994.      Print_heading(fnam);
  995.      Listxref(WordTree);
  996.      if Print_opt = 'C' then
  997.        write(listfil,rp);
  998.      writeln(listfil,ff);
  999.      Release (heaptop); {purge previous cross reference}
  1000.      write(cr, lf, 'Hit Any Key to Continue ');
  1001.      Read(Kbd,c);
  1002.    until false;        {repeat forever - exit is in GET_IN_FILE PROCEDURE}
  1003.  end.  {main procedure}