_STRUCTURED PROGRAMMING COLUMN_ by Jeff Duntemann [LISTING ONE] {--------------------------------------------------------------} { JLIST10 } { Multifile source code lister with 8-char tab expansion } { by Jeff Duntemann } { Turbo Pascal V6.0 } { Last update 1/1/92 } {--------------------------------------------------------------} PROGRAM JList10; USES DOS,CRT,Printer, { Standard Borland units } DirList, { From DDJ for 4/92 } When2; { From DDJ for 1/92 } CONST Up = True; Down = False; Single = True; Double = False; SingleRule = Chr(196); { D } DoubleRule = Chr(205); { M } JLogo : ARRAY[1..4] OF STRING = (' DBDD ZDDDDDDDBDDD ZDD?', ' 3 3 B @DDD? 3 ? 3 3', ' 3 3 3 3 3 3 3 3', ' DY @D A DDDDY A A @DDY'); ESC1 = Chr($1B); ESC2 = ESC1+Chr($5B); LinesPerPage = 75; { 75 assumes 8 lines per inch } TYPE String80 = STRING[80]; VAR InChar : Char; PrintPage : Boolean; Space10 : String80; ListLine : String; I,J : Integer; FileSpecs : String80; FileInfo : String; PrintCommand : String80; FilesToPrint : PDirEntryCollection; FileTime,Now : When; { "When" stamps for time/date processing } {---------------------------------------------------------------} { PRINTER CONTROL ROUTINES } { These routines are all, to some extent, printer dependent. } { Here, the control codes are specific to the HP LJII/III. } {---------------------------------------------------------------} PROCEDURE PrinterReset; BEGIN Write(LST,ESC1+'E'); END; PROCEDURE PrinterToXY(X,Y : Integer); BEGIN Write(LST,ESC1+'&a',Y-1,'R'); Write(LST,ESC1+'&a',X-1,'C'); END; PROCEDURE SetPrinterLinesPerInch(Lines : Integer); BEGIN Write(LST,ESC1+'&l',Lines,'D'); END; PROCEDURE SetLinePrinterFont; BEGIN Write(LST,ESC1+'(s16.66H'); { Select Lineprinter font } END; PROCEDURE SetIBMCharacterSet; BEGIN Write(LST,ESC1+'(10U'); { Select IBM PC symbol set } END; {-----------------------------------------} { END PRINTER-DEPENDENT CODE } {-----------------------------------------} PROCEDURE SendFormFeed; BEGIN Write(LST,Chr(12)) END; FUNCTION ForceCase(Up : BOOLEAN; Target : String) : String; CONST Uppercase : SET OF Char = ['A'..'Z']; Lowercase : SET OF Char = ['a'..'z']; VAR I : INTEGER; BEGIN IF Up THEN FOR I := 1 TO Length(Target) DO IF Target[I] IN Lowercase THEN Target[I] := UpCase(Target[I]) ELSE { NULL } ELSE FOR I := 1 TO Length(Target) DO IF Target[I] IN Uppercase THEN Target[I] := Chr(Ord(Target[I])+32); ForceCase := Target END; PROCEDURE PrintRule(ShowSingle : Boolean; StartColumn,EndColumn : Integer); VAR RuleChar : Char; I : Integer; BEGIN IF ShowSingle THEN RuleChar := SingleRule ELSE RuleChar := DoubleRule; FOR I := 1 TO StartColumn-1 DO Write(LST,' '); FOR I := StartColumn TO EndColumn DO Write(LST,RuleChar); END; PROCEDURE PrintStartBanner(FilesToPrint : PDirEntryCollection); VAR TotalFiles : Integer; TotalBytes : LongInt; PROCEDURE ShowSpecs(Target : PDirEntry); FAR; BEGIN TotalFiles := Succ(TotalFiles); TotalBytes := TotalBytes + Target^.Entry.Size; Writeln(LST,Target^.DirLine); END; BEGIN TotalFiles := 0; TotalBytes := 0; SetPrinterLinesPerInch(12); FOR I := 1 TO 7 DO BEGIN PrintRule(Double,1,134); Writeln(LST); END; FOR I := 1 TO 4 DO Writeln(LST,JLogo[I]); FOR I := 1 TO 7 DO BEGIN PrintRule(Double,1,134); Writeln(LST); END; SetPrinterLinesPerInch(6); PrinterToXY(1,12); Write (LST,'Printer job initiated at '+Now.GetTimeString+'m'); Writeln(LST,' on '+Now.GetLongDateString); PrintRule(Single,1,134); Writeln(LST); Writeln(LST,'Requested filespec: ',FileSpecs); Writeln(LST,'Files to be printed:'); Writeln(LST); FilesToPrint^.ForEach(@ShowSpecs); PrintRule(Single,1,134); Writeln(LST); Writeln(LST,'Total number of files to be printed: ',TotalFiles); Writeln(LST,'Total number of bytes to be printed: ',TotalBytes); SendFormFeed; END; {->>>>PrintFile<<<<-} PROCEDURE PrintFile(ToBePrinted : PDirEntry); VAR LineNumber,PageNumber : Integer; ListFileName : String80; ListFile : Text; PROCEDURE PrintLine(LineToPrint : String; LineNumber : Integer); CONST TabChar = Chr(9); VAR I,J,LinePos,UpstreamPos,AddBlanks : Integer; Space8 : String80; BEGIN Space8 := ' '; Write(LST,Space8,LineNumber : 4,' '); LinePos := 1; FOR I := 1 TO Length(LineToPrint) DO IF LineToPrint[I] = TabChar THEN { Expand tabs } BEGIN UpstreamPos := (((LinePos + 7) DIV 8) * 8) + 1; AddBlanks := UpstreamPos - LinePos; FOR J := 1 TO AddBlanks DO Write(LST,' '); LinePos := UpstreamPos END ELSE BEGIN Write(LST,LineToPrint[I]); LinePos := Succ(LinePos) END; Writeln(LST) END; PROCEDURE PrintHeader; VAR I : Integer; Space8 : String80; BEGIN Space8 := ' '; Writeln(LST,Space8,'FILE: ',ForceCase(Up,ListFileName), ' Version of ',FileTime.GetDateString,' ', FileTime.GetTimeString,'m Printed on ', Now.GetLongDateString,' at ',Now.GetTimeString,'m.', ' Page ',PageNumber); Write(LST,Space8); FOR I := 1 TO 116 DO Write(LST,Chr(196)); Writeln(LST); Writeln(LST); Writeln(LST); END; BEGIN { PrintFile } LineNumber := 1; PageNumber := 1; Space10 := ' '; ListFileName := ToBePrinted^.Path+ToBePrinted^.Entry.Name; Assign(ListFile,ListFileName); Reset(ListFile); IF NOT EOF(ListFile) THEN PrintHeader; WHILE NOT EOF(ListFile) DO BEGIN Readln(ListFile,ListLine); PrintLine(ListLine,LineNumber); LineNumber := Succ(LineNumber); IF ((LineNumber-1) DIV LinesPerPage) > (PageNumber - 1) THEN BEGIN PageNumber := Succ(PageNumber); SendFormFeed; PrintHeader; END END; IF (LineNumber MOD LinesPerPage) > 1 THEN SendFormFeed; Close(ListFile); END; { PrintFile } PROCEDURE SetupPrinter; BEGIN SetLinePrinterFont; SetIBMCharacterSet; END; PROCEDURE PrintAllFiles(FilesToPrint : PDirEntryCollection); { This is the FAR local routine passed to the iterator method. } { It's called once for each item in the collection: } PROCEDURE PrintOneFile(Target : PDirEntry); FAR; BEGIN FileTime.PutWhenStamp(Target^.Entry.Time); PrintFile(Target); END; BEGIN { This is how you iterate a procedure over a collection: } FilesToPrint^.ForEach(@PrintOneFile); END; BEGIN { JLIST10 Main } IF ParamCount = 0 THEN BEGIN Writeln('>>>JLIST10<<< by Jeff Duntemann'); Writeln(' Multifile listing utility'); Writeln(' for the HP Laserjet Series II'); Writeln(' Version of 12/31/91 -- Expands fixed 8-char tabs...'); Writeln(' WARNING: Emits printer control strings that are'); Writeln(' *highly* specific to the HP Laserjet II!'); Writeln; Writeln('Invocation syntax:'); Writeln; Writeln(' JLIST10 ,[..] CR'); Writeln; Writeln('where is the file or files to be printed,'); Writeln('using the DOS filespec conventions, including wildcard'); Writeln('characters * and ?. A banner will be printed initially'); Writeln('with a summary of all files to be printed IF any wildcard'); Writeln('characters were entered as part of the file specification.'); END ELSE BEGIN Now.PutNow; { Fill a When stamp with today's time and date } FileSpecs := ''; { Concatenate all file specs into 1 string: } FOR I := 1 TO ParamCount DO FileSpecs := FileSpecs+' '+ParamStr(I); FilesToPrint := New(PDirEntryCollection, InitCommandLine(128,16,1)); IF FilesToPrint^.Count > 0 THEN BEGIN Writeln; Write('>>>Jlist10 is printing ',FilesToPrint^.Count,' file(s)...'); SetupPrinter; IF FilesToPrint^.Count > 1 THEN PrintStartBanner(FilesToPrint); SetPrinterLinesPerInch(8); PrintAllFiles(FilesToPrint); PrinterReset; { Reset printer at job end } Writeln; END ELSE Writeln('No files match that file spec.'); END; END.