page 60,132 MASM ; This is a modification of the programme described below (SNIPPER). ; 0.0.1 gets all chars on lines between point 1 and point 2 ; 0.0.2 allows the use of HOME and END keys to move around the screen. ; 0.0.3 allows hitting ESC key in filename prompt for entering ; completely new file name. ; 0.0.4 fixed bug in ESC key during filename entry. If esc hit and ; then return, will exit without saving to file. if ESC hit ; then chars entered for new filename, will print to file. ; 0.0.5 added new option when writing to file. Entering F will now ; strip out all multiple spaces and any pipes, as well as will ; put 2 spaces after any punctuation. Old write to file ; (unformatted) is now option "U" ; 0.0.6 fixed problem with help box not displaying all options and ; correctly formatting the box. ; 0.0.7 fixed help box display so that it is uses it's own character ; attributes, and restores original attribute upon exit. ; 0.0.8 Added colour to Help Box. Unsure if will work with mono ; 0.0.9 gets filename from first 8 chars or from first char to period, ; of first line of highlight, + .RTT. Refuses all chars which ; filenames can not contain. ; 0.1.0 checks for mono display adapter. if present, displays mono ; help. ; 0.1.1 Modified display of copyright notice. ; 0.1.2 Added use of INS key when moving to top_left position. Hitting ; INS will move the cursor to the 34th column, which is the ; standard starting space for file descriptions on PCB/ProDoor BBSs ; 0.1.3 Fixed problem with getting filename, and hitting ESC. Now ; resets filechar flag so that if used again after hitting esc, ; or entering a new filename, will now find new filename. ; Also, fills out full space for filename with 0H after each ; filename. Previously, if the new filename was shorter than ; the last one entered, there would be residual chars. ; 0.1.4 Fixed problem with underscore as part of a filename. Had ; accidently included it in the list of chars not acceptable. ; 0.1.5 Fixed highlighting problem associated with reading filenames ; of 8 chars + ext. ; 0.1.6 Program sends "fl filename.ext" to keyboard buffer, for file ; flagging on BBS. ; 0.1.7 Pruned program of unused or unnecessary functions relating to ; SNIPPER ; 0.1.8 Extended total filename size to a maximum of 50 chars for ; large paths. ; 0.1.9 Fixed problem with using the program multiple ; times. Wouldn't write more than one file nor would it spit ; out more then "F" on the second use in the file flag section. ; 0.2.0 Reduced Maximum filename length to 12 places in anticipation of ; the use of a path statement on the command line to be added in ; an upcomming version. ; 0.2.1 Added use of pathname on command line. Path statement will ; now be /P=path. Command line must be eithe filesnip by itself ; or filesnip rows,cols,/P=path ; 0.3.0 No modifications - Found no bugs ; 0.4.0 No modifications - Found no bugs ; 0.5.0 No modifications - Found no bugs ; 0.6.0 No modifications - Found no bugs ; 0.7.0 No modifications - Found no bugs ; 0.8.0 No modifications - Found no bugs ; 0.9.0 No modifications - Found no bugs ; 1.0.0 Initial Release - 6 June 1990 ; 1.0.1 Made use of path statement flag on command line non-case ; sensitive. ; 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 CTL-~, 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 29H ;SCAN CODE FOR "~" KEY SHIFT_MASK EQU 00000100B ;MASK FOR CTL KEY COPYRIGHT DB 17 DUP(20H),214,44 DUP(196),183 DB 13,10,17 DUP(20H),186,44 DUP(20H),186 DB 10,13,17 DUP(20H),186," File-SNIP 1.0.1 (c) 1990 Mad Monk Software ",186 DB 10,13,17 DUP(20H),186,44 DUP(20H),186 DB 10,13,17 DUP(20H),186,44 DUP(20H),186 DB 10,13,17 DUP(20H),186,7,14 DUP(20H),"Hotkey is CTL-~",7,15 DUP(20H),186 DB 10,13,17 DUP(20H),186,44 DUP(20H),186 DB 10,13,17 DUP(20H),211,44 DUP(196),189,13,10,"$",1AH PROGRAMMER DB "File-SNIP: Scott Penrose. SNIPPER: 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 PATH_N_FILE DB 128 DUP (0) FILE_PATH DB 114 DUP (0) FILE_PROMPT DB "Enter Filename: " FILENAME DB "FILESNIP.RTT" ;THE DEFAULT FILENAME DB 2 DUP (0) ;LEAVE ROOM FOR DRIVE AND PATH BUFF_START EQU OFFSET INITIALIZE BUFF_NEXT DW BUFF_START ;POINTER TO NEXT KEY IN BUFFER BUFF_LAST DW BUFF_START ;POINTER TO LAST KEY IN BUFFER BUFF_SIZE EQU 25*(80+2) ;ROOM FOR 25 ROWS OF 80 COLUMNS BUFF_END DW BUFF_START+BUFF_SIZE FILE_BUFF_START EQU OFFSET INITIALIZE+BUFF_SIZE FILE_BUFF_NEXT DW FILE_BUFF_START ;POINTER TO NEXT KEY IN BUFFER FILE_BUFF_LAST DW FILE_BUFF_START ;POINTER TO LAST KEY IN BUFFER FILE_BUFF_SIZE EQU 12H ;18 bytes FILE_BUFF_END DW FILE_BUFF_START+FILE_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 FILE_SEND_CHAR DW ? ;POINTER TO CHARACTER HANDLER HOME_END_HIT LABEL WORD ;if=1 then home was hit HOME_END_LOOP DB 0 ;IF=1, then first time in loop SEND_KEYS DB 0 ;IF=1, USE KEYSTROKES FROM BUFFER FILE_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 SPACE_FLAG DB 0 ;Determine if space should be printed FILECHAR DB 0 ; FILE_EXT DB 0 CHARS_ON_STACK DB 0 ;How many chars have been printed PUNCT_FLAG DB 0 ;was any punctuation found? HELP_MENU DB 201,21 DUP(205),187 DB 186," F - File Formatted ",186 DB 186," P - Print ",186 DB 186," Esc- Quit ",186 DB 200,21 DUP(205),188 HELP_MENU_ATTR1 DB 23 DUP(4EH) ;ANSI menu DB 23 DUP(4EH) DB 23 DUP(4EH) DB 23 DUP(4EH) DB 23 DUP(4EH) HELP_MENU_ATTR2 DB 23 DUP(07H) ;ASCII menu DB 23 DUP(07H) DB 23 DUP(07H) DB 23 DUP(07H) DB 23 DUP(07H) ;------------------------------------------------------------------; ; 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,4FH ;IS IT END KEY? JE END_HIT ;jump to END_hit MOV BX,0001H ;INCREMENT TO ADD ONE COLUMN CMP AH,52H ;IS IT INS KEY? JE INS_HIT ;jump to PLUS_hit 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,47H ;Is it home key JE HOME_HIT ;jump to home_hit MOV BX,00FFH ;INCREMENT TO SUBTRACT ONE COLUMN CMP AH,4BH ;IS IT LEFT ARROW? JNE NOT_LEFT_ARROW JMP GET_KB_KEY1 NOT_LEFT_ARROW: 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: JMP GET_KB_KEY1 ;JUST GET ANOTHER KEY HOME_HIT: MOV DL,0 ;put cursor at beginning of line MOV BL,0 ; PUSH DX MOV DX,TOP_LEFT MOV DL,0H MOV TOP_LEFT,DX POP DX JMP GET_KB_KEY1 ;JUST GET ANOTHER KEY END_HIT: MOV BL,0H ;put cursor at end of line. MOV DL,0H ; PUSH DX MOV DX,TOP_LEFT MOV DL,4FH MOV TOP_LEFT,DX POP DX JMP GET_KB_KEY1 ;JUST GET ANOTHER KEY INS_HIT: MOV BL,0H ;put cursor at 34th column MOV DL,0H ; PUSH DX MOV DX,TOP_LEFT MOV DL,21H MOV TOP_LEFT,DX POP DX JMP GET_KB_KEY1 ;JUST GET ANOTHER KEY GET_KB_KEY2: MOV HOME_END_HIT,0000H ;clear flag for home/end key XOR AH,AH INT 16H ;GET A KEYSTROKE GOT_KEY2: MOV DX,BOT_RIGHT CMP AH,48H ;IS IT UP ARROW? JNE NEXT_1 JMP SUB_ROW_1 ;SUBTRACT A ROW FROM WINDOW NEXT_1: CMP AH,50H ;IS IT DOWN ARROW? JNE NEXT_2 JMP ADD_ROW_1 ;ADD A ROW TO THE WINDOW NEXT_2: CMP AH,4DH ;IS IT RIGHT ARROW? JNE NEXT_3 JMP ADD_COL ;ADD A COLUMN TO THE WINDOW NEXT_3: CMP AH,4BH ;IS IT LEFT ARROW? JNE NEXT_4 JMP SUB_COL ;SUBTRACT A COLUMN FROM WINDOW NEXT_4: CMP AH,47H ;is it home key. JNE NEXT_5 MOV HOME_END_HIT,0001H MOV HOME_END_LOOP,01H JMP SUB_COL NEXT_5: CMP AH,4FH ;is it end key? JNE NEXT_6 MOV HOME_END_HIT,0100H JMP ADD_COL NEXT_6: JMP NOT_ARROW_KEY SUB_COL: CMP DH,TOP_ROW JG OK_GO_BACK CMP DL,LEFT_SIDE ;DONT ERASE IT COMPLETELY JLE GET_KB_KEY2 OK_GO_BACK: CMP DL,0 ;DONT ERASE IT COMPLETELY JLE GET_KB_KEY2 DEC DL ;SUBTRACT A COLUMN MOV RIGHT_SIDE,DL ;SAVE NEW RIGHT SIDE COLUMN INC DL DONT_INC_DL: JMP SHORT COL_LOOP ADD_COL: INC DL ;ADD A COLUMN CMP DL,CRT_COLS ;AT RIGHT EDGE OF SCREEN? JL ADD_COL_1 JMP GET_KB_KEY2 ;STOP WHEN SCREEN IS FILLED ADD_COL_1: MOV RIGHT_SIDE,DL ;SAVE NEW RIGHT SIDE COLUMN COL_LOOP: CMP HOME_END_HIT,0001H JZ COL_LOOP_1 CMP HOME_END_HIT,0100H JZ COL_LOOP_2 CALL REV_VIDEO ;REVERSE THIS CHARACTER JMP GET_KB_KEY2 COL_LOOP_1: CALL REV_VIDEO ;REVERSE THIS CHARACTER DEC DL JMP SUB_COL COL_LOOP_2: CALL REV_VIDEO ;REVERSE THIS CHARACTER JMP ADD_COL SUB_ROW_1: CMP DH,TOP_ROW ;AT TOP OF WINDOW? JG SUB_ROW_2 JMP GET_KB_KEY2 ;DONT ERASE IT COMPLETELY SUB_ROW_2: PUSH DX SUB_ROW: CALL REV_VIDEO DEC DL ;SUBTRACT A COLUMN CMP DL,0 ;DONT ERASE IT COMPLETELY JL SUB_ROW_PLUS JMP SUB_ROW SUB_ROW_PLUS: POP DX PUSH CX MOV CX,TOP_LEFT INC CH CMP CH,DH JE ON_SECOND_ROW JMP SUB_ROW_PLUS_1 ON_SECOND_ROW: CMP CL,DL JLE SUB_ROW_PLUS_1 MOV DL,CL MOV BOT_RIGHT,DX SUB_ROW_PLUS_1: POP CX DEC DH MOV BOT_ROW,DH PUSH DX SUB_ROW_PLUS_2: CMP DL,79 JGE AT_END INC DL CALL REV_VIDEO JMP SUB_ROW_PLUS_2 AT_END: POP DX JMP GET_KB_KEY2 ADD_ROW_1: CMP DH,ROWS ;AT BOTTOM OF SCREEN? JL ADD_ROW_1_1 JMP GET_KB_KEY2 ;STOP WHEN SCREEN IS FILLED ADD_ROW_1_1: PUSH DX ADD_ROW: CMP DL,79 JZ SKIP_INC INC DL CALL REV_VIDEO SKIP_INC: CMP DL,78 JG ADD_ROW_PLUS JMP ADD_ROW ADD_ROW_PLUS: POP DX CMP DH,ROWS ;AT BOTTOM OF SCREEN? JL NOT_BOT JMP GET_KB_KEY2 ;STOP WHEN SCREEN IS FILLED NOT_BOT: INC DH MOV BOT_ROW,DH ROW_LOOP: CALL REV_VIDEO ;REVERSE THIS CHARACTER DEC DL ;MOVE TO NEXT COLUMN CMP DL,0 ;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 FORMAT_OUTPUT NOT_P: MOV BUFF_NEXT,BUFF_START MOV BUFF_LAST,BUFF_START MOV FILE_BUFF_NEXT,FILE_BUFF_START MOV FILE_BUFF_LAST,FILE_BUFF_START MOV SEND_CHAR,OFFSET BUFF_CHAR CMP AH,21H ;IS IT THE "F" KEY JNE NOT_F MOV WRIT_FILE,0 MOV FILE_SEND_CHAR,OFFSET FILE_BUFF_CHAR CALL GET_FILENAME CMP WRIT_FILE,-1 ;WAS ESCAPE REQUESTED? JE ERASE_BOX CALL FORMAT_OUTPUT MOV WRIT_FILE,1 MOV FILE_SEND_KEYS,01H 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 FORMAT_OUTPUT 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 ;********************************************************************* ;---------------------------------------------------------------------; ; Proceedure to read char off screen, and send to file formatted. ; 11-05-90 12:15am ;---------------------------------------------------------------------; FORMAT_OUTPUT: PUSH AX PUSH BX PUSH CX PUSH DX MOV DX,TOP_LEFT ;GET LOCATION OF FIRST CORNER MOV SPACE_FLAG,00H MOV PUNCT_FLAG,00H MOV CHARS_ON_STACK,00H READ_LOOP_NEW: CALL REV_VIDEO CALL READ_CHAR CMP AL,20H JNE READ_LOOP_NEW_1 JMP WAS_SPACE READ_LOOP_NEW_1: CMP AL,7CH JNE NOT_PIPE JMP MOVE_TO_NEXT_CHAR NOT_PIPE: CMP AL,21H ;is it a "!" JNE NOT_PIPE_1 JMP PUNCT NOT_PIPE_1: CMP AL,2EH ;is it a "." JNE NOT_PERIOD JMP PUNCT NOT_PERIOD: CMP AL,3FH ;is it a "?" JNE NOT_QUESTION JMP PUNCT NOT_QUESTION: CMP AL,3AH ;is it a ":" JNE NOT_COLON JMP PUNCT NOT_COLON: CMP AL,3BH ;is it a ";" JNE NOT_SEMICOLON JMP PUNCT NOT_SEMICOLON: READ_NEW_1: CMP SPACE_FLAG,01 JE SPACE_SET CALL SEND_CHAR INC CHARS_ON_STACK MOVE_TO_NEXT_CHAR: CMP DH,BOT_ROW JE LAST_LINE_NEW INC DL CMP DL,79 JG MOVE_1 JMP READ_LOOP_NEW MOVE_1: CALL CR_LF MOV CHARS_ON_STACK,00H MOV SPACE_FLAG,00H MOV PUNCT_FLAG,00H INC DH MOV DL,0 CMP DH,BOT_ROW JG MOVE_3 JMP READ_LOOP_NEW MOVE_3: CALL REV_VIDEO LAST_LINE_NEW: INC DL CMP DL,RIGHT_SIDE JG LAST_LINE_NEW_1 JMP READ_LOOP_NEW LAST_LINE_NEW_1: CALL CR_LF POP DX POP CX POP BX POP AX RET SPACE_SET: CMP CHARS_ON_STACK,0 JE NO_PUNCT_FLAG PUSH AX MOV AX,0020H CALL SEND_CHAR POP AX INC CHARS_ON_STACK CMP PUNCT_FLAG,01H JNE NO_PUNCT_FLAG MOV PUNCT_FLAG,00H PUSH AX MOV AX,0020H CALL SEND_CHAR POP AX INC CHARS_ON_STACK CALL SEND_CHAR INC CHARS_ON_STACK MOV SPACE_FLAG,00H JMP MOVE_TO_NEXT_CHAR NO_PUNCT_FLAG: CALL SEND_CHAR INC CHARS_ON_STACK MOV SPACE_FLAG,00H JMP MOVE_TO_NEXT_CHAR PUNCT: CMP CHARS_ON_STACK,0 JNE PUNCT_1 JMP READ_NEW_1 PUNCT_1: MOV PUNCT_FLAG,01H JMP READ_NEW_1 WAS_SPACE: MOV SPACE_FLAG,01H JMP MOVE_TO_NEXT_CHAR ;********************************************************************* 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 ;********************************************************************* FILE_BUFF_CHAR: MOV BX,FILE_BUFF_LAST ;GET LOCATION OF LAST CHARACTER MOV [BX],AL ;PUT THE CHARACTER IN BUFFER INC BX ;ADVANCE THE POINTER MOV FILE_BUFF_LAST,BX ;CHECK FOR BUFFER FULL CMP BX,FILE_BUFF_END ;IS THE BUFFER FULL YET? JNE FILE_BUFF_OK ;IF NOT, KEEP GOING MOV FILE_SEND_CHAR,OFFSET RETURN FILE_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 PUSH DI LEA SI,HELP_MENU MOV AH,15 INT 10H CMP AL,7 JE MONO_HELP LEA DI,HELP_MENU_ATTR1 JMP EXCHANGE_LOOP MONO_HELP: LEA DI,HELP_MENU_ATTR2 EXCHANGE_LOOP: CMP DL,23 ;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,5 ;AT LAST ROW YET? JL SWAP_CHAR ;QUIT WHEN LAST ROW IS DONE POP DI RET SWAP_CHAR: CALL READ_CHAR ;READ CHARACTER AT THIS POSITION XCHG AL,CS:[SI] ;SWAP WITH THE HELP TEXT XCHG AH,CS:[DI] ;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 INC DI JMP EXCHANGE_LOOP ;********************************************************************* TEST_FILENAME_CHAR: CMP AL,2EH JE FILECHAR_1 CMP AL,20H JLE FILECHAR_1 CMP AL,22H JE FILECHAR_1 CMP AL,25H JE FILECHAR_1 CMP AL,2AH JE FILECHAR_1 CMP AL,2BH JE FILECHAR_1 CMP AL,2CH JE FILECHAR_1 CMP AL,2FH JE FILECHAR_1 CMP AL,3AH JE FILECHAR_1 CMP AL,3BH JE FILECHAR_1 CMP AL,3CH JE FILECHAR_1 CMP AL,3DH JE FILECHAR_1 CMP AL,3EH JE FILECHAR_1 CMP AL,7FH JGE FILECHAR_1 CMP AL,5BH JE FILECHAR_1 CMP AL,5CH JE FILECHAR_1 CMP AL,5DH JE FILECHAR_1 CMP AL,5EH JE FILECHAR_1 CMP AL,60H JE FILECHAR_1 CMP FILE_EXT,00H JE NOT_EXTEN CMP CL,04H JE FILECHAR_1 RET NOT_EXTEN: CMP CL,08H JE FILECHAR_1 RET FILECHAR_1: MOV FILECHAR,01 RET GET_FILENAME: PUSH BX PUSH AX MOV AX,0046H CALL FILE_SEND_CHAR MOV AX,004CH CALL FILE_SEND_CHAR MOV AX,0020H CALL FILE_SEND_CHAR POP AX PUSH DI PUSH SI MOV FILE_EXT,00H MOV FILECHAR,00H PUSH DX PUSH CX MOV CL,00H MOV DX,TOP_LEFT MOV DL,0 LEA SI,FILENAME GET_FILENAME_1: CALL READ_CHAR CALL TEST_FILENAME_CHAR CMP FILECHAR,00H JNE END_OF_FILENAME_1 CMP FILE_EXT,00H JNE FILE_EXTEN MOV CS:[SI],AL INC SI FILE_EXTEN: CALL FILE_SEND_CHAR INC DL INC CL JMP GET_FILENAME_1 END_OF_FILENAME_1: CMP CL,0 JE END_OF_FILENAME_A CMP FILE_EXT,01H JE AT_END_OF_FILENAME MOV FILECHAR,00H MOV FILE_EXT,01H JMP FILE_EXTEN AT_END_OF_FILENAME: MOV AL,0AH CALL FILE_SEND_CHAR MOV AL,0DH CALL FILE_SEND_CHAR MOV AL,2EH MOV CS:[SI],AL INC SI MOV AL,52H MOV CS:[SI],AL INC SI MOV AL,54H MOV CS:[SI],AL INC SI MOV AL,54H MOV CS:[SI],AL INC SI FILL_TO_END: CMP CL,0DH ; CMP CL,18H JE END_OF_FILENAME_A MOV AL,0H MOV CS:[SI],AL INC CL INC SI JMP FILL_TO_END END_OF_FILENAME_A: POP CX POP DX 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,29 ;USE MAX OF 40 CHARACTERS POP BX 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? JNE READ_KBDRD_2 MOV WRIT_FILE,-1 ;INDICATE ESCAPE IS REQUESTED READ_KBDRD_1: 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_KBDRD_1 READ_KBDRD_2: CMP AL,"." ;IS IT A VALID LETTER? JL READ_KB CMP AL,"z" ;IS IT A VALID LETTER? JG READ_KB CMP DL,28 ;ONLY ALLOW 40 CHARACTERS JGE READ_KB TTY_KEY: MOV WRIT_FILE,0 ;FIX ESCAPE HIT THEN CHARS. 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,29 ;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 POP SI POP DI 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 LEA SI,PATH_N_FILE PATH_N_FILE_LOOP: CMP BYTE PTR[SI],0 JE PNFL_DONE MOV BYTE PTR[SI],0 INC SI JMP PATH_N_FILE_LOOP PNFL_DONE: LEA DI,PATH_N_FILE LEA SI,FILE_PATH TRANSFER_PATH_N_FILE: CMP BYTE PTR[SI],0 JE TPNF_DONE PUSH BX MOV BL,[SI] MOV [DI],BL POP BX INC SI INC DI JMP TRANSFER_PATH_N_FILE TPNF_DONE: LEA SI,FILENAME ADD_FILENAME_LOOP: CMP BYTE PTR[SI],0 JE AFL_DONE PUSH BX MOV BL,[SI] MOV [DI],BL POP BX INC SI INC DI JMP ADD_FILENAME_LOOP AFL_DONE: MOV DX,OFFSET PATH_N_FILE ;POINT TO FILENAME ; 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 CTL 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 FILE_SEND_KEYS,1 ;SENDING KEYS FROM BUFFER? JE FILE_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 FILE_INSERT_KEY: STI ;INTERRUPTS BACK ON MOV BX,FILE_BUFF_NEXT ;GET ADDRESS OF NEXT BYTE CMP BX,FILE_BUFF_LAST ;AT END OF BUFFER YET? JL FILE_GET_A_KEY ;IF NOT, GET THE NEXT ONE MOV FILE_SEND_KEYS,0 ;WHEN DONE, TURN OFF SEND SWITCH FILE_GET_A_KEY: MOV AL,CS:[BX] ;GET THE NEXT KEY CODE CMP AL,10 ;IS IT A LINE FEED? JNE FILE_NOT_LF ;DONT RETURN THE LINE FEEDS INC FILE_BUFF_NEXT ;SKIP TO NEXT KEY JMP FILE_INSERT_KEY FILE_NOT_LF: CMP AH,1 ;REQUEST FOR STATUS ONLY? JE FILE_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 FILE_BUFF_NEXT,BX ;SAVE THE POINTER TO NEXT KEY FILE_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? JNE 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? JNB 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 EXIT_NON_TSR: MOV AH,4CH INT 21H 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? JE 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 CALL GET_PARAM ;--------------------------------------------------------------------; ; 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,FILE_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 CMP BL,"/" ;IS IT THE DELIMITER? JE GET_THE_PATH SUB BL,30H ;CONVERT ASCII TO INTEGER JB 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 GET_THE_PATH: MOV BL,[SI] CMP BL,50H JE PATH_FLAG_OK CMP BL,70H JNE DONE PATH_FLAG_OK: INC SI MOV BL,[SI] CMP BL,3DH JNE DONE INC SI LEA DI,FILE_PATH GET_THE_PATH_LOOP: MOV BL,[SI] CMP BL,0DH JE PATH_DONE MOV [DI],BL INC SI INC DI JMP GET_THE_PATH_LOOP PATH_DONE: MOV BYTE PTR[DI],5CH DONE: RET CSEG ENDS END START