home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
pcmag
/
vol7n01.arc
/
CAPTURE.ASM
next >
Wrap
Assembly Source File
|
1987-10-30
|
22KB
|
473 lines
;----------------------------------------------------------------------
; CAPTURE is a resident utility which copies an 80x25 screen buffer
; to a file. Activate CAPTURE by pressing ALT-C or any other hot
; key combination defined by the symbols HOTKEY and SHIFT_MASK.
; The filename will be SCREEN.n. The extension begins with .000 and
; is incremented by one each time CAPTURE is activated.
;-----------------------------------------------------------------------
; BIOS_SEG is located in the ROM-BIOS data area
;-----------------------------------------------------------------------
BIOS_SEG SEGMENT AT 0040H
ORG 0017H
KB_FLAG DB ? ;BIOS keyboard shift status
ORG 004AH
CRT_COLS DB ? ;Current number of screen columns
ORG 0050H
CURSOR_POSN DW 8 DUP(?) ;Current cursor location
ORG 0062H
ACTIVE_PAGE DB ? ;Active page for CGA and EGA
BIOS_SEG ENDS
;=======================================================================
CSEG SEGMENT
ASSUME CS:CSEG, DS:CSEG, ES:CSEG
ORG 0100H ;Beginning for .COM programs
START: JMP INITIALIZE ;Initialization code is at end
;-----------------------------------------------------------------------
; Data needed by this program
;-----------------------------------------------------------------------
HOTKEY EQU 2EH ;Scan code for "C" key
SHIFT_MASK EQU 00001000B ;Mask for ALT key held down
COPYRIGHT DB "CAPTURE 1.0 (c) 1987 Ziff Communications Co"
DB 13,10,"Hotkey is ALT-C$",1Ah
PROGRAMMER DB "Tom Kihlken"
INSTALLED_MSG DB 13,10,"Already Installed$"
FILENAME DB "SCREEN.000",0 ;The first filename
OLDINT09 DD ? ;Old hardware keyboard interrupt vector
OLDINT13 DD ? ;Old BIOS disk IO interrupt vector
OLDINT16 DD ? ;Old keyboard input interrupt vector
OLDINT21 DD ? ;Old DOS function interrupt vector
WRIT_FILE DB 0 ;If=1, need to write to disk
ACTIVE DB 0 ;Indicated CAPTURE is in use
DOS_STAT DB 0 ;Current DOS function indicator
BUSY_FLAGS DB 0 ;Bit masked as follows:
; 1 - DOS function is active
; 2 - BIOS disk IO is active
;-----------------------------------------------------------------------
; CAPTURE reads the screen and stores it in an internal buffer.
;-----------------------------------------------------------------------
CAPTURE PROC NEAR
ASSUME DS:CSEG, ES:BIOS_SEG
CALL GET_CURS_ADDR ;Cursor addr for this page
PUSH ES:[BX] ;Save the cursor location
MOV DI,OFFSET BUFFER ;DS:DI points to the buffer
XOR DX,DX ;Start at row 0, column 0
READ_LOOP:
CMP DL,CRT_COLS ;Past right edge of screen?
JL NOT_PAST_EDGE ;If screen is less than 80
MOV AX,0720H ;columns, then pad with a blank
JMP SHORT BUFF_CHAR
NOT_PAST_EDGE:
CALL GET_CURS_ADDR ;Get address of BIOS cursor
MOV ES:[BX],DX ;Tell BIOS where the cursor is
MOV BH,ACTIVE_PAGE ;Get active page from BIOS data
MOV AH,8 ;BIOS function to read character
INT 10H ;Read the character/attribute
BUFF_CHAR:
MOV [DI],AX ;Put the character in buffer
INC DI ;Increment the pointer twice
INC DI ;Since we stored a word
INC DL ;Do the next char in same row
CMP DL,80 ;At the right border yet?
JL READ_LOOP ;Do 80 characters in this row
INC DH ;Move to next row
XOR DL,DL ;Back to left edge (Column 0)
CMP DH,25 ;Done all 25 rows yet?
JL READ_LOOP ;Loop until whole screen is read
CALL GET_CURS_ADDR ;Cursor address for this page
POP ES:[BX] ;Recover the cursor position
RET ;Then were finished
CAPTURE ENDP
;-----------------------------------------------------------------------
; This procedure obtains the address of the cursor position for this page
;-----------------------------------------------------------------------
GET_CURS_ADDR PROC NEAR
ASSUME DS:CSEG, ES:BIOS_SEG
MOV BL,ACTIVE_PAGE ;Get the current page number
XOR BH,BH ;Convert to a word offset
SHL BX,1 ;Times two for a word
ADD BX,OFFSET CURSOR_POSN ;Add base cursor address
RET
GET_CURS_ADDR ENDP
;-----------------------------------------------------------------------
; This copies the buffer contents to a file. It should only be called
; when DOS is in a stable and reentrant condition.
;-----------------------------------------------------------------------
WRITE_TO_FILE PROC NEAR
ASSUME DS:NOTHING, ES:NOTHING
MOV WRIT_FILE,0 ;Turn off request flag
STI ;Get interrupts back on
PUSH AX ;Must preserve all registers
PUSH BX
PUSH CX
PUSH DX
PUSH BP
PUSH DS
PUSH ES
PUSH CS
POP DS
ASSUME DS:CSEG ;DS points to out code segment
MOV AX,3524H ;Get DOS critical error vector
CALL DOS_FUNCTION ;Do the DOS function
PUSH BX ;Save old INT 24 vector on stack
PUSH ES
; Replace the DOS severe error interrupt with out own routine.
MOV DX,OFFSET NEWINT24
MOV AX,2524H ;Setup to change INT 24h vector
CALL DOS_FUNCTION ;DOS function to change vector
; Try to open the file to determine if it already exists. If it does,
; then just close it and increment the filename.
OPEN_FILE: MOV DX,OFFSET FILENAME ;DS:DX points to filename
MOV AX,3D00H ;Opin file for read access
CALL DOS_FUNCTION ;Do the DOS function
JC OPEN_ERROR ;If open error, take jump
MOV BX,AX ;Need the handle in BX
MOV AH,3EH ;Close this file
CALL DOS_FUNCTION ;Do the DOS function
CALL INC_FILENAME ;Try the next filename
JMP OPEN_FILE
OPEN_ERROR:
CMP AX,2 ;Was it file not found error?
JNE DOS_ERR_EXIT ;Exit on any other error
; Now create the file, then write buffer contents and close it.
MOV DX,OFFSET FILENAME ;DS:DX points to filename
MOV CX,0020H ;Attribute for new file
MOV AH,3CH ;Create file for writing
CALL DOS_FUNCTION ;Do the DOS function
JC CLOSE_FILE ;On any error, take jump
MOV BX,AX ;Save handle in BX
MOV DX,OFFSET BUFFER ;Point to output buffer
MOV CX,4000 ;Write 4000 bytes
MOV AH,40H ;DOS write to a device function
CALL DOS_FUNCTION ;Do the DOS function
CLOSE_FILE:
MOV AH,3EH ;DOS function to close the file
CALL DOS_FUNCTION ;Do the DOS function
CALL INC_FILENAME ;Move to next filename
DOS_ERR_EXIT: POP DS ;Get INT 24H vector from stack
ASSUME DS:NOTHING
POP DX
MOV AX,2524H ;Restore critical error vector
CALL DOS_FUNCTION ;Do the DOS function
POP ES ;Finally restore all registers
POP DS
POP BP
POP DX
POP CX
POP BX
POP AX
MOV ACTIVE,0 ;CAPTURE is done now
RET ;Finished writing to disk
WRITE_TO_FILE ENDP
;-----------------------------------------------------------------------
; This routine does a dos function by calling the old interrupt vector
;-----------------------------------------------------------------------
ASSUME DS:NOTHING, ES:NOTHING
DOS_FUNCTION PROC NEAR
PUSHF ;These instructions simulate
CLI ;an interrupt
CALL CS:OLDINT21 ;Do the DOS function
STI
RET
DOS_FUNCTION ENDP
;-----------------------------------------------------------------------
; This procedure increments the extension for the filename.
;-----------------------------------------------------------------------
INC_FILENAME PROC NEAR
MOV BX,OFFSET FILENAME+9 ;Point to last letter
INC_NEXT_CHAR:
INC BYTE PTR [BX] ;Increment the extension
CMP BYTE PTR [BX],"9" ;Check for carry
JLE INC_RETURN ;If none, were finished
MOV BYTE PTR [BX],"0" ;Set this digit to zero
DEC BX ;Backup to next digit
CMP BX,OFFSET FILENAME+6 ;Dont increment the dot
JLE INC_RETURN
JMP INC_NEXT_CHAR
INC_RETURN:
RET
INC_FILENAME ENDP
;-----------------------------------------------------------------------
; Interrupt 09 (Keyboard) Watch for trigger key. When found, ignore
; it and execute the CAPTURE routine.
;-----------------------------------------------------------------------
NEWINT09 PROC FAR
ASSUME DS:NOTHING, ES:NOTHING
STI ;Allow other interrupts
PUSH AX ;Must save processor state
IN AL,60H ;Get the scan code
CMP AL,HOTKEY ;Is it the hot key?
JE TRIGGER ;If yes, check the mask
INT09_EXIT: POP AX ;Restore the processor state
JMP CS:OLDINT09 ;Continue with ROM routine
TRIGGER:
PUSH DS ;Preserve DS register
MOV AX,BIOS_SEG ;Get BIOS data segment
MOV DS,AX ;Put it in a segment register
ASSUME DS:BIOS_SEG
MOV AL,KB_FLAG ;Shift flags
AND AL,0FH ; only
CMP AL,SHIFT_MASK ;Is the ALT key down?
POP DS ;Restore DS register
ASSUME DS:NOTHING
JNE INT09_EXIT ;If ALT not down, ignore it
;Reset the keyboard and 8259 interrutp controller
IN AL,61H
MOV AH,AL
OR AL,80H ;Reset bit for keyboard
OUT 61H,AL ;Reset the keyboard
MOV AL,AH
JMP SHORT $+2 ;A short delay
OUT 61H,AL ;Reenable keyboard
CLI
MOV AL,20H
OUT 20H,AL ;Reset interrupt controller
STI
CMP ACTIVE,0 ;Is CAPTURE already active?
JNZ SHORT_RET ;If active, then exit
MOV ACTIVE,1 ;Its active now
PUSH BX ;Must preserve all registers
PUSH CX
PUSH DX
PUSH BP
PUSH DI
PUSH DS
PUSH ES
PUSH CS
POP DS ;Set DS to CSEG
MOV AX,BIOS_SEG ;ES points to BIOS data area
MOV ES,AX
ASSUME DS:CSEG, ES:BIOS_SEG ;Assembler directives
CALL CAPTURE ;Read the screen contents
MOV WRIT_FILE,1 ;Indicate need to flush buffer
POP ES ;Restore all registers
POP DS
POP DI
POP BP
POP DX
POP CX
POP BX
ASSUME DS:NOTHING, ES:NOTHING
TEST BUSY_FLAGS,011B ;Is DOS or BIOS disk busy?
JNZ SHORT_RET ;If yes, then we must wait
CALL WRITE_TO_FILE ;Otherwise, we'll do it now
SHORT_RET:
POP AX ;Stack must be restored
IRET ;Now were all done
NEWINT09 ENDP
;-----------------------------------------------------------------------
; Interrupt 13H (BIOS diskette I/O) Set the busy flag during diskette I/O
;-----------------------------------------------------------------------
NEWINT13 PROC FAR
ASSUME DS:NOTHING, ES:NOTHING
PUSHF
OR CS:BUSY_FLAGS,010B ;Set BIOS busy bit
POPF
PUSHF ;This simulates an interrupt
CALL CS:OLDINT13 ;Do the BIOS function
PUSHF ;Save result flags
AND BUSY_FLAGS,11111101B ;Clear BIOS busy bit
POPF ;Get back result flags
STI ;Must return with interrupts on
RET 2 ;Return BIOS result flags
NEWINT13 ENDP
;-----------------------------------------------------------------------
; Interrupt 16H (BIOS keyboard interface) Check to see if the buffer
; needs to be written.
;-----------------------------------------------------------------------
NEWINT16 PROC FAR
ASSUME DS:NOTHING, ES:NOTHING
CMP CS:WRIT_FILE,1 ;Anything to write to disk?
JE CHECK_DOS_STAT ;If yes, see what DOS is doing
BIOS_KB:
JMP CS:OLDINT16 ;Just do normal KB routine
CHECK_DOS_STAT:
CMP CS:DOS_STAT,0AH ;Doing read string?
JE BEGIN_NOW ;If yes, its safe to begin
CMP CS:DOS_STAT,08H ;Doing keybaord input?
JNE BIOS_KB ;If yes, its safe to begin
BEGIN_NOW:
CALL WRITE_TO_FILE ;Write the buffer to disk
OR CS:BUSY_FLAGS,001B ;Reset DOS busy bit
JMP CS:BIOS_KB ;Continue with BIOS routine
NEWINT16 ENDP
;-----------------------------------------------------------------------
; Interrupt 21H (DOS functions) Used to keep track of DOS function calls
;-----------------------------------------------------------------------
NEWINT21 PROC FAR
ASSUME DS:NOTHING, ES:NOTHING
PUSHF ;Save the flags
MOV CS:DOS_STAT,AH ;Store the function number
OR CS:BUSY_FLAGS,001B ;Set DOS busy bit
OR AH,AH ;Doing function zero?
JZ JUMP_TO_DOS ;If yes, take the jump
CMP AH,4BH ;Doing EXEC function?
JE JUMP_TO_DOS ;If yes, take the jump
POPF
PUSHF
CALL CS:OLDINT21 ;Do the DOS function
PUSHF ;Ssve the result flags
AND CS:BUSY_FLAGS,11111110B ;Clear DOS busy bit
CMP CS:WRIT_FILE,1 ;Anything to write to disk?
JNE NO_WRITE ;If not just return
CALL WRITE_TO_FILE ;Safe to access disk now
NO_WRITE:
POPF ;Recover DOS result flags
STI ;Must return with interrupts on
RET 2 ;Return with DOS result flags
JUMP_TO_DOS:
POPF
JMP CS:OLDINT21
NEWINT21 ENDP
;-----------------------------------------------------------------------
; Interrupt 24H (critical DOS error). This interrupt is only in
; effect during a write screen. It is required to suppress the
; 'Abort, Retry, Ignore' message. All fatal disk errors are ignored.
;-----------------------------------------------------------------------
NEWINT24 PROC FAR
ASSUME DS:NOTHING, ES:NOTHING
XOR AL,AL ;Tells DOS to ignore the error
IRET ;Thats all we do here
NEWINT24 ENDP
;----------------------------------------------------------------------
; This are is overwritten by the dynamic buffers.
;----------------------------------------------------------------------
PC = $
BUFFER = PC
PC = PC+4000
LASTBYTE = PC
;-----------------------------------------------------------------------
; Here is the code used to initialize CAPTURE. It is not keep resident.
; The buffer is located here and overlays the initialization code.
;-----------------------------------------------------------------------
ASSUME CS:CSEG, DS:CSEG, ES:NOTHING
INITIALIZE PROC NEAR
MOV DX,OFFSET COPYRIGHT
MOV AH,9 ;DOS display string service
INT 21H ;Display title message
; Search for a previously installed copy of CAPTURE
NOT WORD PTR START ;Modify to avoid false match
XOR BX,BX ;Start search at segment zero
MOV AX,CS ;Compare to this code segment
NEXT_SEGMENT:
INC BX ;Look at next segment
CMP AX,BX ;Until reaching this code seg
MOV ES,BX
JE NOT_INSTALLED
MOV SI,OFFSET START ;Setup to compare strings
MOV DI,SI
MOV CX,16 ;16 bytes must match
REP CMPSB ;Compare DS:SI to ES:DI
OR CX,CX ;Did the strings match?
JNZ NEXT_SEGMENT ;If no match, try next segment
MOV DX,OFFSET INSTALLED_MSG ;else, exit with error
MOV AH,9
INT 21H
MOV AX,4C01H
INT 21H
NOT_INSTALLED:
MOV AX,3509H ;Get keyboard break vector
INT 21H
MOV WORD PTR [OLDINT09], BX ;Save segment
MOV WORD PTR [OLDINT09+2],ES ;Save offset
MOV DX, OFFSET NEWINT09
MOV AX, 2509H
INT 21H ;DOS function to change vector
MOV AX,3513H ;Get BIOS disk interrupt vector
INT 21H
MOV WORD PTR [OLDINT13], BX ;Save the segment
MOV WORD PTR [OLDINT13+2],ES ;Save the offset
MOV DX, OFFSET NEWINT13
MOV AX, 2513H
INT 21H ;DOS function to change vector
MOV AX,3516H ;Get keyboard input vector
INT 21H
MOV WORD PTR [OLDINT16], BX ;Save the segment
MOV WORD PTR [OLDINT16+2],ES ;Save the offset
MOV DX, OFFSET NEWINT16
MOV AX, 2516H
INT 21H ;DOS function to change vector
MOV AX,3521H ;Get DOS function vector
INT 21H
MOV WORD PTR [OLDINT21], BX
MOV WORD PTR [OLDINT21+2],ES
MOV DX, OFFSET NEWINT21
MOV AX, 2521H
INT 21H ;DOS function to change vector
;-----------------------------------------------------------------------
; Deallocate our copy of the enviornment.
; Leave code and space for the buffer resident.
;-----------------------------------------------------------------------
MOV AX,DS:[002CH] ;Get segment of enviornment
MOV ES,AX ;Put it into ES
MOV AH,49H ;Release allocated memory
INT 21H
MOV DX,(OFFSET LASTBYTE - OFFSET CSEG + 15)SHR 4
MOV AX,3100H
INT 21H
INITIALIZE ENDP
CSEG ENDS
END START