home *** CD-ROM | disk | FTP | other *** search
/ Power Programming / powerprogramming1994.iso / progtool / info / help_7n1.arc / CAPTURE.ASM next >
Assembly Source File  |  1987-10-30  |  16KB  |  476 lines

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