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

  1. ;****************************************************************************
  2. ; LPT2FILE captures printer output to a file.  Its syntax is
  3. ;
  4. ;       LPT2FILE LPTn[:]=[[d:][path]filename] [/B=size] [/C]
  5. ;
  6. ; where LPTn specifies the printer output is to be rerouted from (LPT1,
  7. ; LPT2, or LPT3), "filename" specifies the name of the file, and "size"
  8. ; specifies the size of LPT2FILE's internal data buffer (in kilobytes).
  9. ; "Size" defaults to 4k; acceptable values range from 2k to 64k.  Run
  10. ; without command line parameters, LPT2FILE displays which (if any)
  11. ; printer is redirected.  Running it with /C cancels redirection.
  12. ;****************************************************************************
  13.  
  14. code            segment
  15.                 assume  cs:code
  16.                 org     100h
  17. begin:          jmp     init
  18.  
  19. signature       db      0,1,2,"LPT2FILE",2,1,0  ;Program signature
  20. prog_id         db      ?                       ;Multiplex ID number
  21.  
  22. int08h          dd      ?                       ;Interrupt 08H vector
  23. int13h          dd      ?                       ;Interrupt 13H vector
  24. int17h          dd      ?                       ;Interrupt 17H vector
  25. int21h          dd      ?                       ;Interrupt 21H vector
  26. int25h          dd      ?                       ;Interrupt 25H vector
  27. int26h          dd      ?                       ;Interrupt 26H vector
  28. int28h          dd      ?                       ;Interrupt 28H vector
  29. int2Fh          dd      ?                       ;Interrupt 2FH vector
  30.  
  31. errorflag       dd      ?                       ;Critical error flag address
  32. intflags        db      0                       ;Disk interrupt flags
  33. indos           dd      ?                       ;InDOS flag address
  34. bufsize         dw      4096                    ;Internal buffer size
  35. bufhalf         dw      2048                    ;Half buffer size
  36. bufptr          dw      0                       ;Buffer pointer
  37. bufseg          dw      ?                       ;Buffer segment
  38. bytecount       dw      ?                       ;Number of bytes in buffer
  39. counter         db      91                      ;Countdown timer
  40. lptport         db      0FEh,0                  ;Redirected LPT port
  41. filename        db      128 dup (?)             ;File specification
  42.  
  43. ;****************************************************************************
  44. ; TIMER_INT handles interrupt 08H.
  45. ;****************************************************************************
  46.  
  47. timer_int       proc    far
  48.                 pushf                           ;Push FLAGS
  49.                 call    cs:[int08h]             ;Call previous handler
  50.                 cli                             ;Disable interrupts
  51.  
  52.                 cmp     cs:[counter],0          ;Branch if timer has
  53.                 je      timer1                  ;  already expired
  54.                 dec     cs:[counter]            ;Decrement counter
  55.                 jnz     timer_exit              ;Exit if not zero
  56.                 cmp     cs:[bufptr],0           ;Branch if there is data
  57.                 jne     timer1                  ;  in the buffer
  58.                 mov     cs:[counter],91         ;Reset the counter and exit
  59.                 jmp     short timer_exit        ;  if there's not
  60.  
  61. timer1:         push    di                      ;Save ES and DI
  62.                 push    es
  63.                 cmp     cs:[intflags],0         ;Branch if a disk interrupt
  64.                 jne     timer2                  ;  flag is set
  65.                 les     di,cs:[indos]           ;Branch if the InDOS flag
  66.                 cmp     byte ptr es:[di],0      ;  is set
  67.                 jne     timer2
  68.                 les     di,cs:[errorflag]       ;Branch if the critical error
  69.                 cmp     byte ptr es:[di],0      ;  flag is set
  70.                 jne     timer2
  71.                 call    flush                   ;Flush the output buffer
  72. timer2:         pop     es                      ;Restore ES and DI
  73.                 pop     di
  74. timer_exit:     iret
  75. timer_int       endp
  76.  
  77. ;****************************************************************************
  78. ; PRINTER_INT handles interrupt 17H.
  79. ;****************************************************************************
  80.  
  81. printer_int     proc    far
  82.                 cmp     cs:[lptport],0FFh       ;Branch if redirection is
  83.                 jne     prn_check               ;  enabled
  84. prn_bios:       jmp     cs:[int17h]             ;Jump to BIOS handler
  85.  
  86. prn_check:      cmp     dx,word ptr cs:[lptport];Exit if this LPT port is not
  87.                 jne     prn_bios                ;  currently redirected
  88.                 cmp     ah,02h                  ;Exit if function code is
  89.                 ja      prn_bios                ;  greater than 02h
  90.  
  91.                 push    di                      ;Save ES and DI
  92.                 push    es
  93. ;
  94. ; Process interrupt 17H, function 00H (transmit character to printer).
  95. ;
  96.                 or      ah,ah                   ;Branch if AH is not 0
  97.                 jnz     prn1
  98.                 mov     cs:[counter],91         ;Reset timer
  99.                 mov     di,cs:[bufptr]          ;Point DI to buffer
  100.                 cmp     di,cs:[bufsize]         ;Error if the buffer is
  101.                 je      prn_error               ;  full
  102.                 mov     es,cs:[bufseg]          ;Point ES to buffer segment
  103.                 mov     es:[di],al              ;Buffer the character
  104.                 inc     di                      ;Increment the buffer pointer
  105.                 mov     cs:[bufptr],di          ;Store the new pointer
  106.                 cmp     di,cs:[bufhalf]         ;Exit if the buffer is less
  107.                 jb      prn_exit                ;  than half full
  108.  
  109. prn_clear:      cmp     cs:[intflags],0         ;Branch if a disk interrupt
  110.                 jne     prn_exit                ;  flag is set
  111.                 les     di,cs:[indos]           ;Branch if the InDOS flag
  112.                 cmp     byte ptr es:[di],0      ;  is set
  113.                 jne     prn_exit
  114.                 les     di,cs:[errorflag]       ;Branch if the critical error
  115.                 cmp     byte ptr es:[di],0      ;  flag is set
  116.                 jne     prn_exit
  117.                 call    flush                   ;Flush the output buffer
  118.                 jmp     short prn_exit          ;Then exit
  119. ;
  120. ; Process interrupt 17H, function 01H (initialize printer).
  121. ;
  122. prn1:           cmp     ah,01h                  ;Branch if AH is not 1
  123.                 jne     prn2
  124.                 cmp     cs:[bufptr],0           ;Exit if the buffer
  125.                 je      prn_exit                ;  is empty
  126.                 jmp     prn_clear               ;Flush it if it's not
  127. ;
  128. ; Process interrupt 17H, function 02H (get printer status).
  129. ;
  130. prn2:           mov     di,cs:[bufptr]          ;Get buffer pointer
  131.                 cmp     di,cs:[bufsize]         ;Is the buffer full?
  132.                 je      prn_error               ;Error if it is
  133. prn_exit:       mov     ah,90h                  ;Return OK signal in AH
  134.                 pop     es                      ;Restore ES and DI
  135.                 pop     di
  136.                 iret                            ;Return from interrupt
  137.  
  138. prn_error:      mov     ah,08h                  ;Return I/O error in AH
  139.                 pop     es                      ;Restore ES and DI
  140.                 pop     di
  141.                 iret                            ;Return from interrupt
  142. printer_int     endp
  143.  
  144. ;****************************************************************************
  145. ; DOS_INT handles interrupt 21H.
  146. ;****************************************************************************
  147.  
  148. dos_int         proc    near
  149.                 pushf                           ;Save FLAGS
  150.                 cmp     cs:[bufptr],0           ;Exit if the buffer is
  151.                 je      dos_exit                ;  empty
  152.  
  153.                 push    di
  154.                 push    es
  155.                 cmp     cs:[intflags],0         ;Branch if a disk interrupt
  156.                 jne     dos_busy                ;  flag is set
  157.                 les     di,cs:[indos]           ;Branch if the InDOS flag
  158.                 cmp     byte ptr es:[di],0      ;  is set
  159.                 jne     dos_busy
  160.                 les     di,cs:[errorflag]       ;Branch if the critical error
  161.                 cmp     byte ptr es:[di],0      ;  flag is set
  162.                 jne     dos_busy
  163.                 call    flush                   ;Flush the buffer
  164. dos_busy:       pop     es                      ;Restore registers
  165.                 pop     di
  166.  
  167. dos_exit:       popf                            ;Restore FLAGS
  168.                 jmp     cs:[int21h]             ;Exit to original handler
  169. dos_int         endp
  170.  
  171. ;****************************************************************************
  172. ; DOSIDLE_INT handles interrupt 28H.
  173. ;****************************************************************************
  174.  
  175. dosidle_int     proc    far
  176.                 pushf                           ;Push FLAGS
  177.                 call    cs:[int28h]             ;Call previous handler
  178.                 cli                             ;Disable interrupts
  179.  
  180.                 cmp     cs:[bufptr],0           ;Exit if the buffer
  181.                 je      dosidle_exit            ;  is empty
  182.  
  183.                 cmp     cs:[intflags],0         ;Branch if a disk interrupt
  184.                 jne     dosidle_exit            ;  flag is set
  185.                 push    di                      ;Save ES and DI
  186.                 push    es
  187.                 les     di,cs:[errorflag]       ;Check the state of the
  188.                 cmp     byte ptr es:[di],0      ;  critical error flag
  189.                 pop     es                      ;Restore ES and DI
  190.                 pop     di
  191.                 jne     dosidle_exit            ;Exit if the flag is set
  192.                 call    flush                   ;Yes, then flush it
  193. dosidle_exit:   iret                            ;Return from interrupt
  194. dosidle_int     endp
  195.  
  196. ;****************************************************************************
  197. ; DISK_INT handles interrupt 13H.
  198. ;****************************************************************************
  199.  
  200. disk_int        proc    far
  201.                 pushf                           ;Save FLAGS
  202.                 or      cs:[intflags],02h       ;Set disk flag
  203.                 popf                            ;Retrieve FLAGS
  204.                 pushf                           ;Push FLAGS
  205.                 call    cs:[int13h]             ;Call previous handler
  206.                 pushf                           ;Save FLAGS
  207.                 and     cs:[intflags],0FDh      ;Clear disk flag
  208.                 popf                            ;Retrieve FLAGS
  209.                 ret     2                       ;Return with FLAGS intact
  210. disk_int        endp
  211.  
  212. ;****************************************************************************
  213. ; ABS_READ_INT handles interrupt 25H.
  214. ;****************************************************************************
  215.  
  216. abs_read_int    proc    far
  217.                 pushf                           ;Save FLAGS
  218.                 or      cs:[intflags],04h       ;Set disk flag
  219.                 popf                            ;Retrieve FLAGS
  220.                 call    cs:[int25h]             ;Call previous handler
  221.                 pushf                           ;Save FLAGS
  222.                 and     cs:[intflags],0FBh      ;Clear disk flag
  223.                 popf                            ;Retrieve FLAGS
  224.                 ret                             ;Return with FLAGS on stack
  225. abs_read_int    endp
  226.  
  227. ;****************************************************************************
  228. ; ABS_WRITE_INT handles interrupt 26H.
  229. ;****************************************************************************
  230.  
  231. abs_write_int   proc    far
  232.                 pushf                           ;Save FLAGS
  233.                 or      cs:[intflags],08h       ;Set disk flag
  234.                 popf                            ;Retrieve FLAGS
  235.                 call    cs:[int26h]             ;Call previous handler
  236.                 pushf                           ;Save FLAGS
  237.                 and     cs:[intflags],0F7h      ;Clear disk flag
  238.                 popf                            ;Retrieve FLAGS
  239.                 ret                             ;Return with FLAGS on stack
  240. abs_write_int   endp
  241.  
  242. ;****************************************************************************
  243. ; MPLEX_INT handles interrupt 2FH.  If, on entry, AH is set to LPT2FILE's
  244. ; multiplex ID number, MPLEX_INT uses the value in AL as a function code.
  245. ; The functions supported are:
  246. ;
  247. ;    00H    Returns FFH in AL to indicate the program is installed
  248. ;           and returns the address of its signature in ES:DI.
  249. ;
  250. ;    01H    Returns the number of the printer currently redirected
  251. ;           (0, 1, or 2) in AL, or FFH if none are redirected.  If AL
  252. ;           contains 0, 1, or 2, then ES:DI holds the address of the
  253. ;           name of the file output is redirected to.
  254. ;
  255. ;    02H    Accepts the number of the printer to be redirected (0, 1,
  256. ;           or 2) in BL and the address of a file name in DS:SI.  FFH
  257. ;           cancels redirection.  This function causes the output 
  258. ;           buffer to be flushed.
  259. ;****************************************************************************
  260.  
  261. mplex_int       proc    far
  262.                 pushf                           ;Save FLAGS register
  263.                 cmp     ah,cs:[prog_id]         ;Branch if AH holds the
  264.                 je      mplex2                  ;  multiplex ID
  265.                 popf                            ;Restore FLAGS
  266.                 jmp     cs:[int2Fh]             ;Pass the interrupt on
  267. ;
  268. ; Function 00H verifies that the program is installed.
  269. ;               
  270. mplex2:         popf                            ;Restore FLAGS
  271.                 or      al,al                   ;Branch if function code
  272.                 jnz     mplex3                  ;  is other than 00H
  273.                 mov     al,0FFh                 ;Set AL to FFH
  274.                 push    cs                      ;Point ES:DI to the program
  275.                 pop     es                      ;  signature
  276.                 mov     di,offset signature
  277.                 iret                            ;Return from interrupt
  278. ;
  279. ; Function 01H reports the status of redirection.
  280. ;
  281. mplex3:         cmp     al,01h                  ;Branch if function code
  282.                 jne     mplex4                  ;  is other than 01H
  283.                 mov     al,cs:[lptport]         ;Put printer number in AL
  284.                 push    cs                      ;Point ES to this segment
  285.                 pop     es
  286.                 mov     di,offset filename      ;Point DI to file name
  287.                 iret                            ;Return from interrupt
  288. ;
  289. ; Function 02H designates a new printer and file name for redirection.
  290. ;
  291. mplex4:         cmp     cs:[bufptr],0           ;Branch if the output
  292.                 je      mplex5                  ;  buffer is empty
  293.                 call    flush                   ;Flush the buffer
  294. mplex5:         mov     cs:[lptport],bl         ;Store printer number
  295.                 cmp     bl,0FFh                 ;Branch if redirection
  296.                 je      mplex_exit              ;  cancelled
  297.                 push    es                      ;Save ES
  298.                 push    cs                      ;Point ES to this segment
  299.                 pop     es
  300.                 mov     di,offset filename      ;Point DI to file name
  301.                 cld                             ;Clear direction flag
  302. mplex6:         movsb                           ;Copy one character
  303.                 cmp     byte ptr [si-1],0       ;Was it a zero?
  304.                 jne     mplex6                  ;No, then loop back
  305.                 pop     es                      ;Restore ES
  306. mplex_exit:     iret                            ;Return from interrupt
  307. mplex_int       endp
  308.  
  309. ;****************************************************************************
  310. ; FLUSH flushes the output buffer.
  311. ;****************************************************************************
  312.  
  313. flush           proc    near
  314.                 push    ax                      ;Save registers
  315.                 push    bx
  316.                 push    cx
  317.                 push    dx
  318.                 push    ds
  319.  
  320.                 mov     ax,cs                   ;Point DS to the code
  321.                 mov     ds,ax                   ;  segment
  322.                 assume  ds:code
  323.  
  324.                 mov     counter,91              ;Reset the counter
  325.                 mov     ax,bufptr               ;Retrieve buffer pointer
  326.                 mov     bytecount,ax            ;Save it for later
  327.                 mov     bufptr,0                ;Reset the pointer
  328.                 sti                             ;Enable interrupts
  329.  
  330.                 call    openfile                ;Attempt to open the file
  331.                 jc      flush_exit              ;Branch if it failed
  332.  
  333.                 mov     bx,ax                   ;Transfer file handle to BX
  334.  
  335.                 mov     ax,4202h                ;Move the file pointer to
  336.                 sub     cx,cx                   ;  the end of the file
  337.                 mov     dx,cx
  338.                 int     21h
  339.  
  340.                 mov     ah,40h                  ;Copy the output buffer
  341.                 mov     cx,bytecount            ;  to disk
  342.                 sub     dx,dx
  343.                 mov     ds,bufseg
  344.                 assume  ds:nothing
  345.                 int     21h
  346.  
  347.                 mov     ah,3Eh                  ;Close the file
  348.                 int     21h
  349.  
  350. flush_exit:     pop     ds                      ;Restore registers and exit
  351.                 pop     dx
  352.                 pop     cx
  353.                 pop     bx
  354.                 pop     ax
  355.                 ret
  356. flush           endp    
  357.  
  358. ;****************************************************************************
  359. ; OPENFILE attempts to open or create the file output is redirected to.
  360. ; On return, carry is clear if the attempt was successful and the file
  361. ; handle is in AX.  Carry set means the attempt failed.  On entry, DS
  362. ; must point to the code segment.
  363. ;****************************************************************************
  364.  
  365. openfile        proc    near
  366.                 mov     ax,3D01h                ;Attempt to open the file
  367.                 mov     dx,offset filename      ;  for writing
  368.                 int     21h
  369.                 jnc     opened                  ;Branch if it worked
  370.  
  371.                 mov     ax,4301h                ;Attempt to strip all the
  372.                 sub     cx,cx                   ;  attributes off the file
  373.                 mov     dx,offset filename
  374.                 int     21h
  375.  
  376.                 mov     ax,3D01h                ;Then attempt to open it
  377.                 mov     dx,offset filename      ;  for writing again
  378.                 int     21h
  379.                 jnc     opened                  ;Branch if it worked
  380.  
  381.                 mov     ah,3Ch                  ;Attempt to create the
  382.                 sub     cx,cx                   ;  file from scratch
  383.                 mov     dx,offset filename
  384.                 int     21h
  385.                 jnc     opened                  ;Branch if it worked
  386.  
  387.                 stc                             ;Set the carry flag and
  388.                 ret                             ;  exit
  389.  
  390. opened:         clc                             ;Clear the carry flag and
  391.                 ret                             ;  exit
  392. openfile        endp
  393.  
  394. ;****************************************************************************
  395. ; Data that will be discarded when the program becomes memory-resident.
  396. ;****************************************************************************
  397.  
  398. helpmsg         db      "Captures printer output to a file.",13,10,13,10
  399.                 db      "LPT2FILE [LPTn[:]=[[d:][path]filename]] [/B=size] "
  400.                 db      "[/C]",13,10,13,10
  401.                 db      "  LPTn     Specifies the LPT port number.",13,10
  402.                 db      "  /B=size  Specifies the internal buffer size in "
  403.                 db      "kilobytes (default=4k).",13,10
  404.                 db      "  /C       Cancels redirection.",13,10,13,10
  405.                 db      "Running LPT2FILE with no parameters displays the "
  406.                 db      "status of redirection.",13,10,"$"
  407.  
  408. errmsg1         db      "Syntax: LPT2FILE [LPTn[:]=[[d:][path]filename]] "
  409.                 db      "[/B=size] [/C]",13,10,"$"
  410. errmsg2         db      "Requires DOS 3.0 or higher",13,10,"$"
  411. errmsg3         db      "Buffer size is fixed once the program is installed"
  412. crlf            db      13,10,"$"
  413. errmsg4         db      "Invalid buffer size (minimum=2, maximum=64)"
  414.                 db      13,10,"$"
  415. errmsg5         db      "Invalid port number (must be LPT1, LPT2, or LPT3)"
  416.                 db      13,10,"$"
  417. errmsg6         db      "File could not be opened",13,10,"$"
  418. errmsg7         db      "Program could not be installed",13,10,"$"
  419. errmsg8         db      "Not enough memory",13,10,"$"
  420.  
  421. msg1            db      "LPT2FILE 1.0 installed",13,10,"$"
  422. msg2            db      "No printers are currently redirected",13,10,"$"
  423. msg3            db      "LPTn: is currently redirected to $"
  424.  
  425. installed       db      0                       ;0=Not installed
  426. eoladdr         dw      0                       ;End of line address
  427.  
  428. ;****************************************************************************
  429. ; INIT makes the program resident in memory.
  430. ;****************************************************************************
  431.  
  432.                 assume  cs:code,ds:code
  433.  
  434. init            proc    near
  435.                 cld                             ;Clear direction flag
  436.                 mov     si,81h                  ;Point SI to command line
  437.                 call    scanhelp                ;Scan for "/?" switch
  438.                 jnc     checkver                ;Branch if not found
  439.                 mov     ah,09h                  ;Display help text and exit
  440.                 mov     dx,offset helpmsg       ;  with ERRORLEVEL=0
  441.                 int     21h
  442.                 mov     ax,4C00h
  443.                 int     21h
  444. ;
  445. ; Check the DOS version and see if the program is already installed.
  446. ;
  447. checkver:       mov     dx,offset errmsg2       ;Exit if DOS version
  448.                 mov     ah,30h                  ;  is less than 3.0
  449.                 int     21h
  450.                 cmp     al,3
  451.                 jae     checkprog
  452.  
  453. error:          mov     ah,09h                  ;Display error message and
  454.                 int     21h                     ;  exit with ERRORLEVEL=1
  455.                 mov     ax,4C01h
  456.                 int     21h
  457.  
  458. checkprog:      push    es                      ;Save ES
  459.                 call    check_install           ;See if a copy is installed
  460.                 jnc     reset                   ;Branch if not
  461.                 mov     installed,1             ;Set flag if it is
  462.                 mov     prog_id,ah              ;Also store the ID number
  463. reset:          pop     es                      ;Restore ES
  464. ;
  465. ; First capitalize everything on the command line.
  466. ;
  467. parse:          mov     si,81h                  ;Point SI to command line
  468.                 mov     cl,[si-1]               ;CL = Number of characters
  469.                 sub     ch,ch                   ;Convert byte to word in CX
  470.                 jcxz    parse3                  ;Done if CX=0
  471. parse1:         cmp     byte ptr [si],"a"       ;Leave it if less than "a"
  472.                 jb      parse2
  473.                 cmp     byte ptr [si],"z"       ;Leave it if greater than "z"
  474.                 ja      parse2
  475.                 and     byte ptr [si],0DFh      ;Capitalize it
  476. parse2:         inc     si                      ;Advance SI
  477.                 loop    parse1                  ;Loop until done
  478. parse2a:        mov     si,81h                  ;Reset SI
  479. ;
  480. ; Parse the command line for entries.
  481. ;
  482. parse3:         call    findchar                ;Find parameter
  483.                 jnc     parse3a                 ;Branch if not end of line
  484.                 jmp     done                    ;Exit the parsing loop
  485. parse3a:        cmp     byte ptr [si],"/"       ;Branch if the character
  486.                 jne     getportinfo             ;  is not a forward slash
  487. ;
  488. ; Process a /B switch.
  489. ;
  490.                 inc     si                      ;Advance SI
  491.                 lodsb                           ;Get character
  492.                 cmp     al,"B"                  ;Branch if it's not a "B"
  493.                 jne     slashc
  494.                 cmp     installed,0             ;Error if /B entered with the
  495.                 mov     dx,offset errmsg3       ;  program already installed
  496.                 jne     error
  497.                 lodsb                           ;Get the next character
  498.                 cmp     al,"="                  ;Error if not a "="
  499.                 mov     dx,offset errmsg1
  500.                 jne     error
  501.                 call    asc2bin                 ;Get the number after the "="
  502.                 mov     dx,offset errmsg4       ;Exit if error occurred in
  503.                 jc      error                   ;  the conversion
  504.                 cmp     al,2                    ;Error if less than 2
  505.                 jb      error
  506.                 cmp     al,64                   ;Error if greater than 64
  507.                 ja      error
  508.                 sub     ah,ah                   ;Compute the buffer size
  509.                 mov     cl,10                   ;  in bytes by shifting
  510.                 shl     ax,cl                   ;  AX left 10 bits
  511.                 or      ax,ax                   ;Branch if not equal to 0
  512.                 jnz     not_zero
  513.                 dec     ax                      ;Set AX to FFFFH
  514. not_zero:       mov     bufsize,ax              ;Record the buffer size
  515.                 shr     ax,1                    ;Divide buffer size by 2
  516.                 mov     bufhalf,ax              ;Record it
  517.                 jmp     parse3                  ;Return to parsing loop
  518. ;
  519. ; Process a /C switch.
  520. ;
  521. slashc:         mov     dx,offset errmsg1       ;Initialize error pointer
  522.                 cmp     al,"C"                  ;Error if it's not a "C"
  523.                 jne     error1
  524.                 mov     lptport,0FFh            ;Cancel redirection
  525.                 jmp     parse3                  ;Return to input loop
  526. ;
  527. ; Process an LPT port number.
  528. ;
  529. getportinfo:    mov     dx,offset errmsg1       ;Initialize error pointer
  530.                 mov     di,offset errmsg1+8     ;Point DI to "LPT"
  531.                 mov     cx,3                    ;Load CX with count
  532.                 repe    cmpsb                   ;Compare the strings
  533.                 jne     error1                  ;Error if not equal
  534.  
  535.                 mov     dx,offset errmsg5       ;Initialize error pointer
  536.                 lodsb                           ;Get port number
  537.                 cmp     al,"1"                  ;Error if less than "1"
  538.                 jb      error1
  539.                 cmp     al,"3"                  ;Error if greater than "3"
  540.                 ja      error1
  541.                 sub     al,31h                  ;Convert to port number
  542.                 mov     lptport,al              ;Save it
  543.  
  544.                 mov     dx,offset errmsg1       ;Initialize error pointer
  545.                 cmp     byte ptr [si],":"       ;Is next character a colon?
  546.                 jne     gpi3                    ;No, then branch
  547.                 cmp     byte ptr [si],0Dh       ;Error if end of line
  548.                 je      error1
  549.                 inc     si                      ;Skip colon
  550.  
  551. gpi3:           lodsb                           ;Get next character
  552.                 cmp     al,"="                  ;Error if it's not "="
  553.                 jne     error1
  554. ;
  555. ; Process the file name that goes with the port number.
  556. ;
  557.                 push    si                      ;Save string address
  558.                 call    finddelim               ;Find end of file name
  559.                 jc      gpi4                    ;Branch if end of line
  560.                 mov     eoladdr,si              ;Save end of line address
  561. gpi4:           mov     byte ptr [si],0         ;Convert to ASCIIZ string
  562.                 pop     si                      ;Retrieve string address
  563.                 mov     di,offset filename      ;Point DI to file name buffer
  564.                 mov     ah,60h                  ;Turn it into a fully
  565.                 int     21h                     ;  qualified file name
  566.                 jnc     gpi5                    ;Branch if no error
  567.  
  568. error2:         mov     dx,offset errmsg6       ;Exit on error
  569. error1:         jmp     error
  570.  
  571. gpi5:           call    openfile                ;Attempt to open the file
  572.                 jc      error2
  573.  
  574.                 mov     bx,ax                   ;Close the file
  575.                 mov     ah,3Eh
  576.                 int     21h
  577.  
  578.                 cmp     eoladdr,0               ;Reached end of line?
  579.                 je      done                    ;Yes, then quit parsing
  580.                 mov     si,eoladdr              ;Point SI to end of file name
  581.                 inc     si                      ;Advance past the zero byte
  582.                 jmp     parse3                  ;Loop back for more
  583. ;
  584. ; Come here when parsing is done.
  585. ;
  586. done:           cmp     installed,0             ;Branch if the program is
  587.                 jne     done1                   ;  already installed
  588.                 cmp     lptport,0FEh            ;Port number equal to FEH?
  589.                 jne     install                 ;No, then go install
  590.                 inc     lptport                 ;Set port number to FFH
  591.                 jmp     short install           ;Go install
  592.  
  593. done1:          cmp     lptport,0FEh            ;Port number equal to FEH?
  594.                 je      done2                   ;Yes, then we're done
  595.                 mov     ah,prog_id              ;Send new printer number
  596.                 mov     al,02h                  ;  and file name to an
  597.                 mov     bl,lptport              ;  installed copy of
  598.                 mov     si,offset filename      ;  the program
  599.                 int     2Fh
  600.  
  601. done2:          call    showstatus              ;Show redirection status
  602.                 mov     ax,4C00h                ;Exit with ERRORLEVEL=0
  603.                 int     21h
  604. ;
  605. ; Install the program.
  606. ;
  607. install:        call    mplex_id                ;Find a multiplex ID number
  608.                 mov     dx,offset errmsg7       ;Error if none available
  609.                 jc      error1
  610.                 mov     prog_id,ah              ;Save the ID number
  611.  
  612.                 mov     ah,34h                  ;Get and save the address of
  613.                 int     21h                     ;  the InDOS flag
  614.                 mov     word ptr indos,bx
  615.                 mov     word ptr indos[2],es
  616.  
  617.                 push    ds                      ;Save DS
  618.                 mov     ax,5D06h                ;Get and save the address of
  619.                 int     21h                     ;  the critical error flag
  620.                 mov     word ptr cs:[errorflag],si
  621.                 mov     word ptr cs:[errorflag+2],ds
  622.                 pop     ds                      ;Restore DS
  623.                 mov     dx,offset errmsg7       ;Error if function returned
  624.                 jc      error1                  ;  with carry set
  625.  
  626.                 mov     ax,3508h                ;Hook interrupt 08H
  627.                 int     21h
  628.                 mov     word ptr int08h,bx
  629.                 mov     word ptr int08h[2],es
  630.                 mov     ax,2508h
  631.                 mov     dx,offset timer_int
  632.                 int     21h
  633.  
  634.                 mov     ax,3513h                ;Hook interrupt 13H
  635.                 int     21h
  636.                 mov     word ptr int13h,bx
  637.                 mov     word ptr int13h[2],es
  638.                 mov     ax,2513h
  639.                 mov     dx,offset disk_int
  640.                 int     21h
  641.  
  642.                 mov     ax,3517h                ;Hook interrupt 17H
  643.                 int     21h
  644.                 mov     word ptr int17h,bx
  645.                 mov     word ptr int17h[2],es
  646.                 mov     ax,2517h
  647.                 mov     dx,offset printer_int
  648.                 int     21h
  649.  
  650.                 mov     ax,3521h                ;Hook interrupt 21H
  651.                 int     21h
  652.                 mov     word ptr int21h,bx
  653.                 mov     word ptr int21h[2],es
  654.                 mov     ax,2521h
  655.                 mov     dx,offset dos_int
  656.                 int     21h
  657.  
  658.                 mov     ax,3525h                ;Hook interrupt 25H
  659.                 int     21h
  660.                 mov     word ptr int25h,bx
  661.                 mov     word ptr int25h[2],es
  662.                 mov     ax,2525h
  663.                 mov     dx,offset abs_read_int
  664.                 int     21h
  665.  
  666.                 mov     ax,3526h                ;Hook interrupt 26H
  667.                 int     21h
  668.                 mov     word ptr int26h,bx
  669.                 mov     word ptr int26h[2],es
  670.                 mov     ax,2526h
  671.                 mov     dx,offset abs_write_int
  672.                 int     21h
  673.  
  674.                 mov     ax,3528h                ;Hook interrupt 28H
  675.                 int     21h
  676.                 mov     word ptr int28h,bx
  677.                 mov     word ptr int28h[2],es
  678.                 mov     ax,2528h
  679.                 mov     dx,offset dosidle_int
  680.                 int     21h
  681.  
  682.                 mov     ax,352Fh                ;Hook interrupt 2FH
  683.                 int     21h
  684.                 mov     word ptr int2Fh,bx
  685.                 mov     word ptr int2Fh[2],es
  686.                 mov     ax,252Fh
  687.                 mov     dx,offset mplex_int
  688.                 int     21h
  689.  
  690.                 mov     ah,49h                  ;Get the segment address of
  691.                 mov     es,ds:[2Ch]             ;  the environment block
  692.                 int     21h                     ;  and free the segment
  693.  
  694.                 mov     ah,4Ah                  ;Shrink the memory block
  695.                 mov     bx,(offset helpmsg - offset code + 15) shr 4
  696.                 mov     cx,cs                   ;  the program is
  697.                 mov     es,cx                   ;  loaded in
  698.                 int     21h
  699.  
  700.                 mov     ah,48h                  ;Request a new block of
  701.                 mov     bx,bufsize              ;  memory for the data
  702.                 mov     cl,4                    ;  buffer
  703.                 shr     bx,cl
  704.                 inc     bx
  705.                 int     21h
  706.                 mov     dx,offset errmsg8       ;Error if there's not
  707.                 jnc     no_error                ;  enough memory
  708.                 jmp     error
  709. no_error:       mov     bufseg,ax               ;Save the segment address
  710.  
  711.                 mov     ah,09h                  ;Display message verifying
  712.                 mov     dx,offset msg1          ;  the installation
  713.                 int     21h
  714.                 call    showstatus              ;Show redirection status
  715.  
  716.                 mov     ax,3100h                ;Terminate with function 31H
  717.                 mov     dx,(offset helpmsg - offset code + 15)
  718.                 int     21h
  719. init            endp
  720.  
  721. ;****************************************************************************
  722. ; FINDCHAR advances SI to the next non-space or non-comma character.
  723. ; On return, carry set indicates EOL was encountered.
  724. ;****************************************************************************
  725.  
  726. findchar        proc    near
  727.                 lodsb                           ;Get the next character
  728.                 cmp     al,20h                  ;Loop if space
  729.                 je      findchar
  730.                 cmp     al,2Ch                  ;Loop if comma
  731.                 je      findchar
  732.                 dec     si                      ;Point SI to the character
  733.                 cmp     al,0Dh                  ;Exit with carry set if end
  734.                 je      eol                     ;  of line is reached
  735.  
  736.                 clc                             ;Clear carry and exit
  737.                 ret
  738.  
  739. eol:            stc                             ;Set carry and exit
  740.                 ret
  741. findchar        endp
  742.  
  743. ;****************************************************************************
  744. ; FINDDELIM advances SI to the next space or comma character.  On return,
  745. ; carry set indicates EOL was encountered.
  746. ;****************************************************************************
  747.  
  748. finddelim       proc    near
  749.                 lodsb                           ;Get the next character
  750.                 cmp     al,20h                  ;Exit if space
  751.                 je      fd_exit
  752.                 cmp     al,2Ch                  ;Exit if comma
  753.                 je      fd_exit
  754.                 cmp     al,0Dh                  ;Loop back for more if end
  755.                 jne     finddelim               ;  of line isn't reached
  756.  
  757.                 dec     si                      ;Set carry and exit
  758.                 stc
  759.                 ret
  760.  
  761. fd_exit:        dec     si                      ;Clear carry and exit
  762.                 clc
  763.                 ret
  764. finddelim       endp
  765.  
  766. ;****************************************************************************
  767. ; SCANHELP scans the command line for a /? switch.  If found, carry returns
  768. ; set and SI contains its offset.  If not found, carry returns clear.
  769. ;****************************************************************************
  770.  
  771. scanhelp        proc    near
  772.                 push    si                      ;Save SI
  773. scanloop:       lodsb                           ;Get a character
  774.                 cmp     al,0Dh                  ;Exit if end of line
  775.                 je      scan_exit
  776.                 cmp     al,"?"                  ;Loop if not "?"
  777.                 jne     scanloop
  778.                 cmp     byte ptr [si-2],"/"     ;Loop if not "/"
  779.                 jne     scanloop
  780.  
  781.                 add     sp,2                    ;Clear the stack
  782.                 sub     si,2                    ;Adjust SI
  783.                 stc                             ;Set carry and exit
  784.                 ret
  785.  
  786. scan_exit:      pop     si                      ;Restore SI
  787.                 clc                             ;Clear carry and exit
  788.                 ret
  789. scanhelp        endp
  790.  
  791. ;****************************************************************************
  792. ; CHECK_INSTALL returns carry set if the program is already installed,
  793. ; carry clear if it's not.  If carry returns set, AH holds the program's
  794. ; multiplex ID number.
  795. ;****************************************************************************
  796.  
  797. check_install   proc    near
  798.                 mov     ax,8000h                ;Initialize AH and AL
  799.                 mov     cx,80h                  ;Initialize count
  800.  
  801. chinst1:        push    ax                      ;Save AX and CX
  802.                 push    cx
  803.                 sub     di,di                   ;Set ES and DI to 0
  804.                 mov     es,di
  805.                 int     2Fh                     ;Interrupt 2Fh
  806.                 cmp     al,0FFh                 ;Nothing here if AL isn't
  807.                 jne     chinst2                 ;  equal to FFH
  808.  
  809.                 mov     si,offset signature     ;See if program signature
  810.                 mov     cx,14                   ;  appears at the address
  811.                 repe    cmpsb                   ;  returned in ES:DI
  812.                 jne     chinst2                 ;Branch if it does not
  813.  
  814.                 pop     cx                      ;Clear the stack and exit
  815.                 pop     ax                      ;  with carry set
  816.                 stc
  817.                 ret
  818.  
  819. chinst2:        pop     cx                      ;Retrieve AX and CX
  820.                 pop     ax
  821.                 inc     ah                      ;Next multiplex ID
  822.                 loop    chinst1                 ;Loop until done
  823.  
  824.                 clc                             ;Exit with carry clear
  825.                 ret
  826. check_install   endp
  827.  
  828. ;****************************************************************************
  829. ; MPLEX_ID searches for an unused multiplex ID number.  If one is found,
  830. ; it is returned in AH with carry clear.  Carry set means no multiplex
  831. ; ID numbers are currently available.
  832. ;****************************************************************************
  833.  
  834. mplex_id        proc    near
  835.                 mov     ax,8000h                ;Initialize AH and AL
  836.                 mov     cx,80h                  ;Initialize count
  837.  
  838. mxid1:          push    ax                      ;Save AX and CX
  839.                 push    cx
  840.                 int     2Fh                     ;Interrupt 2Fh
  841.                 or      al,al                   ;Branch if AL=0
  842.                 jz      mxid2
  843.                 pop     cx                      ;Retrieve AX and CX
  844.                 pop     ax
  845.                 inc     ah                      ;Increment ID number
  846.                 loop    mxid1                   ;Loop until done
  847.  
  848.                 stc                             ;Exit with carry set
  849.                 ret
  850.  
  851. mxid2:          pop     cx                      ;Clear the stack and exit
  852.                 pop     ax                      ;  with carry clear
  853.                 clc
  854.                 ret
  855. mplex_id        endp
  856.  
  857. ;****************************************************************************
  858. ; ASC2BIN converts a decimal number entered in ASCII form into a binary
  859. ; value in AL.  Carry set on return indicates that an error occurred in
  860. ; the conversion.
  861. ;****************************************************************************
  862.  
  863. asc2bin         proc    near
  864.                 sub     ax,ax                   ;Initialize registers
  865.                 sub     bh,bh
  866.                 mov     dl,10
  867.  
  868. a2b_loop:       mov     bl,[si]                 ;Get a character
  869.                 inc     si
  870.                 cmp     bl,20h                  ;Exit if space
  871.                 je      a2b_exit
  872.                 cmp     bl,2Ch                  ;Exit if comma
  873.                 je      a2b_exit
  874.                 cmp     bl,0Dh                  ;Exit if carriage return
  875.                 je      a2b_exit
  876.  
  877.                 cmp     bl,"0"                  ;Error if character is not
  878.                 jb      a2b_error               ;  a number
  879.                 cmp     bl,"9"
  880.                 ja      a2b_error
  881.  
  882.                 mul     dl                      ;Multiply the value in AL by
  883.                 jc      a2b_error               ;  10 and exit on overflow
  884.                 sub     bl,30h                  ;ASCII => binary
  885.                 add     ax,bx                   ;Add latest value to AX
  886.                 cmp     ax,255                  ;Error if sum > 255
  887.                 jna     a2b_loop                ;Loop back for more
  888.  
  889. a2b_error:      dec     si                      ;Set carry and exit
  890.                 stc
  891.                 ret
  892.  
  893. a2b_exit:       dec     si                      ;Clear carry and exit
  894.                 clc
  895.                 ret
  896. asc2bin         endp
  897.  
  898. ;****************************************************************************
  899. ; SHOWSTATUS displays the current status of printer redirection.
  900. ;****************************************************************************
  901.  
  902. showstatus      proc    near
  903.                 cmp     installed,0             ;See if program is installed
  904.                 je      show1                   ;Branch if not
  905.  
  906.                 mov     ah,prog_id              ;Use the multiplex interrupt
  907.                 mov     al,01h                  ;  (function 01H) to find out
  908.                 int     2Fh                     ;  what printer (if any) is
  909.                 jmp     short show2             ;  redirected
  910.  
  911. show1:          mov     al,lptport              ;Get printer number
  912.                 mov     bx,cs                   ;Point to ES to this segment
  913.                 mov     es,bx
  914.                 mov     di,offset filename      ;Point DI to file name
  915.  
  916. show2:          cmp     al,0FFh                 ;Branch if a printer is
  917.                 jne     show3                   ;  currently redirected
  918.                 mov     ah,09h                  ;Display "No printers
  919.                 mov     dx,offset msg2          ;  redirected" message
  920.                 int     21h                     ;  and exit
  921.                 ret
  922.  
  923. show3:          add     al,31h                  ;Convert printer number to
  924.                 mov     msg3[3],al              ;  ASCII and store it
  925.                 mov     dx,offset msg3          ;Display printer name
  926.                 mov     ah,09h
  927.                 int     21h
  928.                 call    dos_out                 ;Display file name too
  929.                 mov     ah,09h                  ;End the line
  930.                 mov     dx,offset crlf
  931.                 int     21h
  932.                 ret
  933. showstatus      endp
  934.  
  935. ;****************************************************************************
  936. ; DOS_OUT displays the ASCIIZ string pointed to by ES:DI.
  937. ;****************************************************************************
  938.  
  939. dos_out         proc    near
  940.                 mov     dl,es:[di]              ;Get a character
  941.                 or      dl,dl                   ;Exit if it's zero
  942.                 jz      out_exit
  943.                 mov     ah,02h                  ;Output it using DOS
  944.                 int     21h                     ;  function 02H
  945.                 inc     di                      ;Advance DI to next one
  946.                 jmp     dos_out                 ;Loop until done
  947. out_exit:       ret
  948. dos_out         endp
  949.  
  950. code            ends
  951.                 end     begin
  952.