home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS - Coast to Coast / simteldosarchivecoasttocoast.iso / pcmag / vol7n01.zip / CAPTURE.ASM next >
Assembly Source File  |  1987-10-30  |  22KB  |  473 lines

  1. ;----------------------------------------------------------------------
  2. ; CAPTURE is a resident utility which copies an 80x25 screen buffer
  3. ; to a file.  Activate CAPTURE by pressing ALT-C or any other hot
  4. ; key combination defined by the symbols HOTKEY and SHIFT_MASK.
  5. ; The filename will be SCREEN.n. The extension begins with .000 and
  6. ; is incremented by one each time CAPTURE is activated.
  7. ;-----------------------------------------------------------------------
  8. ; BIOS_SEG is located in the ROM-BIOS data area
  9. ;-----------------------------------------------------------------------
  10. BIOS_SEG        SEGMENT AT 0040H
  11.  
  12.                 ORG     0017H
  13. KB_FLAG         DB      ?               ;BIOS keyboard shift status
  14.                 ORG     004AH
  15. CRT_COLS        DB      ?               ;Current number of screen columns
  16.                 ORG     0050H
  17. CURSOR_POSN     DW      8 DUP(?)        ;Current cursor location
  18.                 ORG     0062H
  19. ACTIVE_PAGE     DB      ?               ;Active page for CGA and EGA
  20.  
  21. BIOS_SEG        ENDS
  22.  
  23. ;=======================================================================
  24. CSEG            SEGMENT
  25.                 ASSUME  CS:CSEG, DS:CSEG, ES:CSEG
  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. HOTKEY          EQU     2EH             ;Scan code for "C" key
  33. SHIFT_MASK      EQU     00001000B       ;Mask for ALT key held down
  34.  
  35. COPYRIGHT       DB      "CAPTURE 1.0 (c) 1987 Ziff Communications Co"
  36.                 DB      13,10,"Hotkey is ALT-C$",1Ah
  37. PROGRAMMER      DB      "Tom Kihlken"
  38. INSTALLED_MSG   DB      13,10,"Already Installed$"
  39. FILENAME        DB      "SCREEN.000",0  ;The first filename
  40. OLDINT09        DD      ?       ;Old hardware keyboard interrupt vector
  41. OLDINT13        DD      ?       ;Old BIOS disk IO interrupt vector
  42. OLDINT16        DD      ?       ;Old keyboard input interrupt vector
  43. OLDINT21        DD      ?       ;Old DOS function interrupt vector
  44. WRIT_FILE       DB      0       ;If=1, need to write to disk
  45. ACTIVE          DB      0       ;Indicated CAPTURE is in use
  46. DOS_STAT        DB      0       ;Current DOS function indicator
  47. BUSY_FLAGS      DB      0       ;Bit masked as follows:
  48.                                 ;  1 - DOS function is active
  49.                                 ;  2 - BIOS disk IO is active
  50.  
  51. ;-----------------------------------------------------------------------
  52. ; CAPTURE reads the screen and stores it in an internal buffer.
  53. ;-----------------------------------------------------------------------
  54. CAPTURE         PROC    NEAR
  55.                 ASSUME  DS:CSEG, ES:BIOS_SEG
  56.  
  57.                 CALL    GET_CURS_ADDR           ;Cursor addr for this page
  58.                 PUSH    ES:[BX]                 ;Save the cursor location
  59.                 MOV     DI,OFFSET BUFFER        ;DS:DI points to the buffer
  60.                 XOR     DX,DX                   ;Start at row 0, column 0
  61. READ_LOOP:
  62.                 CMP     DL,CRT_COLS     ;Past right edge of screen?
  63.                 JL      NOT_PAST_EDGE   ;If screen is less than 80
  64.                 MOV     AX,0720H        ;columns, then pad with a blank
  65.                 JMP     SHORT BUFF_CHAR
  66. NOT_PAST_EDGE:
  67.                 CALL    GET_CURS_ADDR   ;Get address of BIOS cursor
  68.                 MOV     ES:[BX],DX      ;Tell BIOS where the cursor is
  69.                 MOV     BH,ACTIVE_PAGE  ;Get active page from BIOS data
  70.                 MOV     AH,8            ;BIOS function to read character
  71.                 INT     10H             ;Read the character/attribute
  72. BUFF_CHAR:
  73.                 MOV     [DI],AX         ;Put the character in buffer
  74.                 INC     DI              ;Increment the pointer twice
  75.                 INC     DI              ;Since we stored a word
  76.  
  77.                 INC     DL              ;Do the next char in same row
  78.                 CMP     DL,80           ;At the right border yet?
  79.                 JL      READ_LOOP       ;Do 80 characters in this row
  80.                 INC     DH              ;Move to next row
  81.                 XOR     DL,DL           ;Back to left edge (Column 0)
  82.                 CMP     DH,25           ;Done all 25 rows yet?
  83.                 JL      READ_LOOP       ;Loop until whole screen is read
  84.                 CALL    GET_CURS_ADDR   ;Cursor address for this page
  85.                 POP     ES:[BX]         ;Recover the cursor position
  86.                 RET                     ;Then were finished
  87. CAPTURE         ENDP
  88.  
  89. ;-----------------------------------------------------------------------
  90. ; This procedure obtains the address of the cursor position for this page
  91. ;-----------------------------------------------------------------------
  92. GET_CURS_ADDR   PROC    NEAR
  93.                 ASSUME  DS:CSEG, ES:BIOS_SEG
  94.  
  95.                 MOV     BL,ACTIVE_PAGE  ;Get the current page number
  96.                 XOR     BH,BH           ;Convert to a word offset
  97.                 SHL     BX,1            ;Times two for a word
  98.                 ADD     BX,OFFSET CURSOR_POSN ;Add base cursor address
  99.                 RET
  100.  
  101. GET_CURS_ADDR   ENDP
  102.  
  103. ;-----------------------------------------------------------------------
  104. ; This copies the buffer contents to a file.  It should only be called
  105. ; when DOS is in a stable and reentrant condition.
  106. ;-----------------------------------------------------------------------
  107. WRITE_TO_FILE   PROC    NEAR
  108.                 ASSUME  DS:NOTHING, ES:NOTHING
  109.  
  110.                 MOV     WRIT_FILE,0     ;Turn off request flag
  111.                 STI                     ;Get interrupts back on
  112.                 PUSH    AX              ;Must preserve all registers
  113.                 PUSH    BX
  114.                 PUSH    CX
  115.                 PUSH    DX
  116.                 PUSH    BP
  117.                 PUSH    DS
  118.                 PUSH    ES
  119.                 PUSH    CS
  120.                 POP     DS
  121.                 ASSUME  DS:CSEG         ;DS points to out code segment
  122.                 MOV     AX,3524H        ;Get DOS critical error vector
  123.                 CALL    DOS_FUNCTION    ;Do the DOS function
  124.                 PUSH    BX              ;Save old INT 24 vector on stack
  125.                 PUSH    ES
  126.  
  127. ; Replace the DOS severe error interrupt with out own routine.
  128.  
  129.                 MOV     DX,OFFSET NEWINT24
  130.                 MOV     AX,2524H        ;Setup to change INT 24h vector
  131.                 CALL    DOS_FUNCTION    ;DOS function to change vector
  132.  
  133. ; Try to open the file to determine if it already exists.  If it does,
  134. ; then just close it and increment the filename.
  135.  
  136. OPEN_FILE:      MOV     DX,OFFSET FILENAME      ;DS:DX points to filename
  137.                 MOV     AX,3D00H        ;Opin file for read access
  138.                 CALL    DOS_FUNCTION    ;Do the DOS function
  139.                 JC      OPEN_ERROR      ;If open error, take jump
  140.                 MOV     BX,AX           ;Need the handle in BX
  141.                 MOV     AH,3EH          ;Close this file
  142.                 CALL    DOS_FUNCTION    ;Do the DOS function
  143.                 CALL    INC_FILENAME    ;Try the next filename
  144.                 JMP     OPEN_FILE
  145. OPEN_ERROR:
  146.                 CMP     AX,2            ;Was it file not found error?
  147.                 JNE     DOS_ERR_EXIT    ;Exit on any other error
  148.  
  149. ; Now create the file, then write buffer contents and close it.
  150.  
  151.                 MOV     DX,OFFSET FILENAME      ;DS:DX points to filename
  152.                 MOV     CX,0020H        ;Attribute for new file
  153.                 MOV     AH,3CH          ;Create file for writing
  154.                 CALL    DOS_FUNCTION    ;Do the DOS function
  155.                 JC      CLOSE_FILE      ;On any error, take jump
  156.  
  157.                 MOV     BX,AX           ;Save handle in BX
  158.                 MOV     DX,OFFSET BUFFER        ;Point to output buffer
  159.                 MOV     CX,4000         ;Write 4000 bytes
  160.                 MOV     AH,40H          ;DOS write to a device function
  161.                 CALL    DOS_FUNCTION    ;Do the DOS function
  162. CLOSE_FILE:
  163.                 MOV     AH,3EH          ;DOS function to close the file
  164.                 CALL    DOS_FUNCTION    ;Do the DOS function
  165.                 CALL    INC_FILENAME    ;Move to next filename
  166.  
  167. DOS_ERR_EXIT:   POP     DS              ;Get INT 24H vector from stack
  168.                 ASSUME  DS:NOTHING
  169.                 POP     DX
  170.                 MOV     AX,2524H        ;Restore critical error vector
  171.                 CALL    DOS_FUNCTION    ;Do the DOS function
  172.  
  173.                 POP     ES              ;Finally restore all registers
  174.                 POP     DS
  175.                 POP     BP
  176.                 POP     DX
  177.                 POP     CX
  178.                 POP     BX
  179.                 POP     AX
  180.                 MOV     ACTIVE,0        ;CAPTURE is done now
  181.                 RET                     ;Finished writing to disk
  182.  
  183. WRITE_TO_FILE   ENDP
  184.  
  185. ;-----------------------------------------------------------------------
  186. ; This routine does a dos function by calling the old interrupt vector
  187. ;-----------------------------------------------------------------------
  188.                 ASSUME  DS:NOTHING, ES:NOTHING
  189. DOS_FUNCTION    PROC    NEAR
  190.  
  191.                 PUSHF                   ;These instructions simulate
  192.                 CLI                     ;an interrupt
  193.                 CALL    CS:OLDINT21     ;Do the DOS function
  194.                 STI
  195.                 RET
  196.  
  197. DOS_FUNCTION    ENDP
  198.  
  199. ;-----------------------------------------------------------------------
  200. ; This procedure increments the extension for the filename.
  201. ;-----------------------------------------------------------------------
  202. INC_FILENAME    PROC    NEAR
  203.                 MOV     BX,OFFSET FILENAME+9 ;Point to last letter
  204. INC_NEXT_CHAR:
  205.                 INC     BYTE PTR [BX]        ;Increment the extension
  206.                 CMP     BYTE PTR [BX],"9"    ;Check for carry
  207.                 JLE     INC_RETURN           ;If none, were finished
  208.                 MOV     BYTE PTR [BX],"0"    ;Set this digit to zero
  209.                 DEC     BX                   ;Backup to next digit
  210.                 CMP     BX,OFFSET FILENAME+6 ;Dont increment the dot
  211.                 JLE     INC_RETURN
  212.                 JMP     INC_NEXT_CHAR
  213. INC_RETURN:
  214.                 RET
  215. INC_FILENAME    ENDP
  216.  
  217. ;-----------------------------------------------------------------------
  218. ; Interrupt 09 (Keyboard)  Watch for trigger key.  When found, ignore
  219. ; it and execute the CAPTURE routine.
  220. ;-----------------------------------------------------------------------
  221. NEWINT09        PROC    FAR
  222.                 ASSUME  DS:NOTHING, ES:NOTHING
  223.  
  224.                 STI                     ;Allow other interrupts
  225.                 PUSH    AX              ;Must save processor state
  226.                 IN      AL,60H          ;Get the scan code
  227.                 CMP     AL,HOTKEY       ;Is it the hot key?
  228.                 JE      TRIGGER         ;If yes, check the mask
  229. INT09_EXIT:     POP     AX              ;Restore the processor state
  230.                 JMP     CS:OLDINT09     ;Continue with ROM routine
  231. TRIGGER:
  232.                 PUSH    DS              ;Preserve DS register
  233.                 MOV     AX,BIOS_SEG     ;Get BIOS data segment
  234.                 MOV     DS,AX           ;Put it in a segment register
  235.                 ASSUME  DS:BIOS_SEG
  236.                 MOV     AL,KB_FLAG      ;Shift flags
  237.                 AND     AL,0FH          ; only
  238.                 CMP     AL,SHIFT_MASK   ;Is the ALT key down?
  239.                 POP     DS              ;Restore DS register
  240.                 ASSUME  DS:NOTHING
  241.                 JNE     INT09_EXIT      ;If ALT not down, ignore it
  242.  
  243. ;Reset the keyboard and 8259 interrutp controller
  244.  
  245.                 IN      AL,61H
  246.                 MOV     AH,AL
  247.                 OR      AL,80H          ;Reset bit for keyboard
  248.                 OUT     61H,AL          ;Reset the keyboard
  249.                 MOV     AL,AH
  250.                 JMP     SHORT $+2       ;A short delay
  251.                 OUT     61H,AL          ;Reenable keyboard
  252.                 CLI
  253.                 MOV     AL,20H
  254.                 OUT     20H,AL          ;Reset interrupt controller
  255.                 STI
  256.  
  257.                 CMP     ACTIVE,0        ;Is CAPTURE already active?
  258.                 JNZ     SHORT_RET       ;If active, then exit
  259.                 MOV     ACTIVE,1        ;Its active now
  260.  
  261.                 PUSH    BX              ;Must preserve all registers
  262.                 PUSH    CX
  263.                 PUSH    DX
  264.                 PUSH    BP
  265.                 PUSH    DI
  266.                 PUSH    DS
  267.                 PUSH    ES
  268.                 PUSH    CS
  269.                 POP     DS              ;Set DS to CSEG
  270.                 MOV     AX,BIOS_SEG     ;ES points to BIOS data area
  271.                 MOV     ES,AX
  272.                 ASSUME  DS:CSEG, ES:BIOS_SEG ;Assembler directives
  273.                 CALL    CAPTURE         ;Read the screen contents
  274.                 MOV     WRIT_FILE,1     ;Indicate need to flush buffer
  275.                 POP     ES              ;Restore all registers
  276.                 POP     DS
  277.                 POP     DI
  278.                 POP     BP
  279.                 POP     DX
  280.                 POP     CX
  281.                 POP     BX
  282.                 ASSUME  DS:NOTHING, ES:NOTHING
  283.                 TEST    BUSY_FLAGS,011B ;Is DOS or BIOS disk busy?
  284.                 JNZ     SHORT_RET       ;If yes, then we must wait
  285.                 CALL    WRITE_TO_FILE   ;Otherwise, we'll do it now
  286. SHORT_RET:
  287.                 POP     AX              ;Stack must be restored
  288.                 IRET                    ;Now were all done
  289.  
  290. NEWINT09        ENDP
  291.  
  292. ;-----------------------------------------------------------------------
  293. ; Interrupt 13H (BIOS diskette I/O) Set the busy flag during diskette I/O
  294. ;-----------------------------------------------------------------------
  295. NEWINT13        PROC    FAR
  296.                 ASSUME  DS:NOTHING, ES:NOTHING
  297.  
  298.                 PUSHF
  299.                 OR      CS:BUSY_FLAGS,010B      ;Set BIOS busy bit
  300.                 POPF
  301.                 PUSHF                           ;This simulates an interrupt
  302.                 CALL    CS:OLDINT13             ;Do the BIOS function
  303.                 PUSHF                           ;Save result flags
  304.                 AND     BUSY_FLAGS,11111101B    ;Clear BIOS busy bit
  305.                 POPF                            ;Get back result flags
  306.                 STI                             ;Must return with interrupts on
  307.                 RET     2                       ;Return BIOS result flags
  308.  
  309. NEWINT13        ENDP
  310.  
  311. ;-----------------------------------------------------------------------
  312. ; Interrupt 16H (BIOS keyboard interface) Check to see if the buffer
  313. ; needs to be written.
  314. ;-----------------------------------------------------------------------
  315. NEWINT16        PROC    FAR
  316.                 ASSUME  DS:NOTHING, ES:NOTHING
  317.  
  318.                 CMP     CS:WRIT_FILE,1          ;Anything to write to disk?
  319.                 JE      CHECK_DOS_STAT          ;If yes, see what DOS is doing
  320. BIOS_KB:
  321.                 JMP     CS:OLDINT16             ;Just do normal KB routine
  322. CHECK_DOS_STAT:
  323.                 CMP     CS:DOS_STAT,0AH         ;Doing read string?
  324.                 JE      BEGIN_NOW               ;If yes, its safe to begin
  325.                 CMP     CS:DOS_STAT,08H         ;Doing keybaord input?
  326.                 JNE     BIOS_KB                 ;If yes, its safe to begin
  327. BEGIN_NOW:
  328.                 CALL    WRITE_TO_FILE           ;Write the buffer to disk
  329.                 OR      CS:BUSY_FLAGS,001B      ;Reset DOS busy bit
  330.                 JMP     CS:BIOS_KB              ;Continue with BIOS routine
  331. NEWINT16        ENDP
  332.  
  333. ;-----------------------------------------------------------------------
  334. ; Interrupt 21H (DOS functions) Used to keep track of DOS function calls
  335. ;-----------------------------------------------------------------------
  336. NEWINT21        PROC    FAR
  337.                 ASSUME  DS:NOTHING, ES:NOTHING
  338.  
  339.                 PUSHF                           ;Save the flags
  340.                 MOV     CS:DOS_STAT,AH          ;Store the function number
  341.                 OR      CS:BUSY_FLAGS,001B      ;Set DOS busy bit
  342.  
  343.                 OR      AH,AH                   ;Doing function zero?
  344.                 JZ      JUMP_TO_DOS             ;If yes, take the jump
  345.                 CMP     AH,4BH                  ;Doing EXEC function?
  346.                 JE      JUMP_TO_DOS             ;If yes, take the jump
  347.  
  348.                 POPF
  349.                 PUSHF
  350.                 CALL    CS:OLDINT21             ;Do the DOS function
  351.  
  352.                 PUSHF                           ;Ssve the result flags
  353.  
  354.                 AND     CS:BUSY_FLAGS,11111110B ;Clear DOS busy bit
  355.                 CMP     CS:WRIT_FILE,1          ;Anything to write to disk?
  356.                 JNE     NO_WRITE                ;If not just return
  357.  
  358.                 CALL    WRITE_TO_FILE           ;Safe to access disk now
  359. NO_WRITE:
  360.                 POPF                    ;Recover DOS result flags
  361.                 STI                     ;Must return with interrupts on
  362.                 RET     2               ;Return with DOS result flags
  363. JUMP_TO_DOS:
  364.                 POPF
  365.                 JMP     CS:OLDINT21
  366. NEWINT21        ENDP
  367.  
  368. ;-----------------------------------------------------------------------
  369. ; Interrupt 24H (critical DOS error).  This interrupt is only in
  370. ; effect during a write screen.  It is required to suppress the
  371. ; 'Abort, Retry, Ignore' message.  All fatal disk errors are ignored.
  372. ;-----------------------------------------------------------------------
  373. NEWINT24        PROC    FAR
  374.                 ASSUME  DS:NOTHING, ES:NOTHING
  375.                 XOR     AL,AL           ;Tells DOS to ignore the error
  376.                 IRET                    ;Thats all we do here
  377.  
  378. NEWINT24        ENDP
  379.  
  380. ;----------------------------------------------------------------------
  381. ;  This are is overwritten by the dynamic buffers.
  382. ;----------------------------------------------------------------------
  383. PC              =       $
  384.  
  385. BUFFER          =       PC
  386. PC              =       PC+4000
  387. LASTBYTE        =       PC
  388.  
  389. ;-----------------------------------------------------------------------
  390. ; Here is the code used to initialize CAPTURE. It is not keep resident.
  391. ; The buffer is located here and overlays the initialization code.
  392. ;-----------------------------------------------------------------------
  393.                 ASSUME  CS:CSEG, DS:CSEG, ES:NOTHING
  394.  
  395. INITIALIZE      PROC    NEAR
  396.  
  397.                 MOV     DX,OFFSET COPYRIGHT
  398.                 MOV     AH,9            ;DOS display string service
  399.                 INT     21H             ;Display title message
  400.  
  401. ; Search for a previously installed copy of CAPTURE
  402.  
  403.                 NOT     WORD PTR START  ;Modify to avoid false match
  404.                 XOR     BX,BX           ;Start search at segment zero
  405.                 MOV     AX,CS           ;Compare to this code segment
  406. NEXT_SEGMENT:
  407.                 INC     BX              ;Look at next segment
  408.                 CMP     AX,BX           ;Until reaching this code seg
  409.                 MOV     ES,BX
  410.                 JE      NOT_INSTALLED
  411.                 MOV     SI,OFFSET START ;Setup to compare strings
  412.                 MOV     DI,SI
  413.                 MOV     CX,16           ;16 bytes must match
  414.                 REP     CMPSB           ;Compare DS:SI to ES:DI
  415.                 OR      CX,CX           ;Did the strings match?
  416.                 JNZ     NEXT_SEGMENT    ;If no match, try next segment
  417.                 MOV     DX,OFFSET INSTALLED_MSG ;else, exit with error
  418.                 MOV     AH,9
  419.                 INT     21H
  420.                 MOV     AX,4C01H
  421.                 INT     21H
  422. NOT_INSTALLED:
  423.                 MOV     AX,3509H        ;Get keyboard break vector
  424.                 INT     21H
  425.                 MOV     WORD PTR [OLDINT09],  BX  ;Save segment
  426.                 MOV     WORD PTR [OLDINT09+2],ES  ;Save offset
  427.                 MOV     DX, OFFSET NEWINT09
  428.                 MOV     AX, 2509H
  429.                 INT     21H             ;DOS function to change vector
  430.  
  431.                 MOV     AX,3513H        ;Get BIOS disk interrupt vector
  432.                 INT     21H
  433.                 MOV     WORD PTR [OLDINT13],  BX  ;Save the segment
  434.                 MOV     WORD PTR [OLDINT13+2],ES  ;Save the offset
  435.                 MOV     DX, OFFSET NEWINT13
  436.                 MOV     AX, 2513H
  437.                 INT     21H             ;DOS function to change vector
  438.  
  439.                 MOV     AX,3516H        ;Get keyboard input vector
  440.                 INT     21H
  441.                 MOV     WORD PTR [OLDINT16],  BX  ;Save the segment
  442.                 MOV     WORD PTR [OLDINT16+2],ES  ;Save the offset
  443.                 MOV     DX, OFFSET NEWINT16
  444.                 MOV     AX, 2516H
  445.                 INT     21H             ;DOS function to change vector
  446.  
  447.                 MOV     AX,3521H        ;Get DOS function vector
  448.                 INT     21H
  449.                 MOV     WORD PTR [OLDINT21],  BX
  450.                 MOV     WORD PTR [OLDINT21+2],ES
  451.                 MOV     DX, OFFSET NEWINT21
  452.                 MOV     AX, 2521H
  453.                 INT     21H             ;DOS function to change vector
  454.  
  455. ;-----------------------------------------------------------------------
  456. ; Deallocate our copy of the enviornment.
  457. ; Leave code and space for the buffer resident.
  458. ;-----------------------------------------------------------------------
  459.  
  460.                 MOV     AX,DS:[002CH]   ;Get segment of enviornment
  461.                 MOV     ES,AX           ;Put it into ES
  462.                 MOV     AH,49H          ;Release allocated memory
  463.                 INT     21H
  464.  
  465.                 MOV     DX,(OFFSET LASTBYTE - OFFSET CSEG + 15)SHR 4
  466.                 MOV     AX,3100H
  467.                 INT     21H
  468.  
  469. INITIALIZE      ENDP
  470.  
  471. CSEG            ENDS
  472.                 END     START
  473.