home *** CD-ROM | disk | FTP | other *** search
/ CD Actual 14 / CDACTUAL.iso / cdactual / demobin / share / program / Pascal / TURPRT16.ZIP / TURPRT16.PAS
Encoding:
Pascal/Delphi Source File  |  1985-10-23  |  35.5 KB  |  1,012 lines

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