home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 December
/
simtel1292_SIMTEL_1292_Walnut_Creek.iso
/
msdos
/
pcmag
/
vol6n18.arc
/
SNIPPER.ASM
next >
Wrap
Assembly Source File
|
1987-09-01
|
26KB
|
779 lines
page 60,132
; SNIPPER is a resident utility which allows cutting out a portion
; of the screen. The selected portion may be printed, written
; to disk or entered in the keyboard buffer. Activate SNIPPER by
; pressing ALT-W, then position the cursor in the upper left corner of
; the window using the arrow keys. Press CR to fix the first corner,
; then expand the window with arrow keys. Finally, type "P" to print,
; "F" for disk file, "G" to retrieve or CR for a help menu. Press ESC
; any time to exit SNIPPER. When installing SNIPPER, use the optional
; parameters to expand it's internal buffer for displays (such as the
; EGA) containing more than the standard 25 rows and 80 columns.
; SNIPPER [rows,columns]
;------------------------------------;
; BIOS_SEG IS THE ROM-BIOS DATA AREA ;
;------------------------------------;
BIOS_SEG SEGMENT AT 0040H
ORG 004AH
CRT_COLS DB ? ;CURRENT NUMBER OF COLUMNS
ORG 0050H
CURSOR_POSN DW 8 DUP(?) ;CURRENT CURSOR LOCATION
ORG 0062H
ACTIVE_PAGE DB ? ;ACTIVE PAGE FOR CGA AND EGA
ORG 0084H
ROWS DB ? ;LAST ROW NUMBER FOR EGA
BIOS_SEG ENDS
CSEG SEGMENT
ASSUME CS:CSEG,DS:NOTHING
ORG 0100H ;BEGINNING FOR .COM PROGRAMS
START: JMP INITIALIZE ;INITIALIZATION CODE IS AT END
;--------------------------------;
; DATA AREA USED BY THIS PROGRAM ;
;--------------------------------;
HOTKEY EQU 11H ;SCAN CODE FOR "W" KEY
SHIFT_MASK EQU 00001000B ;MASK FOR ALT KEY
;
COPYRIGHT DB "SNIPPER 1.0 (c) 1987 Ziff Communications Co."
DB 13,10,"Hotkey is ALT-W",13,10,"$",1AH
PROGRAMMER DB "Tom Kihlken"
INSTALLED_MSG DB "Already Installed",13,10,"$"
BAD_DOS_MSG DB "Requires DOS 2.0+",13,10,"$"
OLDINT09 DD ? ;OLD KEYBOARD BREAK INTERRUPT VECTOR
OLDINT13 DD ? ;OLD BIOS DISK IO INTERRUPT VECTOR
OLDINT16 DD ? ;OLD KEYBOARD INTERRUPT VECTOR
OLDINT21 DD ? ;OLD DOS FUNCTION INTERRUPT VECTOR
ERR_STAT DB ? ;ERROR STATUS DURING FILE OUTPUT
FILE_PROMPT DB "Enter Filename: "
FILENAME DB "SCREEN.CUT" ;THE DEFAULT FILENAME
DB 15 DUP (0) ;LEAVE ROOM FOR DRIVE AND PATH
BUFF_NEXT DW BUFF_START ;POINTER TO NEXT KEY IN BUFFER
BUFF_LAST DW BUFF_START ;POINTER TO LAST KEY IN BUFFER
BUFF_START EQU OFFSET INITIALIZE
BUFF_SIZE EQU 25*(80+2) ;ROOM FOR 25 ROWS OF 80 COLUMNS
BUFF_END DW BUFF_START+BUFF_SIZE
TOP_LEFT LABEL WORD ;FIRST CORNER OF WINDOW
LEFT_SIDE DB 0 ;COLUMN NUMBER OF LEFT SIDE
TOP_ROW DB 0 ;ROW NUMBER OF TOP SIDE
BOT_RIGHT LABEL WORD ;SECOND CORNER OF WINDOW
RIGHT_SIDE DB ? ;COLUMN NUMBER OR RIGHT SIDE
BOT_ROW DB ? ;ROW NUMBER OF BOTTOM
SEND_CHAR DW ? ;POINTER TO CHARACTER HANDLER
SEND_KEYS DB 0 ;IF=1, USE KEYSTROKES FROM BUFFER
WRIT_FILE DB 0 ;IF=1, NEED TO WRITE TO DISK
BUSY_FLAGS DB 0 ;BIT MASKED AS FOLLOWS:
; 1 - DOS IS ACTIVE
; 2 - BIOS IO IS ACTIVE
; 4 - SNIPPER IS ACTIVE
DOS_STAT DB 0 ;CURRENT DOS FUNCTION
HELP_MENU DB 201,10 DUP(205),187
DB 186," F - File ",186
DB 186," P - Print",186
DB 186," S - Save ",186
DB 186," G - Get ",186
DB 186,"Esc- Quit ",186
DB 200,10 DUP(205),188
;------------------------------------------------------------------;
; SNIPPER BUILDS THE WINDOW AND ACCEPTS COMMANDS FROM THE KEYBOARD ;
;------------------------------------------------------------------;
SNIPPER PROC NEAR
ASSUME DS:CSEG, ES:BIOS_SEG
XOR BX,BX ;BX IS INCREMENT FOR ROW/COLUMN
GET_KB_KEY1:
MOV DX,TOP_LEFT ;GET LOCATION OF FIRST CORNER
ADD DH,BH ;ADD IN THE ROW INCREMENT
ADD DL,BL ;ADD IN THE COLUMN INCREMENT
CMP DL,0 ;AT LEFT EDGE OF SCREEN?
JGE NOT_LEFT_EDGE
MOV DL,CRT_COLS ;JUMP TO THE RIGHT EDGE
DEC DL
NOT_LEFT_EDGE:
CMP DL,CRT_COLS ;AT RIGHT EDGE OF SCREEN YET?
JB NOT_RIGHT_EDGE ;IF NOT, KEEP MOVING RIGHT
XOR DL,DL ;IF YES, WRAP TO LEFT EDGE
NOT_RIGHT_EDGE:
CMP DH,0 ;AT TOP OF SCREEN YET?
JGE NOT_AT_TOP
MOV DH,ROWS ;JUMP DOWN TO THE BOTTOM
NOT_AT_TOP:
CMP DH,ROWS ;AT BOTTOM OF SCREEN?
JLE NOT_AT_BOTTOM
XOR DH,DH ;JUMP BACK TO THE TOP
NOT_AT_BOTTOM:
MOV TOP_LEFT,DX ;SAVE NEW CORNER LOCATION
CALL REV_VIDEO ;CHANGE IT TO REVERSE VIDEO
XOR AH,AH ;BIOS KEYBOARD INPUT
INT 16H ;GET A KEYSTROKE
PUSH AX
CALL REV_VIDEO ;PUT ATTRIBUTE BACK TO NORMAL
POP AX
CMP AH,1 ;IS IT ESCAPE?
JNE NOT_ESC
RET ;JUST RETURN TO EXIT
NOT_ESC:
MOV BX,0FF00H ;INCREMENT TO SUBTRACT ONE ROW
CMP AH,48H ;IS IT UP ARROW?
JE GET_KB_KEY1
MOV BX,0100H ;INCREMENT TO ADD ONE ROW
CMP AH,50H ;IS IT DOWN ARROW?
JE GET_KB_KEY1
MOV BX,0001H ;INCREMENT TO ADD ONE COLUMN
CMP AH,4DH ;IS IT RIGHT ARROW?
JE GET_KB_KEY1
MOV BX,00FFH ;INCREMENT TO SUBTRACT ONE COLUMN
CMP AH,4BH ;IS IT LEFT ARROW?
JE GET_KB_KEY1
XOR BX,BX
CMP AL,13 ;IS IT A CARRIAGE RETURN?
JNE NOT_CR
MOV DX,TOP_LEFT ;A CARRIAGE RETURN WAS PRESSED
MOV BOT_RIGHT,DX ;INITIALIZE THE SECOND CORNER
CALL REV_VIDEO ;CHANGE IT BACK TO REVERSE VIDEO
JMP SHORT GET_KB_KEY2
NOT_CR:
CMP AH,22H ;IS IT THE "G" KEY
JE TYPE_BUFF ;IF YES, THAN GET THE WINDOW
JMP GET_KB_KEY1 ;JUST GET ANOTHER KEY
TYPE_BUFF:
MOV SEND_KEYS,1 ;SIGNAL TO SEND THE KEYS
RET
GET_KB_KEY2:
XOR AH,AH
INT 16H ;GET A KEYSTROKE
GOT_KEY2: MOV DX,BOT_RIGHT
CMP AH,48H ;IS IT UP ARROW?
JE SUB_ROW ;SUBTRACT A ROW FROM WINDOW
CMP AH,50H ;IS IT DOWN ARROW?
JE ADD_ROW ;ADD A ROW TO THE WINDOW
CMP AH,4DH ;IS IT RIGHT ARROW?
JE ADD_COL ;ADD A COLUMN TO THE WINDOW
CMP AH,4BH ;IS IT LEFT ARROW?
JE SUB_COL ;SUBTRACT A COLUMN FROM WINDOW
JMP NOT_ARROW_KEY
SUB_COL:
DEC DL ;SUBTRACT A COLUMN
CMP DL,LEFT_SIDE ;DONT ERASE IT COMPLETELY
JL GET_KB_KEY2
MOV RIGHT_SIDE,DL ;SAVE NEW RIGHT SIDE COLUMN
INC DL
JMP SHORT COL_LOOP
ADD_COL:
INC DL ;ADD A COLUMN
CMP DL,CRT_COLS ;AT RIGHT EDGE OF SCREEN?
JAE GET_KB_KEY2 ;STOP WHEN SCREEN IS FILLED
MOV RIGHT_SIDE,DL ;SAVE NEW RIGHT SIDE COLUMN
COL_LOOP:
CALL REV_VIDEO ;REVERSE THIS CHARACTER
DEC DH ;MOVE TO NEXT ROW
CMP DH,TOP_ROW ;AT TOP ROW YET?
JGE COL_LOOP ;LOOP UNTIL AT TOP ROW
JMP GET_KB_KEY2
SUB_ROW:
DEC DH
CMP DH,TOP_ROW ;AT TOP OF WINDOW?
JL GET_KB_KEY2 ;DONT ERASE IT COMPLETELY
MOV BOT_ROW,DH
INC DH
JMP SHORT ROW_LOOP
ADD_ROW:
INC DH
CMP DH,ROWS ;AT BOTTOM OF SCREEN?
JG GET_KB_KEY2 ;STOP WHEN SCREEN IS FILLED
MOV BOT_ROW,DH
ROW_LOOP:
CALL REV_VIDEO ;REVERSE THIS CHARACTER
DEC DL ;MOVE TO NEXT COLUMN
CMP DL,LEFT_SIDE ;AT LEFT EDGE YET?
JGE ROW_LOOP ;CONTINUE UNTIL AT LEFT EDGE
JMP GET_KB_KEY2
NOT_ARROW_KEY:
CMP AH,19H ;WAS IT THE "P" KEY?
JNE NOT_P
MOV SEND_CHAR,OFFSET PRINT_CHAR
JMP READ_WINDOW
NOT_P:
MOV BUFF_NEXT,BUFF_START
MOV BUFF_LAST,BUFF_START
MOV SEND_CHAR,OFFSET BUFF_CHAR
CMP AH,1FH ;WAS IT THE "S" KEY?
JNE NOT_S
MOV SEND_CHAR,OFFSET BUFF_CHAR
JMP READ_WINDOW
NOT_S:
CMP AH,22H ;IS IT THE "G" KEY
JNE NOT_G
MOV SEND_KEYS,1
JMP READ_WINDOW
NOT_G:
CMP AH,21H ;IS IT THE "F" KEY
JNE NOT_F
MOV WRIT_FILE,0
CALL GET_FILENAME
CMP WRIT_FILE,-1 ;WAS ESCAPE REQUESTED?
JE ERASE_BOX
CALL READ_WINDOW
MOV WRIT_FILE,1
TEST BUSY_FLAGS,00000011B ;IS INT21 OR INT13 BUSY?
JNZ RETURN ;IF YES, WAIT TILL LATER
CALL WRITE_TO_FILE ;IF NOT, DO IT NOW
RETURN:
RET
NOT_F:
CMP AH,1 ;IS IT ESCAPE?
JE ERASE_BOX ;IF YES, ERASE BOX AND EXIT
CMP AL,13 ;IS IT A CARRIAGE RETURN?
JE DISPLAY_HELP ;IF YES, DISPLAY HELP
JMP GET_KB_KEY2 ;OTHERWISE JUST GET ANOTHER KEY
ERASE_BOX:
MOV SEND_CHAR,OFFSET RETURN
JMP READ_WINDOW
DISPLAY_HELP:
CALL EXCHANGE_HELP ;PUT UP THE HELP MENU
XOR AH,AH
INT 16H ;GET ANOTHER KEYSTROKE
PUSH AX ;SAVE THE KEYSTROKE
CALL EXCHANGE_HELP ;PULL DOWN THE HELP MENU
POP AX ;GET BACK THE KEYSTROKE
JMP GOT_KEY2
;*********************************************************************
REV_VIDEO:
CALL READ_CHAR ;READ CHARACTER AND ATTRIBUTE
MOV BL,AH ;SAVE ATTRIBUTE IN BL
AND BL,10001000B ;GET BLINK AND INTENSITY BITS
AND AH,01110111B ;NOW LOOK ONLY AT COLOR BITS
MOV CL,4 ;ROTATE FOUR COUNTS
ROR AH,CL ;ROTATE FOREGROUND AND BACKGROUND
OR BL,AH ;PUT BACK BLINK AND INTENSITY BITS
CALL DISPLAY_CHAR ;WRITE CHARACTER AND ATTRIBUTE
RET
;*********************************************************************
READ_WINDOW:
MOV DX,TOP_LEFT ;GET LOCATION OF FIRST CORNER
READ_LOOP:
CALL REV_VIDEO ;PUT ATTRIBUTE BACK TO NORMAL
CALL READ_CHAR ;READ THE CHARACTER
CALL SEND_CHAR ;CALL TO THE POINTER
INC DL ;NEXT CHAR IN ROW
CMP DL,RIGHT_SIDE ;AT THE RIGHT BORDER YET?
JLE READ_LOOP ;DO ALL CHARACTERS IN THIS ROW
CALL CR_LF ;SEND CR-LF AFTER EACH ROW
INC DH ;MOVE TO NEXT ROW
MOV DL,LEFT_SIDE ;BACK TO LEFT EDGE
CMP DH,BOT_ROW ;AT THE BOTTOM BORDER YET?
JLE READ_LOOP ;READ ENTIRE WINDOW
RET
;*********************************************************************
CR_LF:
MOV AL,13
CALL SEND_CHAR ;SEND A CARRIAGE RETURN
MOV AL,10
CALL SEND_CHAR ;SEND A LINE FEED
RET
;*********************************************************************
DISPLAY_CHAR:
PUSH BX ;SAVE THE ATTRIBUTE
CALL GET_CURS_ADDR ;GET ADDRESS OF BIOS CURSOR
MOV ES:[BX],DX ;TELL BIOS WHERE THE CURSOR IS
POP BX ;GET BACK THE ATTRIBUTE
MOV BH,ACTIVE_PAGE ;GET ACTIVE PAGE
PUSH CX ;SAVE THE LOOP COUNT
MOV CX,1 ;WRITE 1 CHARACTER
MOV AH,9 ;WRITE CHARACTER AND ATTRIBUTE
INT 10H
POP CX ;RECOVER LOOP COUNT
RET ;DONE WRITING THE CHARACTER
;*********************************************************************
READ_CHAR:
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
MOV AH,8 ;BIOS FUNCTION TO READ CHARACTER
INT 10H ;READ THE CHARACTER/ATTRIBUTE
RET
;*********************************************************************
PRINT_CHAR:
PUSH DX
XOR AH,AH ;USE FUNCTION 0
XOR DX,DX ;PRINTER NUMBER 0
INT 17H ;BIOS PRINT CHARACTER FUNCTION
ROR AH,1 ;LOOK AT BIT ZERO
JNC PRINT_OK ;DID A TIMEOUT OCCUR?
MOV SEND_CHAR,OFFSET RETURN
PRINT_OK:
POP DX
RET ;DONE PRINTING CHARACTER
;*********************************************************************
BUFF_CHAR:
MOV BX,BUFF_LAST ;GET LOCATION OF LAST CHARACTER
MOV [BX],AL ;PUT THE CHARACTER IN BUFFER
INC BX ;ADVANCE THE POINTER
MOV BUFF_LAST,BX ;CHECK FOR BUFFER FULL
CMP BX,BUFF_END ;IS THE BUFFER FULL YET?
JNE BUFF_OK ;IF NOT, KEEP GOING
MOV SEND_CHAR,OFFSET RETURN
BUFF_OK:
RET ;NOW ITS IN THE BUFFER
;*********************************************************************
GET_CURS_ADDR:
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 IN BASE ADDRESS
RET
;*********************************************************************
EXCHANGE_HELP:
XOR DX,DX ;START AT TOP LEFT CORNER
LEA SI,HELP_MENU
EXCHANGE_LOOP:
CMP DL,12 ;AT LAST COLUMN IN THIS ROW YET?
JL SWAP_CHAR
XOR DL,DL ;BACK TO FIRST COLUMN
INC DH ;DO THE NEXT ROW
CMP DH,7 ;AT LAST ROW YET?
JL SWAP_CHAR ;QUIT WHEN LAST ROW IS DONE
RET
SWAP_CHAR:
CALL READ_CHAR ;READ CHARACTER AT THIS POSITION
XCHG AL,CS:[SI] ;SWAP WITH THE HELP TEXT
MOV BL,AH ;ATTRIBUTE IS THE SAME
CALL DISPLAY_CHAR ;PUT NEW CHARACTER ON SCREEN
INC DL ;POINT TO NEXT POSITION
INC SI
JMP EXCHANGE_LOOP
;*********************************************************************
GET_FILENAME:
LEA SI,FILE_PROMPT ;POINT TO THE PROMPT FOR SOURCE
XOR DI,DI ;USE THE PSP FOR BUFFER
XOR DX,DX ;PUT PROMPT AT TOP LEFT CORNER
MOV CX,40 ;USE MAX OF 40 CHARACTERS
DISPLAY_PROMPT:
PUSH CX ;SAVE LOOP COUNT
CALL READ_CHAR ;GET CHARACTER ON THIS LINE
MOV CS:[DI],AX ;STORE IT IN THE PSP
INC DI ;ADD TWO FOR NEXT CHARACTER
INC DI
MOV AL,CS:[SI] ;GET NEXT PROMPT CHARACTER
INC SI ;NEXT CHARACTER IN PROMPT
MOV BL,47H ;ATTRIBUTE FOR PROMPT
CALL DISPLAY_CHAR ;PUT UP THE PROMPT CHARACTER
INC DL ;POINT TO NEXT COLUMN
POP CX ;GET BACK LOOP COUNT
LOOP DISPLAY_PROMPT ;ENTIRE PROMPT AND FILENAME
FIND_LAST_LETTER:
DEC SI ;BACKUP TO LAST LETTER
DEC DL ;BACKUP TO LAST COLUMN
CMP BYTE PTR [SI],0 ;IS THIS A LETTER?
JE FIND_LAST_LETTER;BACKUP UNTILL A LETTER IS FOUND
INC DL ;PUT BLINKING BOX AT LAST LETTER
READ_KB:
MOV AL,219 ;ASCII FOR BOX CHARACTER
MOV BL,47H+80H ;MAKE IT A BLINKING BOX CHARACTER
CALL DISPLAY_CHAR ;WRITE THE BLINKING BOX
;
XOR AH,AH ;FUNCTIO 0 TO GET NEXT KEY
INT 16H ;BIOS KEYBOARD INPUT
CMP AL,13 ;IS IT A CARRIAGE RETURN?
JE ERASE_PROMPT
CMP AL,8 ;IS IT A BACKSPACE?
JE BACK_SPACE
CMP AH,1 ;IS IT ESCAPE?
JE ESC_RET
CMP AL,"." ;IS IT A VALID LETTER?
JL READ_KB
CMP AL,"z" ;IS IT A VALID LETTER?
JG READ_KB
CMP DL,39 ;ONLY ALLOW 40 CHARACTERS
JGE READ_KB
TTY_KEY:
MOV BL,47H ;ATTRIBUTE FOR FILENAME
CALL DISPLAY_CHAR ;WRITE THE LETTER
INC DL ;MOVE TO NEXT COLUMN
JMP READ_KB ;GET ANOTHER KEYSTROKE
BACK_SPACE:
CMP DL,16 ;AT BEGINNING OF LINE?
JLE READ_KB ;IF YES, CAN'T BACKUP FROM HERE
MOV AL,0 ;WRITE A NORMAL BLANK (ASCII 0)
MOV BL,47H ;ATTRIBUTE FOR FILENAME
CALL DISPLAY_CHAR ;WRITE THE LETTER
DEC DL ;BACKUP THE CURSOR
JMP READ_KB ;THEN GET THE NEXT KEY
ESC_RET:
MOV WRIT_FILE,-1 ;INDICATE ESCAPE IS REQUESTED
ERASE_PROMPT:
XOR AL,AL ;GET RID OF THE CURSOR
CALL DISPLAY_CHAR ;WRITE THE LETTER
LEA DI,FILE_PROMPT ;COPY TO FILENAME
XOR SI,SI ;COPY FROM PSP
XOR DX,DX ;PROMPT IS AT ROW ZERO
MOV CX,40 ;COPY ALL 40 CHARACTERS
ERASE_LOOP:
CALL READ_CHAR ;GET CHARACTER ON THIS LINE
MOV CS:[DI],AL ;PUT IN BACK IN MEMORY
INC DI
MOV AX,CS:[SI] ;GET THE ORIGINAL CHARACTER BACK
MOV BL,AH ;PUT ATTRIBUTE INTO BL
INC SI
INC SI
CALL DISPLAY_CHAR ;WRITE ORIGINAL CHARACTER
INC DL ;MOVE TO NEXT COLUMN
LOOP ERASE_LOOP ;ERASE THE ENTIRE PROMPT
RET
SNIPPER 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
PUSH AX ;MUST PRESERVE ALL REGISTERS
PUSH BX
PUSH CX
PUSH DX
PUSH DS
PUSH ES
PUSH CS
POP DS
ASSUME DS:CSEG ;DS POINTS TO OUR CODE SEGMENT
MOV AX,3524H ;GET DOS CRITICAL ERROR VECTOR
INT 21H ;DOS FUNCTION TO GET VECTOR
PUSH BX ;SAVE OLD VECTOR ON STACK
PUSH ES
; REPLACE THE DOS SEVERE ERROR INTERRUPT WITH OUR OWN ROUTINE.
MOV DX,OFFSET NEWINT24
MOV AX,2524H ;SETUP TO CHANGE INT 24h VECTOR
INT 21H ;CHANGE DOS SEVERE ERROR VECTOR
MOV DX,OFFSET FILENAME ;POINT TO FILENAME
; FIRST TRY TO OPEN THE FILE. IF DOS RETURNS WITH THE CARRY FLAG SET,
; THE FILE DIDN'T EXIST AND WE MUST CREATE IT. ONCE THE FILE IS OPENED,
; ADVANCE THE FILE POINTER TO THE END OF FILE TO APPEND.
MOV AX,3D02H ;DOS FUNCTION TO OPEN FILE
INT 21H ;DOS WILL RETURN WITH CARRY FLAG
JC FILE_NOT_FOUND ;SET IF FILE DOESN'T EXIST.
MOV BX,AX ;KEEP HANDLE IN BX ALSO
XOR CX,CX ;MOVE DOS FILE POINTER TO THE
XOR DX,DX ;END OF THE FILE. THIS LETS US
MOV AX,4202H ;APPEND THIS TO AN EXISTING FILE
INT 21H ;DOS FUNCTION TO MOVE POINTER
JNC WRITE_FILE ;IF NO ERROR, CONTINUE TO WRITE
DOS_ERROR:
CMP ERR_STAT,0 ;DID A SEVERE ERROR OCCUR?
JNE REP_VECTOR ;IF SEVERE ERROR, JUST QUIT
JMP SHORT CLOSE_FILE;JUST CLOSE THE FILE
FILE_NOT_FOUND: CMP ERR_STAT,0 ;DID A SEVERE ERROR OCCUR?
JNE REP_VECTOR ;IF SEVERE ERROR, JUST QUIT
MOV CX,0020H ;ATTRIBUTE FOR NEW FILE
MOV AH,3CH ;CREATE FILE FOR WRITING
INT 21H ;DOS FUNCTION TO CREATE FILE
JC DOS_ERROR ;ON ANY ERROR, TAKE JUMP
MOV BX,AX ;SAVE HANDLE IN BX
WRITE_FILE: MOV DX,BUFF_START ;POINT TO BUFFER
MOV CX,BUFF_LAST ;GET BUFFER POINTER
SUB CX,DX ;NUMBER OF CHARS IN BUFFER
MOV AH,40H ;DOS WRITE TO A DEVICE FUNCTION
INT 21H ;WRITE TO THE FILE
CLOSE_FILE:
MOV AH,3EH ;DOS FUNCTION TO CLOSE THE FILE
INT 21H
REP_VECTOR:
POP DS ;GET INT 24H VECTOR FROM STACK
POP DX
MOV AX,2524H ;RESTORE CRITICAL ERROR VECTOR
INT 21H ;DOS FUNCTION TO CHANGE VECTOR
POP ES ;FINALLY RESTORE ALL REGISTERS
POP DS
POP DX
POP CX
POP BX
POP AX
RET ;FINISHED WRITING TO DISK
WRITE_TO_FILE ENDP
;---------------------------------------------------------------------;
; INTERRUPT 09 ROUTINE. WATCH FOR TRIGGER KEY TO POP UP.
;---------------------------------------------------------------------;
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 OLDINT09 ;CONTINUE WITH ROM ROUTINE
TRIGGER: MOV AH,2 ;GET KEYBOARD STATUS
INT 16H ;BIOS KEYBOARD SERVICE
AND AL,0FH ;Take lo er four bits
CMP AL,SHIFT_MASK ;IS ALT KEY DOWN?
JNZ INT09_EXIT ;IF NOT, IGNORE IT
TEST BUSY_FLAGS,00000100B ;IS SNIPPER ALREADY ACTIVE?
JNZ INT09_EXIT ;IF ACTIVE, THEN EXIT
OR BUSY_FLAGS,00000100B ;ITS ACTIVE NOW
PUSHF
CALL OLDINT09 ;LET ROM PROCESS THE KEY
PUSH BX ;MUST PRESERVE ALL REGISTERS
PUSH CX
PUSH DX
PUSH BP
PUSH SI
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
CALL GET_CURS_ADDR ;CURSOR ADDRESS FOR THIS PAGE
PUSH ES:[BX] ;SAVE THE CURSOR LOCATION
CALL SNIPPER ;DO THE WINDOW
CALL GET_CURS_ADDR ;CURS0R ADDRESS FOR THIS PAGE
POP ES:[BX] ;GET BACK CURSOR POSITION
AND BUSY_FLAGS,11111011B ;SNIPPER IS NOT ACTIVE
POP ES ;RESTORE ALL REGISTERS
POP DS
POP DI
POP SI
POP BP
POP DX
POP CX
POP BX
POP AX
IRET ;NOW WERE ALL DONE
NEWINT09 ENDP
;---------------------------------------------------------------------;
; INTERRUPT 13 ROUTINE. SET BIOS BUST BIT ;
;---------------------------------------------------------------------;
NEWINT13 PROC FAR
ASSUME DS:NOTHING, ES:NOTHING
OR BUSY_FLAGS,00000010B ;SET BIOS BUSY BIT
PUSHF
CALL 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 INTERUPTS ON
RET 2 ;RETURN BIOS RESULT FLAGS
NEWINT13 ENDP
;---------------------------------------------------------------------;
; INTERRUPT 16 ROUTINE. INSERT KEYSTROKES FROM BUFFER ;
;---------------------------------------------------------------------;
NEWINT16 PROC FAR
ASSUME DS:NOTHING, ES:NOTHING
PUSH BX
CMP SEND_KEYS,1 ;SENDING KEYS FROM BUFFER?
JE INSERT_KEY ;IF YES, THEN GET NEXT ONE
CMP WRIT_FILE,1 ;ANYTHING TO WRITE TO DISK?
JE CHECK_DOS_STAT ;IF YES, THIS IS THE TIME
BIOS_KB:
POP BX
JMP OLDINT16 ;JUST DO NORMAL KB ROUTINE
CHECK_DOS_STAT:
CMP DOS_STAT,0AH ;DOING READ STRING?
JE BEGIN_NOW ;IF YES, ITS SAFE TO BEGIN
CMP DOS_STAT,8 ;DOING KEYBOARD INPUT?
JNE BIOS_KB ;IF YES, ITS SAFE TO BEGIN
BEGIN_NOW:
STI ;GET INTERRUPTS BACK ON
CALL WRITE_TO_FILE ;EMPTY THE BUFFER
JMP BIOS_KB ;CONTINUE WITH BIOS ROUTINE
INSERT_KEY:
STI ;INTERRUPTS BACK ON
MOV BX,BUFF_NEXT ;GET ADDRESS OF NEXT BYTE
CMP BX,BUFF_LAST ;AT END OF BUFFER YET?
JL GET_A_KEY ;IF NOT, GET THE NEXT ONE
MOV SEND_KEYS,0 ;WHEN DONE, TURN OFF SEND SWITCH
GET_A_KEY:
MOV AL,CS:[BX] ;GET THE NEXT KEY CODE
CMP AL,10 ;IS IT A LINE FEED?
JNE NOT_LF ;DONT RETURN THE LINE FEEDS
INC BUFF_NEXT ;SKIP TO NEXT KEY
JMP INSERT_KEY
NOT_LF:
CMP AH,1 ;REQUEST FOR STATUS ONLY?
JE RETURN_STATUS ;IF YES, RETURN STATUS ONLY
CMP AH,0 ;REQUEST TO GET THE NEXT KEY
JNE BIOS_KB ;IF NOT, IGNORE THIS FUNCTION
INC BX ;REMOVE THIS KEY FROM OUR BUFFER
MOV BUFF_NEXT,BX ;SAVE THE POINTER TO NEXT KEY
RETURN_STATUS:
OR BL,1 ;CLEAR ZERO FLAG TO INDICATE A
POP BX ;KEY IS AVAILIABLE
RET 2 ;RETURN WITH THESE FLAGS
NEWINT16 ENDP
;---------------------------------------------------------------------;
; INTERRUPT 21 ROUTINE. THIS ROUTINE IS USED TO MONITOR DOS FUNCTION ;
; CALLS. IF THE BUFFER NEEDS TO BE FLUSHED, IT WIL BE DONE HERE. ;
;---------------------------------------------------------------------;
NEWINT21 PROC FAR
ASSUME DS:NOTHING, ES:NOTHING
STI
OR AH,AH ;DOING FUNCTION ZERO?
JNE NOT_ZERO
MOV AH,4CH ;IF YES, CHANGE IT TO A 4CH
NOT_ZERO:
OR BUSY_FLAGS,00000001B ;SET DOS BUSY BIT
MOV DOS_STAT,AH
PUSHF ;SIMULATE AN INTERRUPT
CALL OLDINT21 ;DO THE DOS FUNCTION
PUSHF ;SAVE THE RESULT FLAGS
AND BUSY_FLAGS,11111110B ;CLEAR DOS BUSY BIT
CMP 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
RET 2 ;RETURN WITH DOS RESULT FLAGS
NEWINT21 ENDP
;---------------------------------------------------------------------;
; NEW INTERRUPT 24H (CRITICAL DOS ERROR). THIS INTERRUPT IS ONLY IN ;
; EFFECT ONLY DURING A WRITE SCREEN. IT IS REQUIRED TO SUPPRESS THE ;
; 'ABORT, RETRY, IGNORE' MESSAGE. ALL FATAL DISK ERRORS ARE IGNORED. ;
;---------------------------------------------------------------------;
NEWINT24 PROC FAR
ASSUME CS:CSEG, DS:NOTHING, ES:NOTHING
STI ;TURN INTERRUPTS BACK ON
INC ERR_STAT ;SET THE ERROR FLAG
XOR AL,AL ;TELLS DOS TO IGNORE THE ERROR
IRET ;THATS ALL WE DO HERE
NEWINT24 ENDP
;--------------------------------------------------------------------;
; HERE IS THE CODE USED TO INITIALIZE SNIPPER. ;
;--------------------------------------------------------------------;
ASSUME CS:CSEG, DS:CSEG, ES:CSEG
INITIALIZE:
LEA DX,COPYRIGHT
MOV AH,9 ;DOS DISPLAY STRING SERVICE
INT 21H ;DISPLAY TITLE MESSAGE
; SEARCH FOR AN PREVIOUSLY INSTALLED COPY OF SNIPPER
NOT BYTE PTR START ;MODIFY TO AVOID FASLE 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
LEA SI,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
LEA DX,INSTALLED_MSG
JMP SHORT ERR_EXIT
NOT_INSTALLED:
MOV AH,30H
INT 21H ;GET DOS VERSION NUMBER
CMP AL,2 ;IS IT HIGHER THAN 2.0?
JAE VER_OK ;IF YES, PROCEED
LEA DX,BAD_DOS_MSG
ERR_EXIT: MOV AH,9 ;DOS DISPLAY STRING SERVICE
INT 21H ;DISPLAY ERRER MESSAGE
RET ;RETURN TO DOS
VER_OK:
INC SI ;POINT TO FIRST PARAMETER
MOV SI,81H ;POINT TO PARAMETER AREA
CALL GET_PARAM ;GET FIRST PARAMETER (ROWS)
PUSH AX ;SAVE THE ROW COUNT
CALL GET_PARAM ;GET SECOND PARAMETER (COLUMNS)
ADD AX,2 ;ADD SPACE FOR CR AND LF
POP BX ;GET BACK FIRST PARAMETER
MUL BX ;PRODUCT OF ROWS AND COLUMNS
OR AX,AX ;WAS ANYTHING ENTERED?
JZ NO_PARAMS ;IF NOT, USE DEFAULT VALUE
CMP AX,10000 ;MAXIMUM BUFFER IS 10000 BYTES
JLE SIZE_IS_OK
MOV AX,10000
SIZE_IS_OK:
ADD AX,BUFF_START
MOV BUFF_END,AX ;SET THE NEW BUFFER SIZE
NO_PARAMS:
MOV AX,BIOS_SEG ;LOOK AT BIOS DATA AREA
MOV ES,AX
ASSUME ES:BIOS_SEG
CMP ROWS,0 ;IS NUMBER OF ROWS ENTERED HERE
JNE MUST_BE_EGA ;IF YES, AN EGA MAY BE PRESENT
MOV ROWS,24 ;IF NOT EGA, MUST BE 24 ROWS
MUST_BE_EGA:
ASSUME ES:NOTHING
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 SEGMENT
MOV WORD PTR [OLDINT13+2],ES ;SAVE 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 SEGMENT
MOV WORD PTR [OLDINT16+2],ES ;SAVE 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. ;
; EXIT USING INT 27H. LEAVE CODE AND SPACE FOR 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,BUFF_END ;LEAVE THIS MUCH RESIDENT
INT 27H ;TEMINATE AND STAY RESIDENT
;---------------------------------------------------------;
; GET_PARAM RETRIEVES AN INTEGER FROM THE COMMAND LINE. ;
;---------------------------------------------------------;
GET_PARAM: XOR AX,AX ;CLEAR AX FOR TOTAL
GET_DIGIT: MOV BL,[SI] ;GET CHARACTER INTO BL
CMP BL,0DH ;IS IT THE LAST ONE?
JE DONE
INC SI ;POINT TO NEXT CHARACTER
CMP BL,"," ;IS IT THE DELIMITER?
JE DONE
SUB BL,30H ;CONVERT ASCII TO INTEGER
JC GET_DIGIT ;IS IT A VALID DIGIT
CMP BL,9
JA GET_DIGIT ;IF NOT VALID, JUST SKIP IT
MOV BH,10 ;TIMES 10 FOR NEXT DIGIT
MUL BH ;MULTIPLY SUM AND ADD THIS DIGIT
ADD AL,BL ;ADD DIGIT TO SUM
JMP GET_DIGIT ;READ ALL CHARACTERS ON LINE
DONE: RET
CSEG ENDS
END START