home *** CD-ROM | disk | FTP | other *** search
- page 60,132
- ; SNIPPER by Tom Kihlken
- ;
- ; Copyright (c) 1987 by Ziff Communications Co.
- ; PC Magazine 1987: Vol 6/No. 19, October 27, 1987 (Utilities)
- ;
- ; 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 cursor pad keys,(i.e.,arrows plus Home, End, PgUp v2.3
- ; and PgDn). Press CR to fix the first corner, v2.3
- ; 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 its internal buffer for displays (such as the
- ; EGA) containing more than the standard 25 rows and 80 columns.
- ; SNIPPER [rows,columns]
-
- ; Version 1.0 - as published.
- ; Version 1.1 - corrects a bug in the INT 21 interrupt routine.
- ; Version 1.2 - runs correctly on the AT&T 6300
- ; Version 2.0 - 6/22/88 allow "R" to go to Right Edge. Jim Turner 71560,3452
- ; Version 2.1 - 10/30/88 suggestions from Tom K. Jim Turner 71560,3452
- ; Version 2.2 - 01/25/90 Consolidated. Tim Farley, Atlanta, GA
- ; (Turner's revisions did not include all of Kihlken's
- ; published fixes, and he untabified the file).
- ; Added support for Expanded 101/102 key keyboard.
- ; Added scan code to RETURN--some programs check the scan
- ; code, so it needs to be there so RETURN will be processed.
- ; Moved patch locations to fixed spot at 17F and 18F.
- ; Removed call to INT 16 *inside* INT 9 (yikes!).
- ; Made sure all changes since published version are notated.
- ;
- ;v2.2a 19 May 90 Toad Hall Tweak
- ; - A few CS: overrides just to keep things clear
- ; - Replaced LEA's with "mov reg,offset" (faster)
- ; - Added envseg as a variable at CS:002CH
- ;
- ; Version 2.3 - Cursor Pad Keys(Home,End,PgUp,PgDn) added by T.Gentile
- ; New & Modified Lines have V2.3 Suffix in Columns 75-78
- ;
- ;v2.4 14 Mar 91 Toad Hall Tweak
- ; - Got a request for trailing space trimming. Done.
- ; - Request to consolidate v2.3 code (but keep v2.2+ fixes).
- ; - Request to eliminate direct screen writes (conflict with
- ; speech synthesizers, DeskView).
- ; That's easy to do: there are NO direct screen writes!
- ; Everything is via the BIOS.
-
- ;------------------------------------
- ; BIOS_SEG IS THE ROM-BIOS DATA AREA
- ;------------------------------------
- BIOS_SEG SEGMENT AT 0040H
- ORG 0017H ;[TF]
- kb_flag DB ? ;CURRENT SHIFT STATE ;[TF]
- 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
- bios_rows DB ? ;LAST ROW NUMBER FOR EGA
- BIOS_SEG ENDS
-
- CSEG SEGMENT
- ASSUME CS:CSEG,DS:NOTHING
-
- org 2CH ;v2.2a
- envseg label word ;Environment segment v2.2a
-
- ORG 100H ;BEGINNING FOR .COM PROGRAMS
- Start: JMP Initialize ;INITIALIZATION CODE IS AT END
-
- ;--------------------------------
- ; DATA AREA USED BY THIS PROGRAM
- ;--------------------------------
- copyright DB "SNIPPER 2.4 (c) 1987 Ziff Communications Co."
- DB 13,10,"PC Magazine ",254," Tom Kihlken"
- DB 13,10,"Hotkey is ALT-W",13,10,"$",1AH
- DB 17 DUP (0) ;room to patch hot key name [TF]
-
- DB "KEY SCAN CODE->" ;alert snoops to patch [TF]
- hotkey DB 11H ;SCAN CODE FOR "W" KEY [TF]
- DB "SHIFT MASK---->" ;alert snoops to patch [TF]
- shift_mask DB 00001000B ;MASK FOR ALT KEY [TF]
- ;
- installed$ DB "Already Installed",13,10,"$"
- bad_dos$ DB "Requires DOS 2.0+",13,10,"$"
- file_prompt DB "Enter Filename: "
- filename DB "SCREEN.CUT" ;THE DEFAULT FILENAME
- DB 15 DUP (0) ;LEAVE ROOM FOR DRIVE AND PATH
-
- EVEN ;v2.4
- 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
- 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
-
- 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
- err_stat DB ? ;ERROR STATUS DURING FILE OUTPUT
- dos_stat DB 0 ;CURRENT DOS FUNCTION
- end_flag DB 0 ;"END" Key Pressed =1 V2.3
- pgdn_flag DB 0 ;"PGDN" Key Pressed =1 V2.3
- home_flag DB 0 ;"HOME" Key Pressed =1 V2.3
- pgup_flag DB 0 ;"PGUP" Key Pressed =1 V2.3
- scrn_rows DB ? ;real screen rows [TK]
-
- 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
-
- MOV scrn_rows,24 ;DEFAULT NUMBER OF ROWS ;[TK]
- MOV AH,12H ;[TK]
- MOV BL,10H ;GET EGA INFO ;[TK]
- INT 10H ;[TK]
- CMP BL,10H ;DID BL CHANGE? ;[TK]
- JE Not_Ega ;IF NO, EGA IS NOT PRESENT ;[TK]
- TEST BYTE PTR ES:[00087H],8 ;IS EGA ACTIVE? ;[TK]
- JNZ Not_Ega ;[TK]
- MOV AL,bios_rows ;[TK]
- MOV scrn_rows,AL ;[TK]
- Not_Ega: ;[TK]
- 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
- FORCE_RIGHT: MOV DL,crt_cols ;JUMP TO THE RIGHT EDGE V2.3
- DEC DL
- Not_Left_Edge:
- CMP DL,crt_cols ;AT RIGHT EDGE OF SCREEN YET?
- JB Not_Right_Edge ;IF NOT, KEEP MOVING RIGHT
- FORCE_LEFT: XOR DL,DL ;IF YES, WRAP TO LEFT EDGE V2.3
- Not_Right_Edge:
- CMP DH,0 ;AT TOP OF SCREEN YET?
- JGE Not_At_Top
- FORCE_BOTTOM: MOV DH,scrn_rows ;JUMP DOWN TO THE BOTTOM V2.3
- Not_At_Top:
- CMP DH,scrn_rows ;AT BOTTOM OF SCREEN? ;[TK]
- JLE Not_At_Bottom
- FORCE_TOP: XOR DH,DH ;JUMP BACK TO THE TOP V2.3
- 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
-
- CMP AH,47H ;IS IT HOME KEY? V2.3
- JE FORCE_LEFT ;JUMP TO LEFT SCREEN EDGE V2.3
- CMP AH,49H ;IS IT PGUP KEY? V2.3
- JE FORCE_TOP ;JUMP TO TOP SCRREN EDGE V2.3
- CMP AH,4FH ;IS IT END KEY? V2.3
- JE FORCE_RIGHT ;JUMP TO RIGHT SCREEN EDGE V2.3
- CMP AH,51H ;IS IT PGDN KEY? V2.3
- JE FORCE_BOTTOM ;JUMP TO BOTTOM SCREEN EDGE V2.3
-
- 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, THEN 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 ax,ax ;handy 0, AH=0 v2.4
- MOV end_flag,al ; CLEAR END FLAG V2.3,4
- MOV pgdn_flag,al ; CLEAR PGDN FLAG V2.3,4
- MOV home_flag,al ; CLEAR HOME FLAG V2.3,4
- MOV pgup_flag,al ; CLEAR PGUP FLAG V2.3,4
- ;v2.4 done XOR AH,AH
- INT 16H ;GET A KEYSTROKE
- Got_Key2: MOV DX,bot_right
- CMP AH,4BH ;IS IT LEFT ARROW? v2.3
- JE Sub_Col ;SUBTRACT A COLUMN FROM WINDOW v2.3
- CMP AH,4DH ;IS IT RIGHT ARROW? v2.3
- JE Add_Col ;ADD A COLUMN TO THE WINDOW v2.3
- CMP AH,4FH ;IS IT "END"? V2.3
- JE Got_End ;GO TO RIGHT EDGE OF SCREEN V2.3
- CMP AH,51H ;IS IT "PGDN"? V2.3
- JE Got_PgDn ;GO TO BOTTOM EDGE OF SCREEN V2.3
- CMP AH,47H ;IS IT "HOME"? V2.3
- JE Got_Home ;GO TO LEFT EDGE OF WINDOW V2.3
- CMP AH,49H ;IS IT "PGUP"? V2.3
- JE Got_PgUp ;GO TO TOP EDGE OF WINDOW V2.3
-
- 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
- JMP Not_Arrow_Key
-
- Got_Home: MOV home_flag,1 ;"HOME" KEY PRESSED V2.3
- Sub_Col:
- MOV DX,bot_right ;2ND CORNER COORDS V2.3
- 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
-
- Got_End: MOV end_flag,1 ;"END" KEY PRESSED V2.3
-
- Add_Col:
- MOV DX,bot_right ;2ND CORNER COORDS V2.3
- 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
- CMP end_flag,1 ;IF "END", REPEAT TO RIGHT EDGE V2.3
- JE Add_Col ;ADD ANOTHER COLUMN V2.3
- CMP home_flag,1 ;IF "HOME", REPEAT TO LEFT EDGE V2.3
- JE Sub_Col ;REMOVE ANOTHER COLUMN V2.3
- Get_Kb_K2_Jmp: JMP Get_Kb_Key2 ; V2.3
-
- Got_PgUp: MOV pgup_flag,1 ;"PGUP" KEY PRESSED V2.3
- Sub_Row:
- MOV DX,bot_right ;2ND CORNER COORDS V2.3
- DEC DH
- CMP DH,top_row ;AT TOP OF WINDOW?
- JL Get_Kb_K2_Jmp ;DONT ERASE IT COMPLETELY v2.3
- MOV bot_row,DH
- INC DH
- JMP SHORT Row_Loop
-
- Got_PgDn: MOV pgdn_flag,1 ;"PGDN" KEY PRESSED V2.3
- Add_Row:
- MOV DX,bot_right ;2ND CORNER COORDS V2.3
- INC DH
- CMP DH,scrn_rows ;AT BOTTOM OF SCREEN? [TK]
- JG Get_Kb_K2_Jmp ;STOP WHEN SCREEN IS FILLED v2.3
-
- 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
- CMP pgdn_flag,1 ;IF "PGDN", REPEAT TO BOTTOM EDGE V2.3
- JE Add_Row ;ADD ANOTHER ROW V2.3
- CMP pgup_flag,1 ;IF "PGUP", REPEAT TO TOP EDGE V2.3
- JE Sub_Row ;REMOVE ANOTHER ROW V2.3
-
- 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 ;next procedure is 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
- ;*********************************************************************
- ;v2.4 Let's do our trailing space trimming here
- ; Old code:
-
- Read_Window:
- MOV DX,top_left ;GET LOCATION OF FIRST CORNER
- Read_Loop:
- xor si,si ;init space counter
- ReadR_Loop:
- CALL Rev_Video ;PUT ATTRIBUTE BACK TO NORMAL
- CALL Read_Char ;READ THE CHARACTER (returned in AL)
- cmp al,' ' ;space?
- jnz NonSpace ;nope
- inc si ;yep, bump counter
- jmp short Skip_Space ;skip, don't send it
-
- ;We've hit a non-space char. If there are any accumulated spaces,
- ;we must send them now.
- NonSpace:
- or si,si ;any unsent spaces accrued?
- jz No_SpaceCnt ;nope, send this char
-
- push ax ;save this char
- Space_Loop:
- mov al,' ' ;space to [send_char]
- call [send_char] ;call to the pointer
- dec si ;count down
- jnz Space_Loop ;send all accrued spaces
-
- pop ax ;restore original non-space char
- No_SpaceCnt:
- call [send_char] ;call to the pointer
- Skip_Space:
- inc dl ;next char in row
- cmp dl,right_side ;at the right border yet?
- jle ReadR_Loop ;nope, do all chars in this row
-
- ;If there are any accumulated spaces, they're trailing spaces
- ;and we can ignore them.
-
- 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 ;new send_char function
- 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 ;new send_char function
- Buff_Ok:
- RET ;NOW IT'S 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
- Get_Ret: ;handy return v2.4
- RET
- ;*********************************************************************
- Exchange_Help:
- XOR DX,DX ;START AT TOP LEFT CORNER
- mov si,offset help_menu ;v2.2a
- 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?
- ;v2.4 JL Swap_Char ;QUIT WHEN LAST ROW IS DONE
- ;v2.4 RET
- jnl Get_Ret ;quit when last row is done v2.4
- 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:
- mov si,offset file_prompt ;point to prompt for source v2.2a
- 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 ;0, 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
- xor al,al ;WRITE A NORMAL BLANK (ASCII 0) v2.2a
- 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
- mov di,offset file_prompt ;copy to filename v2.2a
- 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 CS:writ_file,0 ;TURN OFF REQUEST FLAG v2.2a
- PUSH AX ;MUST PRESERVE ALL REGISTERS
- PUSH BX
- PUSH CX
- PUSH DX
- PUSH DS
- PUSH ES
- mov ax,CS ;larger than push/pop v2.2a
- mov DS,ax ;.. but much faster v2.2a
- 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
- 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?
- ;v2.2a JNE Rep_Vector ;IF SEVERE ERROR, JUST QUIT
- ;v2.2a JMP SHORT Close_File;JUST CLOSE THE FILE
- jz Close_File ;no error, just close file v2.2a
- jmp short Rep_Vector ;if severe error, quit v2.2a
-
- 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,CS:[hotkey] ;IS IT THE HOT KEY? [TF]
- JE Trigger ;IF YES, CHECK THE MASK
- Int09_Exit: POP AX ;RESTORE THE PROCESSOR STATE
- JMP CS:oldint09 ;CONTINUE WITH ROM ROUTINE v2.2a
-
- Trigger:
- PUSH DS ;[TF]
- MOV AX,BIOS_SEG ;ES POINTS TO BIOS DATA AREA ;[TF]
- MOV DS,AX ;[TF]
- ASSUME DS:BIOS_SEG ;[TF]
- MOV AL,kb_flag ;GET KEYBOARD STATUS FROM BIOS ;[TF]
- POP DS ;[TF]
- ASSUME DS:NOTHING ;[TF]
-
- AND AL,0FH ;Take lower four bits
- CMP AL,CS:[shift_mask] ;IS ALT KEY DOWN? [TF]
- JNZ Int09_Exit ;IF NOT, IGNORE IT
- TEST CS:busy_flags,00000100B ;IS Snipper ALREADY ACTIVE? v2.2a
- JNZ Int09_Exit ;IF ACTIVE, THEN EXIT
-
- OR CS:busy_flags,00000100B ;IT'S ACTIVE NOW v2.2a
- PUSHF ;fake interrupt
- CALL CS:oldint09 ;LET ROM PROCESS THE KEY v2.2a
- PUSH BX ;MUST PRESERVE ALL REGISTERS
- PUSH CX
- PUSH DX
- PUSH BP
- PUSH SI
- PUSH DI
- PUSH DS
- PUSH ES
- mov ax,CS ;set DS to CSEG v2.2a
- mov DS,ax ;larger, but faster v2.2a
- 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 CURSOR POSITION
- 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 BUSY BIT
- ;---------------------------------------------------------------------
- NewInt13 PROC FAR
- ASSUME DS:NOTHING, ES:NOTHING
-
- OR CS:busy_flags,00000010B ;SET BIOS BUSY BIT v2.2a
- PUSHF ;fake interrupt
- CALL CS:oldint13 ;DO THE BIOS FUNCTION v2.2a
- PUSHF ;SAVE RESULT FLAGS
- AND CS:busy_flags,11111101B ;CLEAR BIOS BUSY BIT v2.2a
- 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 CS:send_keys,1 ;SENDING KEYS FROM BUFFER? v2.2a
- JE Insert_Key ;IF YES, THEN GET NEXT ONE
- CMP CS:writ_file,1 ;ANYTHING TO WRITE TO DISK? v2.2a
- JE Check_Dos_Stat ;IF YES, THIS IS THE TIME
- Bios_Kb:
- POP BX
- JMP CS:oldint16 ;JUST DO NORMAL KB ROUTINE v2.2a
-
- Check_Dos_Stat:
- CMP CS:dos_stat,0AH ;DOING READ STRING? v2.2a
- JE Begin_Now ;IF YES, IT'S SAFE TO BEGIN
- CMP CS:dos_stat,8 ;DOING KEYBOARD INPUT? v2.2a
- JNE Bios_Kb ;IF YES, IT'S 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,CS:buff_next ;GET ADDRESS OF NEXT BYTE v2.2a
- CMP BX,CS:buff_last ;AT END OF BUFFER YET? v2.2a
- JL Get_A_Key ;IF NOT, GET THE NEXT ONE
- MOV CS:send_keys,0 ;WHEN DONE, TURN OFF SEND SWITCH v2.2a
- 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 CS:buff_next ;SKIP TO NEXT KEY v2.2a
- JMP Insert_Key
-
- Not_Lf:
- CMP AH,1 ;REQUEST FOR STATUS ONLY?
- JE Return_Status ;IF YES, RETURN STATUS ONLY
- CMP AH,11H ;Request for ENHANCED status? [TF]
- JE Return_Status ;If yes, return that status [TF]
- or ah,ah ;request to get the next key? v2.2a
- JE Return_Key ;If yes, return that key [TF]
- CMP AH,10H ;Get key on ENHANCED keyboard? [TF]
- JNE Bios_Kb ;IF NOT, IGNORE THIS FUNCTION
- Return_Key: ;[TF]
- INC BX ;REMOVE THIS KEY FROM OUR BUFFER
- MOV CS:buff_next,BX ;SAVE THE POINTER TO NEXT KEY v2.2a
- Return_Status:
- CMP AL,0DH ;Is this a Carriage Return? [TF]
- JNE Next_Key1 ;Nope, just pass it. [TF]
- MOV AH,01CH ;Put in proper scan code for CR [TF]
- JMP short Next_Key2 ;And send it v2.2a
- Next_Key1: ;[TF]
- XOR AH,AH ;Scan code of zero [TF]
- Next_Key2:
- 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
-
- PUSHF ;SAVE ENTRY FLAGS ;[TK]
-
- STI ;ALLOW INTERRUPTS
- CMP AH,4BH ;IF EXEC ;[TK]
- JNE Not_Exec ;[TK]
- POPF ;[TK]
- JMP CS:oldint21 ;GO DIRECT ;[TK]
-
- Not_Exec:
- OR AH,AH ;DOING FUNCTION ZERO?
- JNE Not_Zero
- MOV AH,4CH ;IF YES, CHANGE IT TO A 4CH
- Not_Zero:
- OR CS:busy_flags,00000001B ;SET DOS BUSY BIT v2.2a
- MOV CS:dos_stat,AH ; v2.2a
- POPF ;RESTORE ORIGINAL FLAGS ;[TK]
- PUSHF ;SIMULATE AN INTERRUPT
- CALL CS:oldint21 ;DO THE DOS FUNCTION
- PUSHF ;SAVE THE RESULT FLAGS
- AND CS:busy_flags,11111110B ;CLEAR DOS BUSY BIT v2.2a
- CMP CS:writ_file,1 ;ANYTHING TO WRITE TO DISK? v2.2a
- JNE No_Write ;IF NOT JUST RETURN
- CALL Write_To_File ;SAFE TO ACCESS DISK NOW
- No_Write:
- POPF ;RECOVER DOS RESULT FLAGS ;[TK]
- STI ;[TK]
- 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 CS:err_stat ;SET THE ERROR FLAG v2.2a
- 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:
- mov dx,offset copyright ; v2.2a
- 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
- mov si,offset Start ;setup to compare strings v2.2a
- 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$ ;'Already installed' v2.2a
- 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
- mov dx,offset bad_dos$ ;'Requires DOS 2.0' v2.2a
- Err_Exit: MOV AH,9 ;DOS DISPLAY STRING SERVICE
- INT 21H ;DISPLAY ERROR MESSAGE
- RET ;RETURN TO DOS
-
- Ver_Ok:
- ;v2.4 dumb 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:
- ;
- ; EGA check here was removed & code was added to popup routine (1.2) ;[TK]
- ;
- 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 ;change int 9 vector
- INT 21H
-
- 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 ;set new Int 13H vector
- INT 21H
-
- 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 ;set new Int 16H vector
- INT 21H
-
- 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 ;set new Int 21H vector
- INT 21H
-
- ;--------------------------------------------------------------------
- ; DEALLOCATE OUR COPY OF THE ENVIRONMENT.
- ; EXIT USING INT 27H. LEAVE CODE AND SPACE FOR BUFFER RESIDENT.
- ;--------------------------------------------------------------------
-
- mov ES,envseg ;get segment of environment v2.2a
- 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