MODULE LinePrint;

(**********************************************************************
 * Line printer program
 *
 *       Author:  Keith Thigpen
 *       
 *       Version: 1.00  12-Dec-86   Original
 *                1.10  21-Aug-87   Mods:
 *                                    (a) Addition of -c (condensed)
 *                                    (b) Fixed extra FF
 *                                    (c) Fix hang on unfound file
 *                                    (d) Changed PAR: to generic PRT:
 *    Released to the Public Domain by the Author
 *
 ***********************************************************************)

   (*$S-,$T-,$A+*)
   
   FROM ANSIPrinter IMPORT SHORP3, SHORP4, DEN1, DEN2, SGR1, SGR22;

   FROM ASCII IMPORT FF, ESC, NUL, CR, LF, SI, DC2;

   FROM CommandLine IMPORT GetCL, CLStrings;

   FROM DOSFiles IMPORT Open, Close, FileHandle, ModeOldFile;

   FROM InOut IMPORT EOL, OpenOutputFile, CloseOutput, WriteLn, Write,
                     WriteString, WriteCard;

   FROM Streams IMPORT Done, Connect, Disconnect, STREAM, ReadChar;

   FROM Strings IMPORT Concat, Length;

   (********************************************************************
    *
    * ANSIPrinter Sequences:
    * 
    ********************************************************************
    *
    * SHORP3 : condensed print off
    * SHORP4 : condensed print on
    * DEN1   : nlq off
    * DEN2   : nlq on
    * SGR1   : boldface on
    * SGR22  : boldface off
    * 
    *******************************************************************)

   CONST
      PageLen = 58;                    (* Number of lines by page *)
      CondensedOff = SHORP3;           (* condensed print off     *)
      CondensedOn  = SHORP4;           (* condensed print on      *)
      NLQOff       = DEN1;             (* nlq off                 *)
      NLQOn        = DEN2;             (* nlq on                  *)
      BoldOn       = SGR1;             (* boldface on             *)
      BoldOff      = SGR22;            (* boldface off            *)

   VAR
      ch: CHAR;
      NLQFlag, CFlag, DFlag, FFlag, SFlag, NFlag: BOOLEAN;
      
      temp, index, i, k, l, m, r: CARDINAL;
      LineNum: CARDINAL;               (* Line counter            *)
      PageNum: CARDINAL;               (* page of file            *)
      NumArgs: CARDINAL;
      Skip: CARDINAL;
      NumCopy, Copies: CARDINAL;
      File, Files: CARDINAL;
      FileNum: CARDINAL;
      ParamCtr, ParsePtr: CARDINAL;

      (* MaxCLength := 79                                         *)
      (* CLStrings  = ARRAY [0..MaxCLength -1] OF CHAR            *)

      FName:  ARRAY [0..79] OF CHAR;
      CLArgs: ARRAY [0..5] OF CLStrings;

      FOpen: FileHandle;
      In: STREAM;

   PROCEDURE copy;
   BEGIN
      Write(ch); ReadChar(In, ch);
   END copy;

   PROCEDURE PrintFooter;              (* Print page footer; "-f" *)
   BEGIN
      WriteLn; WriteLn;
      Write (ESC); WriteString (BoldOn);(* Print file name         *)
      WriteString ("File: ");
      Write (ESC); WriteString (BoldOff);
      WriteString (FName);
                                       (* Space to right of page  *)
      FOR Skip := 1 TO 35 DO           (* for page number         *)
         Write (" ");
      END;

      Write (ESC); WriteString (BoldOn);(* Print page number       *)
      WriteString ("Page: ");
      Write (ESC); WriteString (BoldOff);
      WriteCard (PageNum,3); WriteLn; Write (FF);
   END PrintFooter;

   PROCEDURE Help;                     (* '-?' selected for help  *)
   BEGIN
      WriteLn;
      WriteString ("lp version 1.10: file print utility."); WriteLn;
      WriteString ("Usage: lp [-cdfnNls?][filename]."); WriteLn;
      WriteString ("Flags:"); WriteLn;
      WriteString (" -c    condensed character print.");
      WriteLn;
      WriteString (" -d    double-spaced printout.");
      WriteLn;
      WriteString (" -f    print with filename and page footer.");
      WriteLn;
      WriteString (" -l    print in Near Letter Quality mode.");
      WriteLn;
      WriteString (" -nN   print N (nine max) copies of the file.  One is default.");
      WriteLn;
      WriteString (" -s    skip perforation."); WriteLn;
      WriteString (" -?    for help; (this listing)."); WriteLn;
      WriteString ("NOTE that -s flag is set when -f option is chosen.");
      WriteLn;
      WriteString ("by: Keith Thigpen (205)830-0453");
      WriteLn;
      HALT;
   END Help;

   PROCEDURE SetCFlag;     (* Double-Space option     *)
   BEGIN;
      CFlag := TRUE;
   END SetCFlag;

   PROCEDURE SetDFlag;     (* Double-Space option     *)
   BEGIN;
      DFlag := TRUE;
   END SetDFlag;

   PROCEDURE SetFFlag;     (* Print footer option     *)
   BEGIN;
      FFlag := TRUE;
      SFlag := TRUE;
   END SetFFlag;

   PROCEDURE SetNFlag;     (* Print multiple copies   *)
   BEGIN
      NFlag := TRUE;
   END SetNFlag;

   PROCEDURE SetNLQFlag;   (* Near Letter Quality     *)
   BEGIN
      NLQFlag := TRUE;
   END SetNLQFlag;

   PROCEDURE SetSFlag;     (* Skip Perf               *)
   BEGIN;
      SFlag := TRUE;
   END SetSFlag;

   PROCEDURE BadArgs;
   BEGIN;
      WriteString ("Bad Arguments.  Enter 'lp -?' or 'lp ?' for help.");
      WriteLn;
      HALT;
   END BadArgs;

BEGIN                                     (****   main  program   ****)

   (* Init Printer Commands *)
(*   BoldOn := "E";
   BoldOff := "F";
*)
   LineNum := 1; PageNum := 1; index := 0; Copies := 1;

   IF GetCL(NumArgs,CLArgs) THEN
      IF NumArgs = 0 THEN                          (* no file specified *)
         BadArgs;
      END;

      FOR ParamCtr := 0 TO (NumArgs - 1) DO
         ParsePtr := 0;
         IF CLArgs [ParamCtr,ParsePtr] = 055C THEN   (* '-' for options *)
            INC(ParsePtr);
            WHILE (CLArgs[ParamCtr, ParsePtr] # NUL) DO
               CASE CLArgs[ParamCtr,ParsePtr] OF
                  077C: Help;             (* -?   : help             *) |
                  103C, 143C: SetCFlag;   (* -C,c : condensed        *) |
                  104C, 144C: SetDFlag;   (* -D,d : double-spaced    *) |
                  106C, 146C: SetFFlag;   (* -F,f : print footer     *) |
                  114C, 154C: SetNLQFlag; (* -L,l : NLQ mode         *) |
                  116C, 156C:             (* -N,n : multiple copies  *)
                     temp := CARDINAL(CLArgs[ParamCtr,(ParsePtr+1)]);
                     Copies := temp - 48;
                     INC(ParsePtr);
                     SetNFlag;                                          |
                  123C, 163C: SetSFlag;   (* -S,s : skip perf        *) |
                  000C: BadArgs;                                        |
               ELSE
                  BadArgs;
               END;
            INC(ParsePtr);
            END;                          (* WHILE *)

         ELSIF CLArgs [ParamCtr,ParsePtr] = 077C THEN (* '?' for options         *)
            Help;

         ELSIF (CAP (CLArgs [ParamCtr,ParsePtr]) >= "A") AND
               (CAP (CLArgs [ParamCtr,ParsePtr]) <= "Z") THEN
            LOOP
               FName[ParsePtr] := CLArgs[ParamCtr,ParsePtr];
               IF (CLArgs[ParamCtr, ParsePtr] = NUL) THEN
                  EXIT;
               END;
               INC(ParsePtr);
            END;
         ELSE                             (* GetCL returned FALSE    *)
            BadArgs;
         END;
      END;                                (* FOR ParamCtr            *)
   END;

   IF Length (FName) = 0 THEN
      WriteString ("No File specified."); WriteLn;
      BadArgs;
   END;
                                
   Concat (FName, NUL, FName);   (***       Open Input File        ***)

   FOpen := Open (FName, ModeOldFile);
   IF FOpen = 0 THEN             (* Error in opening file            *)
      WriteString ("File not found."); WriteLn;
      HALT;
   END;
   Connect (In, FOpen);

   OpenOutputFile ("PRT:");      (***  Open Output File (Printer)  ***)

   IF CFlag THEN                 (* set condensed print mode         *)
      Write (ESC); WriteString (CondensedOn);   
   END;

   IF NLQFlag THEN               (* set NLQ print mode               *)
      Write (ESC); WriteString (NLQOn);
   END;

   FOR NumCopy := 1 TO Copies DO (* print number of copies requested *)
                                 (* with -n flag                     *)
      ReadChar (In, ch);
      REPEAT
         IF ch = EOL THEN
            copy;

            IF DFlag THEN              (* double-spaced printout *)
               INC (LineNum); Write (CR); Write (LF);
            END;

            INC (LineNum);

            IF LineNum = PageLen THEN

               IF FFlag THEN
                  PrintFooter;
               END;

               IF (SFlag = TRUE) AND
                  (FFlag = FALSE) THEN
                  Write (FF);
               END;

               LineNum := 1; INC (PageNum);
            END;

         ELSE copy;
         END;

      UNTIL ch = NUL;                   (* Parser hit EOF    *)

      IF FFlag THEN
         FOR Skip := LineNum TO PageLen DO (* Skip to bottom of *)
            WriteLn;                       (*     last page     *)
         END;
         PrintFooter;
      END;

      Close (FOpen);
      Disconnect (In);
      
      IF NOT FFlag THEN
         Write (FF);
      END;
   END;                                 (* FOR NumCopy          *)

   Write (FF);

   IF CFlag THEN                        (* clear condensed mode *)
      Write (ESC); WriteString(CondensedOff);
   END;

   IF NLQFlag THEN                      (* clear NLQ  mode      *)
      Write (ESC); WriteString (NLQOff);
   END;

   CloseOutput;

END LinePrint.
