home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
hypertxt
/
hs25.arc
/
PDBITS.LZH
/
SNIPPER.ASM
< prev
next >
Wrap
Assembly Source File
|
1989-02-26
|
27KB
|
1,004 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 UNTIL 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 lower 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