home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-386-Vol-2of3.iso / h / hercap10.zip / HERCAP.ASM < prev    next >
Assembly Source File  |  1991-01-13  |  39KB  |  840 lines

  1. ;----------------------------------------------------------------------
  2. ; CAPTURE is a resident utility which copies a Hercules graphics screen
  3. ; to a file. Activate HERCAP by pressing Ctrl-F9 or the hot key
  4. ; specified by /K<number> on the command line. Help by /?.
  5. ; The filename will be SCNxxxxx.TIF. The number part begins with 00000
  6. ; and is incremented by 1 each time CAPTURE is activated.
  7. ; ---> Heavily modified by TapirSoft Gisbert W.Selke, 08 Jan 1991   <---
  8. ; ---> for Hercules graphics screen capture                         <---
  9. ;-----------------------------------------------------------------------
  10.  
  11. ;-----------------------------------------------------------------------
  12. BIOS_SEG        SEGMENT AT 0040H
  13.  
  14.                 ORG     0017H
  15. KB_FLAG         DB      ?               ;BIOS keyboard shift status
  16.  
  17. BIOS_SEG        ENDS
  18.  
  19. ;=======================================================================
  20. CSEG            SEGMENT
  21.                 Assume  CS:CSEG, DS:CSEG, ES:CSEG
  22.  
  23.                 Org     0080h
  24. CmdLine         Label   Byte                    ; pointer to command line
  25.  
  26.                 ORG     0100H                   ; Beginning for .COM programs
  27. START:          JMP     INITIALIZE              ; Initialization code is at end
  28.  
  29. ;-----------------------------------------------------------------------
  30. ; Data needed by this program
  31. ;-----------------------------------------------------------------------
  32.  
  33. NROWS           Equ     348                     ; number of rows on screen
  34. NPIX            Equ     720                     ; number of pixels per row
  35. NBYTES          Equ     NROWS*((NPIX+7)/8)      ; length of screen in bytes
  36.  
  37. DosCall         Equ     21h                     ; DOS interrupt number
  38. PrintChar       Equ     02h                     ; DOS function 'print char'
  39. PrintString     Equ     09h                     ; DOS function 'print string'
  40. SetVec          Equ     2500h                   ; DOS function 'set interrupt vector'
  41. Keep            Equ     3100h                   ; DOS function 'stay resident'
  42. GetVec          Equ     3500h                   ; DOS function 'get interrupt vector'
  43. FreeMem         Equ     49h                     ; DOS function 'free memory'
  44. Exec            Equ     4Bh                     ; DOS function 'exec'
  45. ExitCode        Equ     4Ch                     ; exit with error code
  46.  
  47. ChkCode         Equ     4242h                   ; our special installation check
  48. RemoveCode      Equ     4243h                   ; our special request for removal
  49.  
  50. Tab             Equ     09h                     ; ASCII tab
  51. CR              Equ     0Dh                     ; carriage return
  52. LF              Equ     0Ah                     ; line feed
  53. CtrlZ           Equ     1Ah                     ; end-of-file mark
  54.  
  55. CopyRight       db      CR, 'HERCAP 1.0 (c) 1987/91 Ziff Communications Co'
  56.                 db      '/TapirSoft Gisbert W.Selke$', CtrlZ
  57. FileName        db      80 Dup (0)              ; output path and file name
  58. FileNamePtr     dw      FileName                ; pointer to beginning etc.
  59.  
  60. ScreenSeg       dw      0B000H  ;segment address of Hercules graphics scr pg 0
  61. HotKey          db      43h             ; scan code of F9
  62. ShiftMask       db      00000100b       ; shift mask: any Ctrl key
  63. OldInt09        DD      ?       ;Old hardware keyboard interrupt vector
  64. OldInt13        DD      ?       ;Old BIOS disk I/O interrupt vector
  65. OldInt16        DD      ?       ;Old keyboard input interrupt vector
  66. OldInt21        DD      ?       ;Old DOS function interrupt vector
  67. WriteFile       DB      0       ;If=1, need to write to disk
  68. ACTIVE          DB      0       ;Indicates CAPTURE is in use
  69. DOS_Stat        DB      0       ;Current DOS function indicator
  70. Busy_flags      DB      0       ;Bit masked as follows:
  71.                                 ;  1 - DOS function is active
  72.                                 ;  2 - BIOS disk I/O is active
  73.  
  74. ; TIFF header and basic tags:
  75. TIFF_HEADER     dw      4949h               ; byte order : intel
  76.                 dw      42d                 ; version #
  77.                 dd      8                   ; length of first part of header
  78.                 dw      13d                 ; number of tags to come
  79.                 dw      0FFh, 3, 1, 0, 1, 0 ; subfile, full resolution
  80.                 dw      100h, 3, 1, 0, NPIX, 0 ; image width
  81.                 dw      101h, 3, 1, 0, NROWS, 0; image height
  82.                 dw      102h, 3, 1, 0, 1, 0 ; bits per sample
  83.                 dw      103h, 3, 1, 0, 1, 0 ; no compression
  84.                 dw      106h, 3, 1, 0, 1, 0 ; 0 is code for black
  85.                 dw      10Eh, 2, DescLen, 0, DescPos, 0; where do we come from
  86.                 dw      10Fh, 2, MakeLen, 0, MakePos, 0; vanity
  87.                 dw      111h, 4, 1, 0       ; strip offset
  88.                 dd      HDR_LEN             ; ...
  89.                 dw      115h, 3, 1, 0, 1, 0 ; samples per pixel
  90.                 dw      117h, 4, 1, 0       ; strip byte count
  91.                 dd      NBYTES              ; ...
  92.                 dw      11Ch, 3, 1, 0, 1, 0 ; planar configuration
  93.                 dw      131h, 2, SoftLen, 0, SoftPos, 0; more vanity
  94.                 dw      0                   ; end of tags
  95.  
  96. Desc            db      'Captured Hercules Screen', 0
  97. DescLen         Equ     $ - Desc
  98. DescPos         Equ     Desc - TIFF_Header
  99.  
  100. Make            db      'TapirSoft Gisbert W.Selke', 0
  101. MakeLen         Equ     $ - Make
  102. MakePos         Equ     Make - TIFF_Header
  103.  
  104. SoftWare        db      'HerCap 1.0', 0
  105. SoftLen         Equ     $ - SoftWare
  106. SoftPos         Equ     SoftWare - TIFF_Header
  107.  
  108. HDR_LEN         equ     ($ - TIFF_HEADER)
  109.  
  110. ;-----------------------------------------------------------------------
  111. ; CAPTURE reads the screen and stores it in an internal buffer.
  112. ;-----------------------------------------------------------------------
  113. CAPTURE         PROC    NEAR
  114.                 Assume  ES:CSEG, DS:CSEG
  115.  
  116.                 PUSH    DS
  117.                 PUSH    DS
  118.                 POP     ES
  119.                 MOV     DI,OFFSET BUFFER        ;ES:DI points to the buffer
  120.                 MOV     CX,ScreenSeg
  121.                 MOV     DS,CX
  122.                 XOR     SI,SI                   ;DS:SI points to graphics scr 0
  123.                 MOV     CX, NROWS/4             ;(number of screen rows) Div 4
  124. READ_LOOP1:
  125.                 PUSH    DS
  126.                 PUSH    CX
  127.                 PUSH    SI
  128.                 MOV     AL, 4                   ;rows come in fours
  129. READ_LOOP2:
  130.                 MOV     CX, NPIX/16             ;screen row length in words
  131.                 REP     MOVSW
  132.                 POP     SI
  133.                 PUSH    SI                      ;reset SI
  134.                 MOV     CX, DS                  ;inc DS
  135.                 ADD     CX,200H
  136.                 MOV     DS, CX
  137.                 DEC     AL
  138.                 JNZ     READ_LOOP2
  139.  
  140.                 POP     SI
  141.                 ADD     SI, NPIX/8
  142.                 POP     CX
  143.                 POP     DS
  144.                 LOOP    READ_LOOP1
  145.  
  146.                 POP     DS
  147.                 RET                             ;Then we're finished
  148. CAPTURE         ENDP
  149.  
  150. ;-----------------------------------------------------------------------
  151. ; This copies the buffer contents to a file.  It should only be called
  152. ; when DOS is in a stable and reentrant condition.
  153. ;-----------------------------------------------------------------------
  154. WRITE_TO_FILE   PROC    NEAR
  155.                 Assume  DS:NOTHING, ES:NOTHING
  156.  
  157.                 MOV     WriteFile,0     ;Turn off request flag
  158.                 STI                     ;Get interrupts back on
  159.                 PUSH    AX              ;Must preserve all registers
  160.                 PUSH    BX
  161.                 PUSH    CX
  162.                 PUSH    DX
  163.                 PUSH    BP
  164.                 PUSH    DS
  165.                 PUSH    ES
  166.                 PUSH    CS
  167.                 POP     DS
  168.                 Assume  DS:CSEG         ;DS points to our code segment
  169.                 MOV     AX,3524H        ;Get DOS critical error vector
  170.                 CALL    DOS_FUNCTION    ;Do the DOS function
  171.                 PUSH    BX              ;Save old INT 24 vector on stack
  172.                 PUSH    ES
  173.  
  174. ; Replace the DOS severe error interrupt with our own routine.
  175.  
  176.                 MOV     DX,OFFSET NEWINT24
  177.                 MOV     AX,2524H        ;Setup to change INT 24h vector
  178.                 CALL    DOS_FUNCTION    ;DOS function to change vector
  179.  
  180. ; Try to open the file to determine if it already exists.  If it does,
  181. ; then just close it and increment the filename.
  182.  
  183. OPEN_FILE:      MOV     DX,OFFSET FILENAME ;DS:DX points to filename
  184.                 MOV     AX,3D00H        ;Open file for read access
  185.                 CALL    DOS_FUNCTION    ;Do the DOS function
  186.                 JC      OPEN_ERROR      ;If open error, take jump
  187.                 MOV     BX,AX           ;Need the handle in BX
  188.                 MOV     AH,3EH          ;Close this file
  189.                 CALL    DOS_FUNCTION    ;Do the DOS function
  190.                 CALL    INC_FILENAME    ;Try the next filename
  191.                 JMP     OPEN_FILE
  192. OPEN_ERROR:
  193.                 CMP     AX,2            ;Was it 'file not found' error?
  194.                 JNE     DOS_ERR_EXIT    ;Exit on any other error
  195.  
  196. ; Now create the file, then write buffer contents and close it.
  197.  
  198.                 MOV     DX,OFFSET FILENAME      ;DS:DX points to filename
  199.                 MOV     CX,0020H        ;Attribute for new file
  200.                 MOV     AH,3CH          ;Create file for writing
  201.                 CALL    DOS_FUNCTION    ;Do the DOS function
  202.                 JC      CLOSE_FILE      ;On any error, take jump
  203.  
  204.                 MOV     BX,AX           ;Save handle in BX
  205.                 MOV     DX,OFFSET TIFF_HEADER;Point to TIFFF header data
  206.                 MOV     CX,HDR_LEN      ;Write HDR_LEN bytes
  207.                 MOV     AH,40H          ;DOS 'write to a device' function
  208.                 CALL    DOS_FUNCTION    ;Do the DOS function
  209.  
  210.                 MOV     DX,OFFSET BUFFER;Point to output buffer
  211.                 MOV     CX,NBYTES       ;Write NBYTES bytes
  212.                 MOV     AH,40H          ;DOS 'write to a device' function
  213.                 CALL    DOS_FUNCTION    ;Do the DOS function
  214. CLOSE_FILE:
  215.                 MOV     AH,3EH          ;DOS function to close the file
  216.                 CALL    DOS_FUNCTION    ;Do the DOS function
  217.                 CALL    INC_FILENAME    ;Move to next filename
  218.  
  219. DOS_ERR_EXIT:   POP     DS              ;Get INT 24H vector from stack
  220.                 Assume  DS:NOTHING
  221.                 POP     DX
  222.                 MOV     AX,2524H        ;Restore critical error vector
  223.                 CALL    DOS_FUNCTION    ;Do the DOS function
  224.  
  225.                 POP     ES              ;Finally restore all registers
  226.                 POP     DS
  227.                 POP     BP
  228.                 POP     DX
  229.                 POP     CX
  230.                 POP     BX
  231.                 POP     AX
  232.                 MOV     ACTIVE,0        ;CAPTURE is done now
  233.                 RET                     ;Finished writing to disk
  234.  
  235. WRITE_TO_FILE   ENDP
  236.  
  237. ;-----------------------------------------------------------------------
  238. ; This routine does a dos function by calling the old interrupt vector
  239. ;-----------------------------------------------------------------------
  240.                 Assume  DS:NOTHING, ES:NOTHING
  241. DOS_FUNCTION    PROC    NEAR
  242.  
  243.                 PUSHF                   ;These instructions simulate
  244.                 CLI                     ;an interrupt
  245.                 CALL    CS:OldInt21     ;Do the DOS function
  246.                 STI
  247.                 RET
  248.  
  249. DOS_FUNCTION    ENDP
  250.  
  251. ;-----------------------------------------------------------------------
  252. ; This procedure increments the number part of the filename.
  253. ;-----------------------------------------------------------------------
  254. INC_FILENAME    PROC    NEAR
  255.                 MOV     BX, FileNamePtr      ;Point to last digit
  256. INC_NEXT_CHAR:
  257.                 INC     BYTE PTR [BX]        ;Increment the extension
  258.                 CMP     BYTE PTR [BX],"9"    ;Check for carry
  259.                 JLE     INC_RETURN           ;If none, we're finished
  260.                 MOV     BYTE PTR [BX],"0"    ;Set this digit to zero
  261.                 DEC     BX                   ;Backup to next digit
  262.                 CMP     BX,OFFSET FILENAME+2 ;increment digits only
  263.                 JLE     INC_RETURN
  264.                 JMP     INC_NEXT_CHAR
  265. INC_RETURN:
  266.                 RET
  267. INC_FILENAME    ENDP
  268.  
  269. ;-----------------------------------------------------------------------
  270. ; Interrupt 09 (Keyboard)  Watch for trigger key.  When found, ignore
  271. ; it and execute the CAPTURE routine.
  272. ;-----------------------------------------------------------------------
  273. NEWINT09        PROC    FAR
  274.                 Assume  DS:NOTHING, ES:NOTHING
  275.  
  276.                 STI                     ;Allow other interrupts
  277.                 PUSH    AX              ;Must save processor state
  278.                 IN      AL,60H          ;Get the scan code
  279.                 CMP     AL,HOTKEY       ;Is it the hot key?
  280.                 JE      TRIGGER         ;If yes, check the mask
  281. INT09_EXIT:     POP     AX              ;Restore the processor state
  282.                 JMP     CS:OldInt09     ;Continue with ROM routine
  283. TRIGGER:
  284.                 PUSH    DS              ;Preserve DS register
  285.                 MOV     AX,BIOS_SEG     ;Get BIOS data segment
  286.                 MOV     DS,AX           ;Put it in a segment register
  287.                 Assume  DS:BIOS_SEG
  288.                 MOV     AL,KB_FLAG      ;Shift flags
  289.                 AND     AL,0FH          ; only
  290.                 CMP     AL,ShiftMask    ;Is the ALT key down?
  291.                 POP     DS              ;Restore DS register
  292.                 Assume  DS:NOTHING
  293.                 JNE     INT09_EXIT      ;If ALT not down, ignore it
  294.  
  295. ;Reset the keyboard and 8259 interrupt controller
  296.  
  297.                 IN      AL,61H
  298.                 MOV     AH,AL
  299.                 OR      AL,80H          ;Reset bit for keyboard
  300.                 OUT     61H,AL          ;Reset the keyboard
  301.                 MOV     AL,AH
  302.                 JMP     SHORT $+2       ;A short delay
  303.                 OUT     61H,AL          ;Reenable keyboard
  304.                 CLI
  305.                 MOV     AL,20H
  306.                 OUT     20H,AL          ;Reset interrupt controller
  307.                 STI
  308.  
  309.                 CMP     ACTIVE,0        ;Is CAPTURE already active?
  310.                 JNZ     SHORT_RET       ;If active, then exit
  311.                 MOV     ACTIVE,1        ;It's active now!
  312.  
  313.                 PUSH    BX              ;Must preserve all registers
  314.                 PUSH    CX
  315.                 PUSH    DX
  316.                 PUSH    BP
  317.                 PUSH    DI
  318.                 PUSH    DS
  319.                 PUSH    ES
  320.                 PUSH    CS
  321.                 POP     DS              ;Set DS to CSEG
  322.                 MOV     AX,BIOS_SEG     ;ES points to BIOS data area
  323.                 MOV     ES,AX
  324.                 Assume  DS:CSEG, ES:BIOS_SEG ;Assembler directives
  325.                 CALL    CAPTURE         ;Read the screen contents
  326.                 MOV     WriteFile,1     ;Indicate need to flush buffer
  327.                 POP     ES              ;Restore all registers
  328.                 POP     DS
  329.                 POP     DI
  330.                 POP     BP
  331.                 POP     DX
  332.                 POP     CX
  333.                 POP     BX
  334.                 Assume  DS:NOTHING, ES:NOTHING
  335.                 TEST    Busy_flags,011B ;Is DOS or BIOS disk busy?
  336.                 JNZ     SHORT_RET       ;If yes, then we must wait
  337.                 CALL    WRITE_TO_FILE   ;Otherwise, we'll do it now
  338. SHORT_RET:
  339.                 POP     AX              ;Stack must be restored
  340.                 IRET                    ;Now we're all done
  341.  
  342. NEWINT09        ENDP
  343.  
  344. ;-----------------------------------------------------------------------
  345. ; Interrupt 13H (BIOS diskette I/O) Set the busy flag during diskette I/O
  346. ;-----------------------------------------------------------------------
  347. NEWINT13        PROC    FAR
  348.                 Assume  DS:NOTHING, ES:NOTHING
  349.  
  350.                 PUSHF
  351.                 OR      CS:Busy_flags,010B      ;Set BIOS busy bit
  352.                 POPF
  353.                 PUSHF                           ;This simulates an interrupt
  354.                 CALL    CS:OldInt13             ;Do the BIOS function
  355.                 PUSHF                           ;Save result flags
  356.                 AND     Busy_flags,11111101B    ;Clear BIOS busy bit
  357.                 POPF                            ;Get back result flags
  358.                 STI                             ;Must return with interrupts on
  359.                 RET     2                       ;Return BIOS result flags
  360.  
  361. NEWINT13        ENDP
  362.  
  363. ;-----------------------------------------------------------------------
  364. ; Interrupt 16H (BIOS keyboard interface) Check to see if the buffer
  365. ; needs to be written.
  366. ;-----------------------------------------------------------------------
  367. NEWINT16        PROC    FAR
  368.                 Assume  DS:NOTHING, ES:NOTHING
  369.  
  370.                 Cmp     ax, ChkCode             ; is it 'are you there?' ?
  371.                 Jne     NI16A
  372.                 Xor     ax, ax                  ; if so, tell we are indeed!
  373.                 IRet
  374.  
  375. NI16A:          Cmp     ax, RemoveCode          ; should we remove ourselves?
  376.                 Je      NI16Remove              ; if so, that's ok with us
  377.  
  378.                 CMP     CS:WriteFile,1          ;Anything to write to disk?
  379.                 JE      CHECK_DOS_Stat          ;If yes, see what DOS is doing
  380. BIOS_KB:
  381.                 JMP     CS:OldInt16             ;Just do normal KB routine
  382. CHECK_DOS_Stat:
  383.                 CMP     CS:DOS_Stat,0AH         ;Doing read string?
  384.                 JE      BEGIN_NOW               ;If yes, it's safe to begin
  385.                 CMP     CS:DOS_Stat,08H         ;Doing keyboard input?
  386.                 JNE     BIOS_KB                 ;If yes, it's safe to begin
  387. BEGIN_NOW:
  388.                 CALL    WRITE_TO_FILE           ;Write the buffer to disk
  389.                 OR      CS:Busy_flags,001B      ;Reset DOS busy bit
  390.                 JMP     CS:BIOS_KB              ;Continue with BIOS routine
  391.  
  392. NI16Remove:     Mov     dx, word ptr [cs:OldInt09]; otherwise start removal
  393.                 Mov     ax, word ptr [cs:OldInt09+2]
  394.                 Mov     ds, ax
  395.                 Mov     ax, SetVec+09h          ; Reestablish old INT 09h handler
  396.                 Int     DOSCall
  397.  
  398.                 Mov     dx, word ptr [cs:OldInt13]
  399.                 Mov     ax, word ptr [cs:OldInt13+2]
  400.                 Mov     ds, ax
  401.                 Mov     ax, SetVec+13h          ; Reestablish old INT 13h handler
  402.                 Int     DOSCall
  403.  
  404.                 Mov     dx, word ptr [cs:OldInt16]
  405.                 Mov     ax, word ptr [cs:OldInt16+2]
  406.                 Mov     ds, ax
  407.                 Mov     ax, SetVec+16h          ; Reestablish old INT 16h handler
  408.                 Int     DOSCall
  409.  
  410.                 Mov     dx, word ptr [cs:OldInt21]
  411.                 Mov     ax, word ptr [cs:OldInt21+2]
  412.                 Mov     ds, ax
  413.                 Mov     ax, SetVec+21h          ; Reestablish old INT 16h handler
  414.                 Int     DOSCall
  415.  
  416.                 Mov     ax, cs                  ; Return our segment
  417.                 IRet
  418.  
  419. NEWINT16        ENDP
  420.  
  421. ;-----------------------------------------------------------------------
  422. ; Interrupt 21H (DOS functions) Used to keep track of DOS function calls
  423. ;-----------------------------------------------------------------------
  424. NEWINT21        PROC    FAR
  425.                 Assume  DS:NOTHING, ES:NOTHING
  426.  
  427.                 PUSHF                           ;Save the flags
  428.                 MOV     CS:DOS_Stat,AH          ;Store the function number
  429.                 OR      CS:Busy_flags,001B      ;Set DOS busy bit
  430.  
  431.                 OR      AH,AH                   ;Doing function zero?
  432.                 JZ      JUMP_TO_DOS             ;If yes, take the jump
  433.                 CMP     AH, Exec                ;Doing EXEC function?
  434.                 JE      JUMP_TO_DOS             ;If yes, take the jump
  435.  
  436.                 POPF
  437.                 PUSHF
  438.                 CALL    CS:OldInt21             ;Do the DOS function
  439.  
  440.                 PUSHF                           ;Save the result flags
  441.  
  442.                 AND     CS:Busy_flags,11111110B ;Clear DOS busy bit
  443.                 CMP     CS:WriteFile,1          ;Anything to write to disk?
  444.                 JNE     NO_WRITE                ;If not, just return
  445.  
  446.                 CALL    WRITE_TO_FILE           ;Safe to access disk now
  447. NO_WRITE:
  448.                 POPF                    ;Recover DOS result flags
  449.                 STI                     ;Must return with interrupts on
  450.                 RET     2               ;Return with DOS result flags
  451. JUMP_TO_DOS:
  452.                 POPF
  453.                 JMP     CS:OldInt21
  454. NEWINT21        ENDP
  455.  
  456. ;-----------------------------------------------------------------------
  457. ; Interrupt 24H (critical DOS error).  This interrupt is only in
  458. ; effect during a write screen.  It is required to suppress the
  459. ; 'Abort, Retry, Ignore' message.  All fatal disk errors are ignored.
  460. ;-----------------------------------------------------------------------
  461. NEWINT24        PROC    FAR
  462.                 Assume  DS:NOTHING, ES:NOTHING
  463.                 XOR     AL,AL           ;Tells DOS to ignore the error
  464.                 IRET                    ;That's all we do here
  465.  
  466. NEWINT24        ENDP
  467.  
  468. ;----------------------------------------------------------------------
  469. ;  This area is overwritten by the dynamic buffers.
  470. ;----------------------------------------------------------------------
  471. PC              =       $
  472.  
  473. BUFFER          =       PC
  474. PC              =       PC+NBYTES
  475. LASTBYTE        =       PC
  476.  
  477. ;-----------------------------------------------------------------------
  478. ; Here is the code used to initialize HerCap. It is not kept resident.
  479. ; The buffer is located here and overlays the initialization code.
  480. ;-----------------------------------------------------------------------
  481.                 Assume  CS:CSEG, DS:CSEG, ES:NOTHING
  482.  
  483. INITIALIZE      PROC    NEAR
  484.  
  485.                 MOV     DX,OFFSET CopyRight
  486.                 MOV     AH, PrintString ;DOS display string service
  487.                 INT     DosCall         ;Display title message
  488.  
  489.                 Call    ParseArgs       ; check command line parameters
  490. ; ah has function code:
  491.                 Cmp     ah, 1           ; request for help?
  492.                 Jne     Init2           ; if not, proceed to check
  493.                 Mov     dx, Offset Usage; usage text
  494.                 Mov     al, 1           ; exit code
  495.  
  496. ShowMsg:        Push    ax
  497.                 Mov     ah, PrintString
  498.                 Int     DosCall
  499.                 Pop     ax
  500.                 mov     ah, ExitCode    ; exit with error code set earlier
  501.                 int     DosCall
  502.  
  503. ; Search for a previously installed copy of CAPTURE
  504.  
  505. Init2:          Cmp     ah, 3                   ; request for key help?
  506.                 Jne     Init2A
  507.                 Jmp     ShowKey                 ; if so, do it
  508. Init2A:         Mov     bx, ax
  509.                 Mov     ax, ChkCode             ; now check if we're loaded
  510.                 Int     16h                     ; already loaded <-> ax = 0
  511.  
  512.                 Cmp     bh, 2                   ; request for removal?
  513.                 Jne     Init2B
  514.                 Jmp     Remove                  ; proceed to remove
  515.                                                 ; now we should install;
  516. Init2B:         Or      ax, ax                  ; are we there already?
  517.                 Jne     Init3                   ; if not, proceed normally
  518.  
  519.                 Mov     dx, Offset LoadedMsg    ; tell we're already there
  520.                 Mov     al, 2                   ; error code 2
  521.                 Jmp Short ShowMsg               ; and exit to DOS
  522.  
  523. Init3:          MOV     AX,GetVec+09h   ;Get keyboard break vector
  524.                 INT     DosCall
  525.                 MOV     WORD PTR [OldInt09],  BX  ;Save segment
  526.                 MOV     WORD PTR [OldInt09+2],ES  ;Save offset
  527.                 MOV     DX, OFFSET NEWINT09
  528.                 MOV     AX, SetVec+09h
  529.                 INT     DosCall         ;DOS function to change vector
  530.  
  531.                 MOV     AX,GetVec+13h   ;Get BIOS disk interrupt vector
  532.                 INT     DosCall
  533.                 MOV     WORD PTR [OldInt13],  BX  ;Save the segment
  534.                 MOV     WORD PTR [OldInt13+2],ES  ;Save the offset
  535.                 MOV     DX, OFFSET NEWINT13
  536.                 MOV     AX, SetVec+13h
  537.                 INT     DosCall         ;DOS function to change vector
  538.  
  539.                 MOV     AX,GetVec + 16h ;Get keyboard input vector
  540.                 INT     DosCall
  541.                 MOV     WORD PTR [OldInt16],  BX  ;Save the segment
  542.                 MOV     WORD PTR [OldInt16+2],ES  ;Save the offset
  543.                 MOV     DX, OFFSET NEWINT16
  544.                 MOV     AX, SetVec + 16h
  545.                 INT     DosCall         ;DOS function to change vector
  546.  
  547.                 MOV     AX,GetVec+DosCall;Get DOS function vector
  548.                 INT     DosCall
  549.                 MOV     WORD PTR [OldInt21],  BX
  550.                 MOV     WORD PTR [OldInt21+2],ES
  551.                 MOV     DX, OFFSET NEWINT21
  552.                 MOV     AX, SetVec+DosCall
  553.                 INT     DosCall                 ; DOS function to change vector
  554.  
  555.                 Mov     si, Offset BaseName     ; pointer to file name proper
  556.                 Mov     di, FileNamePtr         ; pointer into buffer
  557.                 Push    ds
  558.                 Pop     es
  559.                 Mov     cx, 12                  ; max 12 chars length
  560.                 Repne   Movsb                   ; copy them!
  561.                 Mov     ax, FileNamePtr         ; make FileNamePtr point to
  562.                 Add     ax, 7                   ; last digit in name
  563.                 Mov     FileNamePtr, ax
  564.  
  565. ;-----------------------------------------------------------------------
  566. ; Deallocate our copy of the environment.
  567. ; Leave code and space for the buffer resident.
  568. ;-----------------------------------------------------------------------
  569.  
  570.                 MOV     AX,DS:[002CH]   ;Get segment of environment
  571.                 MOV     ES,AX           ;Put it into ES
  572.                 MOV     AH,FreeMem      ;Release allocated memory
  573.                 INT     DosCall
  574.                 Mov     dx, Offset InstallMsg; tell we have installed
  575.                 Mov     ah, PrintString
  576.                 Int     DosCall
  577.  
  578.                 MOV     DX,(OFFSET LASTBYTE - OFFSET CSEG + 15)SHR 4
  579.                 MOV     AX,Keep
  580.                 INT     DosCall
  581.  
  582. ; Code for removal of resident part:
  583. Remove:         Or      ax, ax                  ; request for removal
  584.                 Je      Remove1                 ; if we're there, proceed;
  585.                 Mov     dx, Offset NotThereMsg  ; otherwise tell we're not there
  586.                 Mov     al, 3
  587.                 Jmp     ShowMsg
  588.  
  589. Remove1:        Push    ds
  590.                 Mov     ax, RemoveCode          ; prepare removal
  591.                 Int     16h                     ; call our routine
  592.                 Pop     ds                      ; retrieve data segment address
  593.                 Mov     es, ax                  ; memory of routine:
  594.                 Mov     ah, FreeMem             ; free it!
  595.                 Int     DOSCall
  596.                 Mov     dx, Offset RemovedMsg   ; report unloading
  597.                 Xor     al, al
  598.                 Jmp     ShowMsg
  599.  
  600. ; Code for display of hot key:
  601. ShowKey:        Mov     dx, Offset HitKeyMsg    ; Tell we're all set
  602.                 Mov     ah, PrintString
  603.                 Int     DosCall
  604.  
  605.                 MOV     AX,GetVec+09h           ; Get keyboard break vector
  606.                 INT     DosCall
  607.                 MOV     WORD PTR [OldInt09],  BX; Save segment
  608.                 MOV     WORD PTR [OldInt09+2],ES; Save offset
  609.                 MOV     DX, OFFSET DummyInt09   ; point to our wee interceptor
  610.                 MOV     AX, SetVec+09h
  611.                 INT     DosCall                 ; DOS function to change vector
  612.  
  613. GetHotKey:      Xor     ah, ah                  ; Get a proper key
  614.                 Int     16h
  615.  
  616.                 Mov     dx, word ptr [cs:OldInt09] ; point back to normal
  617.                 Mov     ax, word ptr [cs:OldInt09+2]
  618.                 Push    ds
  619.                 Mov     ds, ax
  620.                 Mov     ax, SetVec+09h          ; Reestablish old INT 09h handler
  621.                 Int     DOSCall
  622.                 Pop     ds
  623.  
  624.                 Mov     ah, HotKey              ; recover hot key code
  625.                 Mov     al, ShiftMask           ; ... and shift mask
  626.                 Call    ShowNum                 ; display that number
  627.                 Mov     ax, 4C00h               ; exit with error code 0
  628.                 Int     DosCall
  629.  
  630. INITIALIZE      ENDP
  631.  
  632. ShowNum         Proc    Near
  633. ; displays ax in hex format
  634.                 Push    ax
  635.                 Push    cx
  636.                 Push    dx
  637.                 Mov     cx, 4                   ; 4 hex digits
  638.  
  639. ShowNum1:       Push    ax                      ; push it
  640.                 Push    cx
  641.                 Mov     cl, 4
  642.                 ShR     ax, cl                  ; shift right one nibble
  643.                 Pop     cx
  644.                 Loop    ShowNum1
  645.                                                 ; now 4 nibbles are on stack
  646.                 Mov     cx, 4
  647. ShowNum2:       Pop     dx                      ; recall next nibble
  648.                 And     dl, 0Fh                 ; mask out other nibbles
  649.                 Cmp     dl, 9                   ; is it above 9?
  650.                 Jbe     ShowNum3
  651.                 Add     dl, 'A'-'0'-10          ; convert to letter A..F
  652. ShowNum3:       Add     dl, '0'                 ; convert to digit
  653.                 Mov     ah, PrintChar           ; display it
  654.                 Int     DosCall
  655.                 Loop    ShowNum2
  656.  
  657.                 Pop     dx
  658.                 Pop     cx
  659.                 Pop     ax
  660.                 Ret
  661. ShowNum         EndP
  662.  
  663. ParseArgs       Proc    Near
  664. ; parse command line arguments; return action code in ah:
  665. ; ah=0: install; ah=1: usage; ah=2: remove; ah=3: display hot key
  666. ; also sets path string and/or hot key code
  667.  
  668.                 Push    si
  669.                 Push    di
  670.                 Mov     si, Offset CmdLine + 1  ; point to command line
  671.                 Xor     ah, ah                  ; init cmd marker
  672.  
  673. PANext:         Lodsb                           ; get next char
  674.                 Cmp     al, CR                  ; at end?
  675.                 Je      PADone                  ; if so, finish
  676.                 Cmp     al, ' '                 ; ignore this?
  677.                 Je      PANext
  678.                 Cmp     al, ','                 ; ignore this?
  679.                 Je      PANext
  680.                 Cmp     al, Tab                 ; ignore this?
  681.                 Je      PANext
  682.                 Cmp     al, '/'                 ; switch char?
  683.                 Je      PASwitch                ; skip if so
  684.                 Cmp     al, '-'                 ; switch char?
  685.                 Jne     PAUsage                 ; skip if not
  686.  
  687. PASwitch:       Lodsb                           ; which switch?
  688.  
  689.                 Cmp     al, '0'                 ; request page 0?
  690.                 Jne     PASw1                   ; skip if not
  691.                 Mov     ScreenSeg, 0B000h       ; screen page 0 base address
  692.                 Jmp Short PANext
  693.  
  694. PASw1:          Cmp     al, '1'                 ; request page 1?
  695.                 Jne     PASw2                   ; skip if not
  696.                 Mov     ScreenSeg, 0B800h       ; screen page 1 base address
  697.                 Jmp Short PANext
  698.  
  699. PASw2:          Or      al, 20h                 ; convert to lower case
  700.                 Cmp     al, 'u'                 ; request uninstallation?
  701.                 Jne     PASw3                   ; skip if not
  702.                 Mov     ah, 2                   ; remember to remove
  703.                 Jmp Short PANext
  704.  
  705. PASw3:          Cmp     al, 'k'                 ; hot key spec?
  706.                 Jne     PASw4                   ; skip if not
  707.                 Mov     bh, ah
  708.                 Call    GetNum                  ; returns number in ax
  709.                 Or      ax, ax                  ; hot key help requested?
  710.                 Je      PASw3A                  ; if so, jot it down!
  711.                 Mov     HotKey, ah
  712.                 Mov     ShiftMask, al
  713.                 Mov     ah, bh
  714.                 Jmp Short PANext
  715. PASw3A:         Mov     ah, 3                   ; 'hot key help' request
  716.                 Jmp Short PANext
  717.  
  718. PASw4:          Cmp     al, 'p'                 ; request for outfile path?
  719.                 Je      PASw4A                  ; if so, proceed to store it
  720.  
  721. PAUsage:        Mov     ah, 1                   ; otherwise illegal arg
  722.  
  723. PADone:         Pop     di
  724.                 Pop     si
  725.                 Ret
  726.  
  727. ; get path, store it in appropriate buffer:
  728. PASw4A:         Mov     di, FileNamePtr         ; pointer to path buffer
  729.  
  730. PASw4B:         Lodsb                           ; get next byte
  731.                 Cmp     al, CR                  ; end of cmd line?
  732.                 Je      PASw4C
  733.                 Cmp     al, ' '                 ; end of arg?
  734.                 Je      PASw4C
  735.                 Cmp     al, Tab                 ; end of arg?
  736.                 Je      PASw4C
  737.                 Stosb                           ; else store char in path
  738.                 Jmp Short PASw4B
  739.  
  740. PASw4C:         Dec     si                      ; decrement cmd line ptr
  741.                 Cmp     byte ptr [di-1], '\'    ; does path end in '\'?
  742.                 Je      PASw4D
  743.                 Cmp     byte ptr [di-1], ':'    ; does path end in ':'?
  744.                 Je      PASw4D
  745.  
  746.                 Mov     al, '\'                 ; else force ending '\'
  747.                 Stosb
  748.  
  749. PASw4D:         Mov     FileNamePtr, di         ; update path pointer
  750.                 Jmp     PANext                  ; and scan on
  751.  
  752. ParseArgs       EndP
  753.  
  754. GetNum          Proc    Near
  755. ; reads hex number from current position in command line (ds:si),
  756. ; returns it in ax
  757.                 Push    bx
  758.                 Push    cx
  759.                 Xor     bx, bx                  ; assemble number here
  760.                 Mov     cl, 4                   ; convenient shift factor
  761.  
  762. GetNum1:        Lodsb                           ; get next char
  763.                 Cmp     al, CR                  ; check if end of argument
  764.                 Je      GetNumEnd
  765.                 Cmp     al, ' '                 ; ...
  766.                 Je      GetNumEnd
  767.                 Cmp     al, Tab                 ; ...
  768.                 Je      GetNumEnd
  769.                 Or      al, 20h                 ; make lowercase
  770.                 Sub     al, '0'                 ; try to make it a decimal digit
  771.                 Jc      GetNum1                 ; was too small; ignore
  772.                 Cmp     al, 9
  773.                 Jbe     GetNum2                 ; success!
  774.                 Sub     al, 'a'-'0'+10          ; else, try true hex digit
  775.                 Jc      GetNum1                 ; too small; ignore
  776.                 Cmp     al, 15
  777.                 Ja      GetNum1                 ; too large; ignore
  778.  
  779. GetNum2:        ShL     bx, cl                  ; shift earlier digits
  780.                 Or      bl, al                  ; add in new digit
  781.                 Jmp Short GetNum1
  782.  
  783. GetNumEnd:      Mov     ax, bx                  ; clean up
  784.                 Dec     si                      ; back up pointer
  785.                 Pop     cx
  786.                 Pop     bx
  787.                 Ret
  788.  
  789. GetNum          EndP
  790.  
  791. DummyInt09      PROC    FAR
  792. ; same as above, except we just get a key and store it away safely
  793.                 Assume  DS:NOTHING, ES:NOTHING
  794.  
  795.                 STI                     ;Allow other interrupts
  796.                 PUSH    AX              ;Must save processor state
  797.                 IN      AL,60H          ;Get the scan code
  798.                 Or      al, al
  799.                 Je      DummyI09Exit
  800.                 Mov     HotKey, al      ; store it as hot key
  801.                 PUSH    DS              ;Preserve DS register
  802.                 MOV     AX,BIOS_SEG     ;Get BIOS data segment
  803.                 MOV     DS,AX           ;Put it in a segment register
  804.                 Assume  DS:BIOS_SEG
  805.                 MOV     AL,KB_FLAG      ;Shift flags
  806.                 AND     AL,0FH          ; only
  807.                 Mov     ShiftMask, al   ;stow flags away
  808.                 POP     DS              ;Restore DS register
  809.  
  810. DummyI09Exit:   POP     AX              ;Restore the processor state
  811.                 JMP     CS:OldInt09     ;Continue with ROM routine
  812.  
  813. DummyInt09      EndP
  814.  
  815. BaseName        db      'SCN00000.TIF', 0       ; The first filename
  816.  
  817. Usage           db      CR, LF, CR, LF
  818.                 db      'HERCAP 1.0 resident Hercules graphics screen capture'
  819.                 db      ' to TIFF files', CR, LF, CR, LF
  820.                 db      'Usage: HERCAP [args]     where args may be', CR, LF
  821.                 db      '/?         : this help screen', CR, LF
  822.                 db      '/K<number> : hex code of hot key; default is 4304 for '
  823.                 db      'Ctrl-F9', CR, LF
  824.                 db      '             (use /K? to find codes for keys!)', CR, LF
  825.                 db      '/0 or /1   : for screen page 0 (default) rsp. 1', CR, LF
  826.                 db      '/P<path>   : for screen dumps; default is current '
  827.                 db      'directory', CR, LF
  828.                 db      '/U         : uninstall', CR, LF
  829.                 db      '             no arg installs with default values'
  830.                 db      CR, LF, '$'
  831.  
  832. LoadedMsg       DB      CR, LF, "had already been installed.$"
  833. InstallMsg      DB      CR, LF, "has been installed.$"
  834. RemovedMsg      DB      CR, LF, "has been uninstalled.$"
  835. NotThereMsg     DB      CR, LF, "had not been installed.$"
  836. HitKeyMsg       DB      CR, LF, "Hit the key to check: $"
  837.  
  838. CSEG            ENDS
  839.                 END     START
  840.