home *** CD-ROM | disk | FTP | other *** search
/ Multimedia & CD-ROM 3 / mmcd03-jun1995-cd.iso / utils / various / utils-1 / laserlst.asm < prev    next >
Assembly Source File  |  1991-06-24  |  45KB  |  957 lines

  1.             PAGE    75,132
  2.             TITLE   "LASERLST - List file to HP LaserJet"
  3.  
  4. CSEG        SEGMENT PARA PUBLIC 'CODE'
  5.             ASSUME  CS:CSEG, DS:CSEG, ES:CSEG, SS:CSEG
  6.             ORG     100H
  7.  
  8. START:      JMP     MAIN                    ; go to start of program
  9.  
  10. HEADER_MSG  DB      "LaserLst 1.1 (c) 1989 Ziff Communications Co.", 0DH,0AH
  11.             DB      "PC Magazine ",254," Michael Holmes & Bob Flanders",0DH,0AH
  12. CRLF        DB      0DH,0AH
  13. DOLLAR      DB      "$"
  14. ; ---------------------------------------------------------------------------
  15. ;   Initialized work areas
  16. ; ---------------------------------------------------------------------------
  17. ARG1        DW      0                       ; addr of first argument
  18. ARG2        DW      0                       ; addr of second argument
  19. PHANDLE     DW      4                       ; printer handle (stdprn)
  20. TABCOL      DW      8                       ; tab width
  21. NEWPAGE     DB      0                       ; new page requested flag
  22. HPSTATE     DB      0                       ; printer state  (1 = initialized)
  23.  
  24. TITLE_      DB      1BH,"&dD"               ; title line for heading
  25. TITLE_DTE   DB      "mm/dd/yyyy  "          ; ..and display
  26. TITLE_TME   DB      "hh:mm       Filename: "
  27. TITLE_FLE   DB      19 dup(32)
  28. TITLE_DSP   EQU     $-TITLE_DTE
  29.             DB      "                    Page"
  30. TITLE_PGE   DB      "xxxx",0dh,0ah,0ah
  31.             DB      1BH,"&d@"
  32. TITLE_LEN   EQU     $-TITLE_                ; length of title
  33. ;----------------------------------------------------------------------
  34. ;   DTA structure for DOS "find matching" call
  35. ;----------------------------------------------------------------------
  36. DTA         EQU     80H                     ; dta offset
  37. DTA_ATTR    EQU     BYTE PTR DTA+21         ; file attribute
  38. DTA_TIME    EQU     WORD PTR DTA_ATTR+1     ; file time
  39. DTA_DATE    EQU     WORD PTR DTA_TIME+2     ; file date
  40. DTA_LSIZ    EQU     WORD PTR DTA_DATE+2     ; file lsw of size
  41. DTA_HSIZ    EQU     WORD PTR DTA_LSIZ+2     ; file msw of size
  42. DTA_NAME    EQU     BYTE PTR DTA_HSIZ+2     ; file name of file
  43. DTA_LEN     EQU     DTA_NAME+15-DTA         ; length of dta find entry
  44. ;----------------------------------------------------------------------
  45. ;   Messages to user
  46. ;----------------------------------------------------------------------
  47. FILENF      DB      "File not found.",0DH,0AH,"$"
  48. PRTOERR     DB      "Could not open output file.",0DH,0AH,"$"
  49. FORMAT      DB      0DH,0AH,"Command: LASERLST [d:][path]filename[.ext]"
  50.             DB      " [outfile] [/Tn]",0DH, 0AH, 0AH
  51.             DB      "where:",09H,"outfile defaults to LPT1:",0DH,0AH
  52.             DB      09H,"n is tab width (16 max)",0DH,0AH,"$"
  53. ;----------------------------------------------------------------------
  54. ;   HP control strings
  55. ;----------------------------------------------------------------------
  56. STRING1     DB      1BH,"E",1BH,"&l1O",1BH,"(s16.66H",1BH,"&l5.14C"
  57.             DB      1BH,"&l6E",1BH,"&l71F",1BH,"(s-3B"
  58.             DB      1BH,"&a0R",1BH,"&a85M",1BH,"&a5L",0DH
  59. STRING1_LEN EQU     $-STRING1
  60.  
  61. STRING2     DB      0ch,1BH,"E"
  62. STRING2_LEN EQU     $-STRING2
  63.  
  64. STRING3     DB      1BH,"&a0R",1BH,"&a90M",1BH,"&a88L",0DH,0AH,0DH,0AH
  65. STRING3_LEN EQU     $-STRING3
  66.  
  67. STRING4     DB      "|", 0DH,0AH
  68.  
  69. STRING5     DB      1BH,"&a0R",1BH,"&a171M",1BH,"&a91L",0DH
  70. STRING5_LEN EQU     $-STRING5
  71.  
  72. STRING6     DB      0CH,1BH,"&a0R",1BH,"&a85M",1BH,"&a5L",0DH
  73. STRING6_LEN EQU     $-STRING6
  74. ; ---------------------------------------------------------------------------
  75. ;   MAIN - Mainline of program
  76. ; ---------------------------------------------------------------------------
  77. MAIN        PROC                            ; start of program
  78.  
  79.             CALL    INIT                    ; initialize program
  80.  
  81. MAIN10:     CALL    OPEN                    ; open the input file
  82.             JC      MAIN80                  ; if we can't .. try next
  83.  
  84. MAIN20:     CALL    READ                    ; read a block
  85.  
  86.             CALL    PRINT                   ; print the line
  87.  
  88.             OR      SI, SI                  ; q. end of file?
  89.             JNZ     MAIN20                  ; a. no .. get next line
  90.  
  91.             MOV     BX, FHANDLE             ; bx = input file handle
  92.             MOV     AH, 3EH                 ; ah = close file
  93.             INT     21H                     ; .. ask DOS to do it
  94.  
  95. MAIN80:     MOV     AH, 4FH                 ; ah = find next file
  96.             INT     21H                     ; q. file found?
  97.             JNC     MAIN10                  ; a. yes .. continue
  98.  
  99.             MOV     DX, OFFSET DOLLAR       ; dx -> null message
  100.             CALL    DIE                     ; .. say goodnight
  101.  
  102. MAIN        ENDP
  103. ; ---------------------------------------------------------------------------
  104. ;   INIT - Handle initialization
  105. ; ---------------------------------------------------------------------------
  106. INIT        PROC
  107.  
  108.             CLD                             ; assure ascending
  109.             MOV     AH, 19H                 ; ah = get current drive
  110.             INT     21H                     ; al = current drive
  111.             MOV     EDRV, AL                ; save entry drive
  112.  
  113.             MOV     SI, OFFSET EDIR         ; si -> current directory area
  114.             MOV     BYTE PTR [SI], '\'      ; .. start with backslash
  115.             INC     SI                      ; si -> next byte
  116.             XOR     DL, DL                  ; dl = default drive
  117.             MOV     AH, 47H                 ; ah = get current dir
  118.             INT     21H                     ; .. save in area
  119.  
  120.             MOV     DX, OFFSET HEADER_MSG   ; dx -> header message
  121.             MOV     AH, 9                   ; ah = print ascii$ message
  122.             INT     21H                     ; .. ask DOS to do it
  123.  
  124.             CALL    PARMS                   ; check parameters
  125.  
  126.             CMP     ARG2, 0                 ; q. arg2 specified?
  127.             JE      INIT20                  ; a. yes .. skip open
  128.  
  129.             MOV     DX, ARG2                ; dx -> arg2 value
  130.             MOV     AH, 3CH                 ; ah = create file
  131.             XOR     CX, CX                  ; .. cx = file attributes
  132.             INT     21H                     ; q. open the file ok?
  133.             JNC     INIT10                  ; a. yes .. continue
  134.  
  135.             MOV     DX, OFFSET PRTOERR      ; dx -> open error message
  136.             CALL    DIE                     ; .. you're dead, Jim.
  137.  
  138. INIT10:     MOV     PHANDLE, AX             ; save printer handle
  139.  
  140. INIT20:     CALL    DFLPATH                 ; set up dir & drive
  141.  
  142.             MOV     AH, 4EH                 ; ah = find first
  143.             MOV     DX, OFFSET FILENAME     ; dx -> file to find
  144.             XOR     CX, CX                  ; cx = search attribute
  145.             INT     21H                     ; q. find first file ok?
  146.             JNC     INIT90                  ; a. yes .. continue
  147.  
  148.             MOV     DX, OFFSET FILENF       ; dx -> file not found
  149.             CALL    DIE                     ; .. gasp you're final breath
  150.  
  151. INIT90:     RET                             ; return to caller
  152.  
  153. INIT        ENDP
  154. ; ---------------------------------------------------------------------------
  155. ;   OPEN - Opens the next file to process and update title line
  156. ;     Exit: Carry indicates file would not open.
  157. ; ---------------------------------------------------------------------------
  158. OPEN        PROC
  159.  
  160.             MOV     DX, OFFSET DTA_NAME     ; dx -> file name
  161.             MOV     AX, 3D00H               ; al = open for read
  162.             INT     21H                     ; .. ask DOS to do it.
  163.             JNC     OPEN05                  ; ok .. continue
  164.  
  165.             RET                             ; else .. return if error
  166.  
  167. OPEN05:     MOV     FHANDLE, AX             ; save file handle
  168.             MOV     LASTBUFF, 0             ; show last buffer not read
  169.  
  170.             MOV     SI, OFFSET DTA_NAME     ; si -> file name
  171.             MOV     DI, OFFSET TITLE_FLE    ; di -> file name area
  172.             PUSH    DI                      ; .. save it
  173.             MOV     AL, ' '                 ; al = blank
  174.             MOV     CX, 15                  ; .. amount to blank
  175.       REP   STOSB                           ; .. clear the file name
  176.             POP     DI                      ; .. restore output pointer
  177.  
  178. OPEN10:     LODSB                           ; al = byte from file name
  179.  
  180.             OR      AL, AL                  ; q. end of name?
  181.             JZ      OPEN20                  ; a. yes .. end loop
  182.  
  183.             STOSB                           ; store a byte
  184.             JMP     OPEN10                  ; .. and move next
  185.  
  186. OPEN20:     MOV     BL, '0'                 ; fill value
  187.             MOV     AX, DS:DTA_DATE         ; ax = date field
  188.             PUSH    AX                      ; save for later
  189.             PUSH    AX                      ; .. again
  190.  
  191.             MOV     CL, 5                   ; cl = shift value
  192.             SHR     AX, CL                  ; .. mm to lower bits
  193.             AND     AX, 0FH                 ; .. upper bits off
  194.             MOV     CX, 2                   ; cx = number of characters
  195.             MOV     DI, OFFSET TITLE_DTE    ; di -> mm
  196.             CALL    ITOA                    ; .. move in mm
  197.  
  198.             POP     AX                      ; ax = date
  199.             AND     AX, 1FH                 ; al = dd
  200.             MOV     CX, 2                   ; cx = number of chars
  201.             MOV     DI, OFFSET TITLE_DTE+3  ; di -> dd
  202.             CALL    ITOA                    ; .. move into dd
  203.  
  204.             POP     AX                      ; ax = date
  205.             MOV     CL, 9                   ; cl = shift amount
  206.             SHR     AX, CL                  ; .. ax = yy
  207.             ADD     AX, 1980                ; ax = year
  208.             MOV     CX, 4                   ; cx = length of output
  209.             MOV     DI, OFFSET TITLE_DTE+6  ; di -> yyyy
  210.             CALL    ITOA                    ; .. move into yyyy
  211.  
  212.             MOV     AX, DS:DTA_TIME         ; ax = time
  213.             PUSH    AX                      ; .. save for later
  214.             MOV     CL, 11                  ; cl = shift value
  215.             SHR     AX, CL                  ; .. ax = hh
  216.             MOV     CX, 2                   ; cx = length of output
  217.             MOV     DI, OFFSET TITLE_TME    ; di -> hh
  218.             CALL    ITOA                    ; .. move into hh
  219.  
  220.             POP     AX                      ; ax = time
  221.             MOV     CL, 5                   ; cl = shift value
  222.             SHR     AX, CL                  ; ax = mm
  223.             AND     AX, 3FH                 ; .. upper bits off
  224.             MOV     CX, 2                   ; cx = length of output
  225.             MOV     DI, OFFSET TITLE_TME+3  ; di -> mm
  226.             CALL    ITOA                    ; .. move into mm
  227.  
  228.             MOV     AH, 40H                 ; ah = write to device
  229.             MOV     BX, 1                   ; bx = stdout device
  230.             MOV     CX, TITLE_DSP           ; cx = length to display
  231.             MOV     DX, OFFSET TITLE_DTE    ; dx -> part of header line
  232.             INT     21H                     ; issue dos call
  233.  
  234.             MOV     AH, 40H                 ; ah = write to device
  235.             MOV     BX, 1                   ; bx = stdout device
  236.             MOV     CX, 2                   ; cx = length to display
  237.             MOV     DX, OFFSET CRLF         ; dx -> <cr><lf> string
  238.             INT     21H                     ; issue dos call
  239.  
  240.             CLC                             ; show all went ok
  241. OPEN90:     RET
  242.  
  243. OPEN        ENDP
  244. ; ---------------------------------------------------------------------------
  245. ;   READ - Read the next buffer full
  246. ;     Exit: si -> next line, 0 if eof, cx =  length of line
  247. ; ---------------------------------------------------------------------------
  248. READ        PROC
  249.  
  250.             PUSH    AX                      ; save registers
  251.             PUSH    BX
  252.             PUSH    DX
  253.  
  254.             MOV     SI, 0                   ; si -> nothing
  255.  
  256.             CMP     LASTBUFF, 1             ; q. last buffer have 1ah?
  257.             JE      READ90                  ; a. yes .. end it all
  258.  
  259.             MOV     AH, 03FH                ; ah = read file
  260.             MOV     BX, FHANDLE             ; bx = handle of file to read
  261.             MOV     CX, BUFLEN              ; cx = amount to read
  262.             MOV     DX, OFFSET BUFFER       ; dx -> buffer
  263.             INT     21H                     ; read, please
  264.             JC      READ90                  ; error .. return eof
  265.  
  266.             OR      AX, AX                  ; q. any read?
  267.             JZ      READ90                  ; a. yes .. return with something
  268.  
  269.             MOV     SI, OFFSET BUFFER       ; si -> start of line
  270.             MOV     CX, AX                  ; cx = nbr of characters read
  271.             MOV     BX, AX                  ; .. and bx
  272.  
  273.             MOV     DI, SI                  ; di -> chars read
  274.             MOV     AL, 1AH                 ; al = EOF indicator
  275.  
  276.     REPNE   SCASB                           ; q. eof found?
  277.             JNE     READ80                  ; a. no .. continue
  278.  
  279.             INC     CX                      ; .. increment count
  280.             NEG     CX                      ; .. and negate it
  281.             MOV     LASTBUFF, 1             ; .. and set lastbuff flag
  282.  
  283. READ80:     ADD     CX, BX                  ; q. any bytes this buffer?
  284.             JNZ     READ90                  ; a. yes .. continue
  285.  
  286.             MOV     SI, 0                   ; a. else .. show end of file.
  287.  
  288. READ90:     POP     DX                      ; restore registers
  289.             POP     BX                      ;
  290.             POP     AX                      ;
  291.             RET                             ; ..and return to caller
  292.  
  293. READ        ENDP
  294. ; ---------------------------------------------------------------------------
  295. ;   PRINT - Print requested data
  296. ;     Entry: si -> string to print or 0, cx =  length of input string
  297. ; ---------------------------------------------------------------------------
  298. PRINT       PROC
  299.  
  300.             OR      SI, SI                  ; q. end of file call?
  301.             JNE     PRINT10                 ; a. no .. continue
  302.  
  303.             CALL    EPILOGUE                ; put out trailing characters
  304.             RET                             ; ..and return to caller
  305.  
  306. PRINT10:    PUSH    AX                      ; save registers
  307.             PUSH    BX
  308.             PUSH    CX
  309.             PUSH    DX
  310.             PUSH    SI
  311.  
  312.             CMP     HPSTATE, 0              ; q. initial state?
  313.             JNE     PRINT20                 ; a. no .. continue
  314.  
  315.             CALL    PROLOGUE                ; send out initial string
  316.  
  317. PRINT20:    CALL    EXPAND                  ; handle tab expansion
  318.             MOV     DX, SI                  ; dx -> start of new buffer
  319.             MOV     BX, CX                  ; bx = nbr of chars in buffer
  320.             XOR     CX, CX                  ; cx = nbr of chars to print
  321.             MOV     AH, USEDLEN             ; ah = printed chars in this line
  322.  
  323. PRINT30:    LODSB                           ; al = first character
  324.  
  325.             CMP     AL, 0CH                 ; q. formfeed?
  326.             JNE     PRINT40                 ; a. yes .. process it
  327.  
  328.             CALL    LINEPRT                 ; print the line
  329.             CALL    PAGEBREAK               ; do a page break
  330.             XOR     AH, AH                  ; ah = nbr of columns used
  331.             DEC     BX                      ; bx = decrement remaining count
  332.             INC     DX                      ; dx -> next printable character
  333.             JMP     PRINT70                 ; ..and continue w/common code
  334.  
  335. PRINT40:    CMP     AL, 0AH                 ; q. linefeed?
  336.             JNE     PRINT50                 ; a. no .. continue
  337.  
  338.             DEC     BX                      ; bx = remaining chars in buffer
  339.             INC     CX                      ; cx = nbr of characters to print
  340.             CALL    LINEPRT                 ; print the line
  341.             XOR     AH, AH                  ; ah = nbr of columns used
  342.             CALL    BUMPLINE                ; increment/test line counter
  343.             JMP     PRINT70                 ; ..and continue w/common code
  344.  
  345. PRINT50:    CMP     AL, 0DH                 ; q. carriage return?
  346.             JNE     PRINT55                 ; a. no .. continue
  347.             JMP     SHORT PRINT57           ; ..and continue w/common code
  348.  
  349. PRINT55:    CMP     AL, 08H                 ; q. BackSpace?
  350.             JNE     PRINT60                 ; a. no .. continue
  351.  
  352.             DEC     AH                      ; move back a column
  353.             JNS     PRINT65                 ; .. but not beyond first
  354.  
  355. PRINT57:    XOR     AH, AH                  ; ah = start of line
  356.             JMP     SHORT PRINT65           ; .. and continue
  357.  
  358. PRINT60:    INC     AH                      ; increment nbr of columns used
  359. PRINT65:    INC     CX                      ; ..and nbr of chars to print
  360.             DEC     BX                      ; decrement remaining char count
  361.  
  362.             CMP     AH, 81                  ; q. reached end of line?
  363.             JL      PRINT70                 ; a. no .. continue
  364.  
  365.             CALL    LINEPRT                 ; print upto page width
  366.             PUSH    CX                      ; save registers
  367.             PUSH    DX                      ;
  368.             MOV     DX, OFFSET CRLF         ; dx -> <cr><lf>
  369.             MOV     CX, 2                   ; cx = string length
  370.             CALL    WRITE                   ; print the crlf to do line wrapping
  371.             POP     DX                      ; restore registers
  372.             POP     CX                      ;
  373.             XOR     AH, AH                  ; ah = nbr of columns used
  374.             CALL    BUMPLINE                ; increment/test line counter
  375.  
  376. PRINT70:    OR      BX, BX                  ; q. anything left to check?
  377.             JNZ     PRINT30                 ; a. yes .. loop till done
  378.  
  379.             CALL    LINEPRT                 ; print the line
  380.             MOV     USEDLEN, AH             ; save nbr of columns used
  381.  
  382.             POP     SI                      ; restore registers
  383.             POP     DX                      ;
  384.             POP     CX                      ;
  385.             POP     BX                      ;
  386.             POP     AX                      ;
  387.             RET                             ; ..and return to caller
  388.  
  389. PRINT       ENDP
  390. ; ---------------------------------------------------------------------------
  391. ;   DIE - Display an error message and return to DOS
  392. ;     Entry: dx -> error message ended in dollar sign.
  393. ; ---------------------------------------------------------------------------
  394. DIE         PROC
  395.  
  396.             MOV     AH, 9                   ; ah = print string
  397.             INT     21H                     ; .. call dos to print error
  398.  
  399.             MOV     DL, EDRV                ; dl = drive to select
  400.             MOV     AH, 0EH                 ; ah = select drive
  401.             INT     21H                     ; .. select the drive
  402.  
  403.             MOV     DX, OFFSET EDIR         ; dx -> directory
  404.             MOV     AH, 3BH                 ; ah = CHDIR request
  405.             INT     21H                     ; .. ask DOS to do it
  406.  
  407.             MOV     AX, 4C00H               ; ax = exit
  408.             INT     21H                     ; .. terminate routine
  409.  
  410. DIE         ENDP
  411. ; ---------------------------------------------------------------------------
  412. ;   PARMS - Parses the command line
  413. ; ---------------------------------------------------------------------------
  414. PARMS       PROC
  415.  
  416.             CALL    UPCASE                  ; upper case the parm area
  417.             MOV     SI, 81H                 ; si -> parms area
  418.  
  419. PARMS10:    LODSB                           ; get parameter character
  420.  
  421.             CMP     AL, '/'                 ; q. option?
  422.             JE      PARMS80                 ; a. yes .. check option
  423.             CMP     AL, 0DH                 ; q. end of line?
  424.             JE      PARMS50                 ; a. yes .. exit
  425.             CMP     AL, ' '                 ; q. blank?
  426.             JNA     PARMS10                 ; a. yes .. skip
  427.             CALL    ARG                     ; set the argument
  428.             JC      PARMSERR                ; .. die on an error
  429.  
  430. PARMS30:    LODSB                           ; get next character
  431.             CMP     AL, 0DH                 ; q. end of line?
  432.             JE      PARMS50                 ; a. yes .. process
  433.             CMP     AL, '/'                 ; q. start of option?
  434.             JE      PARMS80                 ; a. yes .. process
  435.             CMP     AL, ' '                 ; q. end of PARMS?
  436.             JA      PARMS30                 ; a. no .. next char
  437.  
  438.             CALL    ENDPARM                 ; terminate parm string
  439.             JMP     PARMS10                 ; .. look for next
  440.  
  441. PARMS50:    CALL    ENDPARM                 ; terminate parm string
  442.  
  443.             CMP     ARG1, 0                 ; q. PARMS 1 available?
  444.             JE      PARMSERR                ; a. no .. error
  445.             RET                             ; .. else .. return to caller
  446.  
  447. PARMS80:    CALL    ENDPARM                 ; terminate parm string
  448.             LODSB                           ; al = option character
  449.  
  450.             CMP     AL, 'T'                 ; q. Tab width?
  451.             JNE     PARMSERR                ; a. no .. error in option
  452.  
  453.             CALL    ATOI                    ; ax =  tab width
  454.  
  455.             CMP     AX, 16                  ; q. request greater than max?
  456.             JG      PARMS10                 ; a. yes .. unreasonable
  457.  
  458.             MOV     TABCOL, AX              ; .. save tab width
  459.             JMP     PARMS10                 ; .. continue scan
  460.  
  461. PARMSERR:   MOV     DX, OFFSET FORMAT       ; dx -> format message
  462.             CALL    DIE                     ; abort
  463.  
  464. PARMS       ENDP
  465. ; ---------------------------------------------------------------------------
  466. ;   ARG - Setup pointers to the command line arguments
  467. ;     Entry: si -> second character in argument.
  468. ;     Exit: ARG1 or ARG2 pointers filled in.
  469. ;       Carry set if more than 2 arguments detected.
  470. ; ---------------------------------------------------------------------------
  471. ARG         PROC
  472.  
  473.             LEA     BX, [SI-1]              ; bx -> argument
  474.             CMP     ARG1, 0                 ; q. arg1 filled in?
  475.             JNE     ARG10                   ; a. yes .. check 2
  476.             MOV     ARG1, BX                ; save arg1 pointer
  477.             JMP     SHORT ARG90             ; .. exit ok!
  478.  
  479. ARG10:      CMP     ARG2, 0                 ; q. arg2 filled in?
  480.             JE      ARG20                   ; a. no .. fill it in
  481.             STC                             ; else .. error
  482.             RET                             ; .. and return to caller
  483.  
  484. ARG20:      MOV     ARG2, BX                ; save arg2 pointer
  485. ARG90:      CLC                             ; show no error
  486.             RET                             ; return to caller
  487.  
  488. ARG         ENDP
  489. ; ---------------------------------------------------------------------------
  490. ;   ENDPARM - Handle parameters which end in a colon
  491. ;     Entry: si -> first character past end of parameter
  492. ; ---------------------------------------------------------------------------
  493. ENDPARM     PROC
  494.  
  495.             CMP     BYTE PTR [SI-2], ':'    ; q. argument end in a colon?
  496.             JNE     ENDPARM10               ; a. no .. continue
  497.  
  498.             MOV     BYTE PTR [SI-2], 0      ; ..it doesn't any more
  499.             RET                             ; ..and return
  500.  
  501. ENDPARM10:  MOV     BYTE PTR [SI-1], 0      ; end the parameter
  502.             RET                             ; ..and return
  503.  
  504. ENDPARM     ENDP
  505. ; ---------------------------------------------------------------------------
  506. ;   DFLPATH - Setup the default drive and path
  507. ; ---------------------------------------------------------------------------
  508. DFLPATH     PROC
  509.  
  510.             MOV     DI, ARG1                ; di -> first arg
  511.  
  512. DFLPATH10:  CMP     BYTE PTR [DI+1], ':'    ; q. drive specified?
  513.             JNE     DFLPATH20               ; a. no .. use current drive
  514.             MOV     DL, [DI]                ; dl = drive to use
  515.             SUB     DL, 'A'                 ; get requested drive number
  516.             MOV     AH, 0EH                 ; set requested drive
  517.             INT     21H                     ; .. via dos
  518.             ADD     DI, 2                   ; di -> next part
  519.  
  520. DFLPATH20:  PUSH    DI                      ; save pointer
  521.             MOV     BX, DI                  ; bx -> start of area
  522.             XOR     AL, AL                  ; al = search for null
  523.             MOV     CX, 128                 ; very max to search
  524.             CLD
  525.     REPNE   SCASB                           ; find end of arg
  526.             LEA     SI, [DI-1]              ; si -> nul
  527.             MOV     CX, 0                   ; cx = # chars to move
  528.             CMP     SI, BX                  ; q. any file name
  529.             JE      DFLPATH80               ; a. no .. error
  530.  
  531. DFLPATH30:  DEC     SI                      ; si -> prev char
  532.             CMP     BYTE PTR [SI], '\'      ; q. dir?
  533.             JE      DFLPATH35               ; a. yes .. end of file name.
  534.             INC     CX                      ; cx = char count
  535.             CMP     SI, BX                  ; q. done?
  536.             JE      DFLPATH37               ; a. yes .. move file name
  537.             JMP     DFLPATH30               ; .. continue
  538.  
  539. DFLPATH35:  INC     SI                      ; si -> start of file name
  540. DFLPATH37:  OR      CX, CX                  ; q. file name spec'd?
  541.             JZ      DFLPATH80               ; a. no .. error
  542.             CMP     CX, 12                  ; q. too long?
  543.             JA      DFLPATH85               ; a. yes .. error
  544.             PUSH    SI                      ; save start pointer
  545.             MOV     DI, OFFSET FILENAME     ; di -> file name
  546.             INC     CX                      ; .. assure nul moves too
  547.      REP    MOVSB                           ; .. move in the file name
  548.             POP     SI                      ; restore start pointer
  549.             POP     DI                      ; .. and dir pointer
  550.             CMP     SI, BX                  ; q. at start of parm?
  551.             JE      DFLPATH90               ; a. yes .. return
  552.             INC     BX                      ; bx -> next char
  553.             CMP     SI, BX                  ; q. root only given?
  554.             JE      DFLPATH40               ; a. yes .. continue
  555.             DEC     SI                      ; si -> last \
  556.  
  557. DFLPATH40:  MOV     BYTE PTR [SI], 0        ; make dir ASCIIZ
  558. DFLPATH50:  MOV     DX, DI                  ; dx -> directory
  559.             MOV     AH, 3BH                 ; ah = CHDIR opcode
  560.             INT     21H                     ; .. change directory
  561.             JNC     DFLPATH90               ; if ok .. continue
  562.             JMP     SHORT DFLPATH85         ; dx -> baddir request
  563.  
  564. DFLPATH80:  MOV     DX, OFFSET FORMAT       ; dx -> no file specified
  565.             CALL    DIE
  566.  
  567. DFLPATH85:  MOV     DX, OFFSET FILENF       ; dx -> invalid filename spec'd
  568.             CALL    DIE
  569.  
  570. DFLPATH90:  RET                             ; return to caller
  571.  
  572. DFLPATH     ENDP
  573. ; ---------------------------------------------------------------------------
  574. ;   EXPAND - Handle tab expansion
  575. ;     Entry:
  576. ;       si -> line read from file ended by a linefeed
  577. ;       cx =  length of line
  578. ;     Exit:
  579. ;       si -> reformatted line in output buffer
  580. ;       cx =  new line length
  581. ; ---------------------------------------------------------------------------
  582. EXPAND      PROC
  583.  
  584.             PUSH    AX                      ; save registers
  585.             PUSH    BX
  586.             PUSH    DX
  587.             PUSH    DI
  588.  
  589.             MOV     DI, OFFSET OBUFF        ; di -> start of output buffer
  590.  
  591. EXPAND10:   LODSB                           ; al = character from input line
  592.  
  593.             CMP     AL, 09H                 ; q. tab character?
  594.             JNE     EXPAND30                ; a. no .. continue processing
  595.  
  596.             MOV     AX, CURCOL              ; ax = current column
  597.             DEC     AX                      ; ax = column offset
  598.             XOR     DX, DX                  ; dx:ax = current column
  599.             MOV     BX, TABCOL              ; bx = nbr of columns per tab
  600.             IDIV    BX                      ; dx = space within tab stop
  601.  
  602.             SUB     BX, DX                  ; bx = spaces left in tab stop
  603.  
  604.             MOV     AL, 20H                 ; al = space char to padding string
  605.  
  606. EXPAND20:   STOSB                           ; put a blank in output buffer
  607.             INC     CURCOL                  ; bump current column nbr
  608.  
  609.             DEC     BX                      ; q. done yet?
  610.             JNZ     EXPAND20                ; a. no .. keep looping
  611.             JMP     SHORT EXPAND50          ; a. yes .. get next character
  612.  
  613. EXPAND30:   CMP     AL, 0DH                 ; q. carriage return?
  614.             JE      EXPAND33                ; a. yes .. reset column
  615.  
  616.             CMP     AL, 0CH                 ; q. form feed?
  617.             JNE     EXPAND35                ; a. no .. continue processing
  618.  
  619. EXPAND33:   MOV     CURCOL, 0               ; setup for start of new line
  620.             JMP     SHORT EXPAND40          ; .. continue
  621.  
  622. EXPAND35:   CMP     AL, 08H                 ; q. backspace?
  623.             JNE     EXPAND40                ; a. no .. continue
  624.  
  625.             STOSB                           ; save the BS
  626.             DEC     CURCOL                  ; .. move back a space
  627.             JNZ     EXPAND50                ; .. get next character
  628.  
  629.             MOV     CURCOL, 1               ; init current column
  630.             JMP     SHORT EXPAND50          ; .. continue
  631.  
  632. EXPAND40:   STOSB                           ; move character to output line
  633.             CMP     AL, 0AH                 ; q. line feed?
  634.             JE      EXPAND50                ; a. yes .. don't count it
  635.  
  636.             INC     CURCOL                  ; bump current column nbr
  637.  
  638. EXPAND50:   LOOP    EXPAND10                ; ..loop till input exhausted
  639.  
  640.             MOV     SI, OFFSET OBUFF        ; si -> start of output buffer
  641.             MOV     CX, DI                  ; di -> just past last char of output
  642.             SUB     CX, SI                  ; cx = nbr of characters in output
  643.  
  644.             POP     DI                      ; restore registers
  645.             POP     DX
  646.             POP     BX
  647.             POP     AX
  648.             RET                             ; ..and return to caller
  649.  
  650. EXPAND      ENDP
  651. ; ---------------------------------------------------------------------------
  652. ;   LINEPRT - Handle printing a line
  653. ;     Entry:
  654. ;       dx -> start of line
  655. ;       cx =  nbr of characters to print
  656. ;     Exit:
  657. ;       dx -> start of next line
  658. ;       cx =  0
  659. ; ---------------------------------------------------------------------------
  660. LINEPRT     PROC
  661.  
  662.             JCXZ    LINEPRT90               ; if nothing to print.. return
  663.  
  664.             CMP     NEWPAGE, 1              ; q. need a new page?
  665.             JNE     LINEPRT10               ; a. no .. continue
  666.  
  667.             CALL    PAGEBREAK               ; else .. do a pagebreak
  668.  
  669. LINEPRT10:  CALL    WRITE                   ; write the line
  670.  
  671.             ADD     DX, CX                  ; dx -> start of next line
  672.             XOR     CX, CX                  ; cx = nbr of characters to print
  673. LINEPRT90:  RET
  674.  
  675. LINEPRT     ENDP
  676. ; ---------------------------------------------------------------------------
  677. ;   MKTITLE - Make the title line be ready to print
  678. ;     Exit:
  679. ;       dx -> title line
  680. ;       cx =  title line length
  681. ; ---------------------------------------------------------------------------
  682. MKTITLE     PROC
  683.             PUSH    AX                      ; save registers
  684.             PUSH    BX
  685.             PUSH    DI
  686.  
  687.             MOV     AX, PAGENO              ; ax = page number
  688.             MOV     CX, 4                   ; cx = length of output
  689.             MOV     BL, ' '                 ; bl = fill char (blank)
  690.             MOV     DI, OFFSET TITLE_PGE    ; di -> output area
  691.             CALL    ITOA                    ; .. fill in page number
  692.  
  693.             MOV     DX, OFFSET TITLE_       ; dx -> title
  694.             MOV     CX, TITLE_LEN           ; cx = length of title
  695.             CALL    WRITE                   ; print title line
  696.  
  697.             POP     DI                      ; restore registers
  698.             POP     BX
  699.             POP     AX
  700.             RET                             ; return to caller
  701.  
  702. MKTITLE     ENDP
  703. ; ---------------------------------------------------------------------------
  704. ;   PAGEBREAK - Handle page overflow condition
  705. ; ---------------------------------------------------------------------------
  706. PAGEBREAK   PROC
  707.  
  708.             PUSH    BX                      ; save registers
  709.             PUSH    CX
  710.             PUSH    DX
  711.  
  712.             TEST    PAGENO, 1               ; q. finishing up with left page?
  713.             JZ      PAGEBRK20               ; a. no .. do other page
  714.  
  715.             MOV     DX, OFFSET STRING3      ; dx -> get to right page string
  716.             MOV     CX, STRING3_LEN         ; cx = length
  717.             CALL    WRITE                   ; write out 1st part of string
  718.  
  719.             MOV     BX, 66                  ; bx = loop count
  720.             MOV     CX, 3                   ; cx = nbr of chars to print
  721.             MOV     DX, OFFSET STRING4      ; dx -> vertical bar string
  722.  
  723. PAGEBRK10:  CALL    WRITE                   ; write on line of vertical bars
  724.  
  725.             DEC     BX                      ; q. done yet?
  726.             JNZ     PAGEBRK10               ; a. no .. keep looping
  727.  
  728.             MOV     DX, OFFSET STRING5      ; dx -> string to finish up
  729.             MOV     CX, STRING5_LEN         ; cx = length
  730.             JMP     PAGEBRK30               ; ..and continue w/common code
  731.  
  732. PAGEBRK20:  MOV     DX, OFFSET STRING6      ; dx -> get to left page string
  733.             MOV     CX, STRING6_LEN         ; cx = length
  734.  
  735. PAGEBRK30:  CALL    WRITE                   ; print the init line
  736.  
  737.             MOV     LINECNT, 1              ; reset line counter
  738.             MOV     NEWPAGE, 0              ; clear new page request flag
  739.             INC     PAGENO                  ; ..and bump page number
  740.  
  741.             CALL    MKTITLE                 ; print title line
  742.  
  743.             POP     DX                      ; restore registers
  744.             POP     CX                      ;
  745.             POP     BX                      ;
  746.             RET                             ; ..and return to caller
  747.  
  748. PAGEBREAK   ENDP
  749. ; ---------------------------------------------------------------------------
  750. ;   BUMPLINE - Increment line counter and test for overflow
  751. ; ---------------------------------------------------------------------------
  752. BUMPLINE    PROC
  753.             INC     LINECNT                 ; increment line counter
  754.  
  755.             CMP     LINECNT, 66             ; q. reached max lines/page?
  756.             JLE     BUMPLINE90              ; a. no .. continue
  757.  
  758.             MOV     NEWPAGE, 1              ; else .. show we'll need a new one
  759.  
  760. BUMPLINE90: RET                             ; ..then return to caller
  761.  
  762. BUMPLINE    ENDP
  763. ; ---------------------------------------------------------------------------
  764. ;   PROLOGUE - Put out laserjet initialization string
  765. ; ---------------------------------------------------------------------------
  766. PROLOGUE    PROC
  767.  
  768.             PUSH    CX                      ; save registers
  769.             PUSH    DX
  770.  
  771.             MOV     DX, OFFSET STRING1      ; dx -> initialization string
  772.             MOV     CX, STRING1_LEN         ; cx = length
  773.             CALL    WRITE                   ; print the init line
  774.  
  775.             MOV     PAGENO, 1               ; setup page number
  776.             MOV     CURCOL, 1               ; ..and current column number
  777.             MOV     LINECNT, 1              ; ..and line counter
  778.             MOV     HPSTATE, 1              ; ..show in left page
  779.             MOV     USEDLEN, 0              ; ..clear column position
  780.             CALL    MKTITLE                 ; print title line
  781.  
  782.             POP     DX                      ; restore registers
  783.             POP     CX                      ;
  784.             RET                             ; ..and return to caller
  785.  
  786. PROLOGUE    ENDP
  787. ; ---------------------------------------------------------------------------
  788. ;   EPILOGUE - Put out laserjet finish up string
  789. ; ---------------------------------------------------------------------------
  790. EPILOGUE    PROC
  791.  
  792.             PUSH    CX                      ; save registers
  793.             PUSH    DX
  794.  
  795.             MOV     DX, OFFSET STRING2      ; dx -> termination string
  796.             MOV     CX, STRING2_LEN         ; cx = length
  797.             CALL    WRITE                   ; print the init line
  798.  
  799.             MOV     HPSTATE, 0              ; show back to initialization state
  800.  
  801.             POP     DX                      ; restore registers
  802.             POP     CX                      ;
  803.             RET                             ; ..and return to caller
  804.  
  805. EPILOGUE    ENDP
  806. ; ---------------------------------------------------------------------------
  807. ;   WRITE - Send a string to the printer
  808. ;     Entry:
  809. ;       dx -> string to write
  810. ;       cx =  nbr of characters
  811. ; ---------------------------------------------------------------------------
  812. WRITE       PROC
  813.  
  814.             PUSH    AX                      ; save registers
  815.             PUSH    BX
  816.  
  817.             MOV     AH, 40H                 ; ah = write to file/device function
  818.             MOV     BX, PHANDLE             ; bx = printer handle
  819.             INT     21H                     ; issue dos call
  820.  
  821.             POP     BX                      ; restore registers
  822.             POP     AX                      ;
  823.             RET                             ; ..and return to caller
  824.  
  825. WRITE       ENDP
  826. ; ---------------------------------------------------------------------------
  827. ;   UPCASE - Convert command line arguments to uppercase
  828. ; ---------------------------------------------------------------------------
  829. UPCASE      PROC
  830.  
  831.             PUSH    SI                      ; save caller regs
  832.             PUSH    DI
  833.             MOV     SI, 81H                 ; si -> start of parm area
  834.             MOV     DI, SI                  ; .. same for di
  835.             CLD                             ; .. assure ascending
  836.  
  837. UPCASE10:   LODSB                           ; al = char
  838.             CMP     AL, 0DH                 ; q. end of line?
  839.             JE      UPCASE90                ; a. yes .. end of line!
  840.             CMP     AL, 'a'                 ; q. is it below 'a'?
  841.             JB      UPCASE20                ; a. yes .. continue
  842.             CMP     AL, 'z'                 ; q. is it above 'z'?
  843.             JA      UPCASE20                ; a. yes .. continue
  844.             SUB     AL, 20H                 ; set to upper case
  845.  
  846. UPCASE20:   STOSB                           ; save the byte
  847.             JMP     UPCASE10                ; .. and continue
  848.  
  849. UPCASE90:   POP     DI                      ; restore caller regs
  850.             POP     SI
  851.             RET                             ; .. and return to caller
  852.  
  853. UPCASE      ENDP
  854. ; ---------------------------------------------------------------------------
  855. ;   ATOI - Translate an ascii value to binary
  856. ;     Entry:
  857. ;       si -> ascii value
  858. ;     Exit:
  859. ;       al =  binary value
  860. ; ---------------------------------------------------------------------------
  861. ATOI        PROC
  862.  
  863.             XOR     AX, AX                  ; ax = accumulator = 0
  864.  
  865. ATOI10:     CMP     BYTE PTR [SI], '0'      ; q. below ascii 0?
  866.             JB      ATOI90                  ; a. yes.. exit
  867.  
  868.             CMP     BYTE PTR [SI], '9'      ; q. above ascii 9?
  869.             JA      ATOI90                  ; a. yes.. exit
  870.  
  871.             XOR     AH, AH                  ; reset ah
  872.             MOV     BL, 10                  ; bl = multiply value
  873.             MUL     BL                      ; .. multiply by 10
  874.             MOV     BL, [SI]                ; bl = value
  875.             AND     BL, 0FH                 ; .. upper bits off
  876.             ADD     AL, BL                  ; .. add to bl
  877.  
  878.             INC     SI                      ; si -> next char
  879.             JMP     ATOI10                  ; .. tranlate it
  880.  
  881. ATOI90:     RET                             ; .. return to caller
  882.  
  883. ATOI        ENDP
  884. ; ---------------------------------------------------------------------------
  885. ;   ITOA - Integer to ASCII characters
  886. ;     Entry:
  887. ;       ax =  value to convert
  888. ;       bl =  fill character
  889. ;       cx =  nbr of characters
  890. ;       di -> start of alpha area
  891. ; ---------------------------------------------------------------------------
  892. ITOA        PROC
  893.  
  894.             PUSH    AX                      ; save registers
  895.             PUSH    BX
  896.             PUSH    CX
  897.             PUSH    DX
  898.             PUSH    DI
  899.             PUSHF
  900.             STD                             ; ..and set direction flag
  901.  
  902.             ADD     DI, CX                  ; di -> 1st char past work area
  903.             DEC     DI                      ; di -> last char in work area
  904.             PUSH    BX                      ; save fill character
  905.             MOV     BX, 10                  ; bx = divisor
  906.  
  907. ITOA10:     OR      AX, AX                  ; q. any value to convert?
  908.             JZ      ITOA20                  ; a. no .. exit loop
  909.  
  910.             XOR     DX, DX                  ; dx:ax = value to divide
  911.             IDIV    BX                      ; ax = dividend, dx = remainder
  912.             OR      DL, 30H                 ; dl = ASCII number
  913.             MOV     [DI], DL                ; store character in buffer
  914.             DEC     DI                      ; di -> next output char location
  915.  
  916.             DEC     CX                      ; q. any more room in buffer?
  917.             JNZ     ITOA10                  ; a. yes .. continue loop
  918.  
  919.             POP     BX                      ; restore register
  920.             JMP     ITOA90                  ; ..and exit through common code
  921.  
  922. ITOA20:     POP     AX                      ; al = fill character
  923.  
  924. ITOA30:     STOSB                           ; store fill character
  925.  
  926.             DEC     CX                      ; q. any more room in buffer?
  927.             JNZ     ITOA30                  ; a. yes .. continue loop
  928.  
  929. ITOA90:     POPF                            ; restore flags
  930.             POP     DI                      ; ..and registers
  931.             POP     DX                      ;
  932.             POP     CX                      ;
  933.             POP     BX                      ;
  934.             POP     AX                      ;
  935.             RET                             ; ..and return
  936.  
  937. ITOA        ENDP
  938. ; ---------------------------------------------------------------------------
  939. ;   Uninitialized data areas
  940. ; ---------------------------------------------------------------------------
  941. UDATA       EQU     $                       ; start of unitialized data
  942. PAGENO      EQU     WORD PTR UDATA          ; current page number
  943. CURCOL      EQU     WORD PTR PAGENO+2       ; current column
  944. LINECNT     EQU     WORD PTR CURCOL+2       ; line count
  945. EDRV        EQU     BYTE PTR LINECNT+2      ; current disk
  946. EDIR        EQU     BYTE PTR EDRV+1         ; current directory
  947. FILENAME    EQU     BYTE PTR EDIR+65        ; filename specifed as ARG1
  948. LASTBUFF    EQU     BYTE PTR FILENAME+13    ; last buffer indicator
  949. FHANDLE     EQU     WORD PTR LASTBUFF+1     ; input file handle
  950. BUFFER      EQU     BYTE PTR FHANDLE+2      ; file buffer
  951. BUFLEN      EQU     2048                    ; length of buffer
  952. USEDLEN     EQU     BYTE PTR BUFFER+BUFLEN  ; used length in a logical line
  953. OBUFF       EQU     BYTE PTR USEDLEN+1      ; output buffer - must be last!
  954.  
  955. CSEG        ENDS                            ; end of code segment
  956.             END     START
  957.