home *** CD-ROM | disk | FTP | other *** search
-
- ;------------------------------------------------------------------------------
- ; CUTPASTE.ASM
- ; Must be converted to a .COM file
- ;------------------------------------------------------------------------------
- ;
- ;---------------
- ;======= Equates
- ;---------------
- ;
- ;------- Window
- WNDW_HT EQU 25
- WNDW_WD EQU 80
- ;------- Scan codes -- hot keys
- CUT_KEY EQU 7000H ; Alt-Fn9
- PASTE_KEY EQU 6600H ; Ctl-Fn9
- ;------- Scan code -- mark key
- MARK_CHAR EQU 3B00H ; Fn1
- ;------- Scan codes -- cursor movement keys
- UP_ARROW EQU 4800H
- DOWN_ARROW EQU 5000H
- LEFT_ARROW EQU 4B00H
- RIGHT_ARROW EQU 4D00H
- CTL_RGT_ARW EQU 7400H ; Control-RightArrow
- CTL_LFT_ARW EQU 7300H ; Control-LeftArrow
- HOME_KEY EQU 4700H
- END_KEY EQU 4F00H
- TOP_PAGE EQU 4900H ; PageUp
- BOT_PAGE EQU 5100H ; PageDown
- ;------- Scan codes -- insert/delete keys
- CHAR_INS EQU 5200H
- DELETE EQU 5300H ; Delete (lower right)
- BACKSPACE EQU 0008H ; User rubout (^H) key
- LINE_INS EQU 000DH ; Enter
- DEL_TO_EOL EQU 4000H ; Fn6
- LINE_DEL EQU 4100H ; Fn7
- ;------- Scan codes -- carriage return
- CAR_RET1 EQU 000DH ; Carriage return (one byte)
- CAR_RET2 EQU 1C0DH ; Carriage return (two bytes)
- ;------- Characters and attributes
- BLANK EQU 0720H ; Define the blank character
- ATTR EQU 07H ; Default attribute (white on black)
- INV_ATTR EQU 70H ; Inverse of ATTR (black on white)
- ;
- ;
- ;======================================= Segment CODESEG
- ;
- COMSEG SEGMENT PARA PUBLIC 'CODE'
- ASSUME CS:COMSEG, DS:COMSEG, ES:COMSEG
- ORG 100H
-
- START LABEL NEAR
- JMP INSTALL
-
- ;-------------------------
- ;======= Data storage area
- ;-------------------------
- ;
- ;------- Copyright information
- COPYRITE DB 'Copyright Gerry Boyd, Larry Weiss, Randy Davis 1985 All Rights Reserved'
- DB '(214)238-9545'
- ;------- Buffer to hold screen contents
- SCRNSAVE DW ( WNDW_HT * (WNDW_WD+1) ) DUP(BLANK)
- ;------- Cursor location
- CURSOR_POS DW 0
- OLD_CUR_POS DW 0
- ;------- Old stack location
- SAVSTAKSP DW 0
- SAVSTAKSS DW 0
- ;------- Request type
- REQUEST LABEL WORD
- REQUEST0 DB 0
- REQUEST1 DB 0
- REQUEST2 DB 0
- ;------- Original keyboard request handler address
- OLDINT16 LABEL DWORD
- OLDINT16IP DW 0
- OLDINT16CS DW 0
- ;------- Define the confines of the window
- LEFT_MARG DB 0
- RIGHT_MARG DB 0
- TOP_MARG DB 0
- BOT_MARG DB 0
- ;------- Feed chars to application
- MARK DW -1 ; Flag used in character feed
- FEED_START DW 0 ; Address in buffer of begin...
- FEED_STOP DW 0 ; ...and end of feed
- FEED_END1 DW 0 ; Temp holding spot for beg feed addr
- FEED_END2 DW 0 ; Temp holding spot for end feed addr
- FEED_CHAR DW 0 ; Char to feed on this call
- ;------- Display segment
- DISPLAY_SEG DW 0
- ;------- Flag decribing movement of data between screen and buffer
- SWAP_SAVE DB 0
-
-
- ;-------------------
- ;======= Subroutines
- ;-------------------
-
- ASSUME CS:COMSEG, DS:COMSEG, ES:NOTHING
-
- ;======= Proc CALC_WINDOW
- ;
- ; Calculate window extremeties and store them in
- ; RIGHT_MARG, LEFT_MARG, TOP_MARG, BOT_MARG
- ;
- CALC_WINDOW PROC NEAR
- ;------- Find out video mode for calculating window size
- MOV AH,0FH
- INT 10H
- ;------- Save the video segment
- MOV CX,0B000H ; Assume monochrome
- CMP AL,7 ; Look for mode 7
- JZ CW100 ; Loop around if mono
- MOV CX,0B800H ; No, it's graphics
- CW100: MOV DISPLAY_SEG,CX
- ;------- Save window margins
- DEC AH ; Number of screen columns
- MOV RIGHT_MARG,AH
- MOV LEFT_MARG,0
- MOV TOP_MARG,0
- MOV BOT_MARG,WNDW_HT-1
- ;------- Exit
- RET
- CALC_WINDOW ENDP
-
-
- ;======= Proc WINDOW_SAVE
- WINDOW_SAVE PROC NEAR
- MOV SWAP_SAVE,0
- CALL WIN_SWP_SAV
- RET
- WINDOW_SAVE ENDP
-
-
- ;======= Proc WINDOW_SWAP
- WINDOW_SWAP PROC NEAR
- MOV SWAP_SAVE,0FFH
- CALL WIN_SWP_SAV
- RET
- WINDOW_SWAP ENDP
-
-
- ;======= Proc WIN_SWP_SAV
- ;
- ; When SWAP_SAVE=0, saves screen in buffer SCRNSAVE.
- ; When SWAP_SAVE=FF, exchanges contents of screen SCRNSAVE.
- ; This procedure does no BIOS calls -- all direct writes
- ;
- WIN_SWP_SAV PROC NEAR
- ;
- ;******* Setup for processing loop
- MOV CX,WNDW_HT ; Number of rows in window area
- MOV ES,DISPLAY_SEG ; Load up the video segment
- MOV SI,OFFSET SCRNSAVE ; Point SI at beginning of buffer
- XOR DI,DI ; DI indexes rows (lines)
- XOR BX,BX ; BX indexes columns (chars)
- ;
- ;******* Loop on lines
- WS050 LABEL NEAR
- MOV BL,LEFT_MARG ; Start on this line at left margin
- ;------- Process next character and attribute on line
- WS100: SHL BX,1 ; Change column number to byte pointer
- MOV AX,ES:[BX][DI] ; Get the next char/attr from screen
- XCHG AX,[SI] ; Store it and write saved char
- ADD SI,2 ; Move pointer over a word
- ;------- Perform swap/save check
- CMP SWAP_SAVE,0 ; Is this window swap or window save?
- JZ WS150 ; Loop around if a save
- MOV ES:[BX][DI],AX ; For swap, restore that char to screen
- ;------- Test for end of line
- WS150: SHR BX,1 ; Put byte offset back to col number
- INC BX
- CMP BL,RIGHT_MARG ; Are we beyond the end of the line?
- JNA WS100 ; No, branch and process next char
- ;------- Skip down to next line
- MOV [SI],CAR_RET2 ; So CRs are fed properly later
- ADD SI,2 ; Move pointer over a word
- SHL BX,1 ; Adjust DI by one line so that it...
- ADD DI,BX ; ...points to beginning of next line
- LOOP WS050
- ;
- ;******* Exit
- RET
- WIN_SWP_SAV ENDP
-
-
- ;======= Proc EDITOR
- ;
- ; Check for edit keys (such as Ins, Del, etc).
- ; If not one of those, assume its ASCII and insert it in the screen.
- ; Return when `cut' hotkey detected.
- ;
- EDITOR PROC NEAR
- ;
- ;******* Get a character and prepare for processing
- ED100 LABEL NEAR
- ;------- Read a character from the keyboard
- CALL GET_CHAR
- ;------- If character is ASCII, then null out scan code
- OR AL,AL
- JZ ED105
- XOR AH,AH
- ;------- Remove previous shading (if any)
- ED105: CALL UNSHAD_SCRN
- ;------- Place cursor position in BX (will become new cursor position)
- MOV BX,CURSOR_POS
- ;------- Check for and loop around if not `cut' hotkey pressed
- CMP AX,CUT_KEY
- JNZ ED120
- ;------- `Cut' hotkey pressed -- set termination conditions
- MOV MARK,-1
- MOV FEED_END1,0
- MOV FEED_END2,0
- ;------- Branch to end of routine
- JMP ED800
- ;
- ;******* Simple cursor movement keys
- ;------- Left arrow
- ED120: CMP AX,LEFT_ARROW
- JNZ ED140
- DEC BL
- JMP ED500
- ;------- Right arrow
- ED140: CMP AX,RIGHT_ARROW
- JNZ ED160
- INC BL
- JMP ED500
- ;------- Up arrow
- ED160: CMP AX,UP_ARROW
- JNZ ED180
- DEC BH
- JMP ED500
- ;------- Down arrow
- ED180: CMP AX,DOWN_ARROW
- JNZ ED185
- INC BH
- JMP ED500
- ;------- Home
- ED185: CMP AX,HOME_KEY
- JNZ ED190
- MOV BL,LEFT_MARG
- JMP ED500
- ;------- End
- ED190: CMP AX,END_KEY
- JNZ ED195
- MOV BL,RIGHT_MARG
- JMP ED500
- ;------- PageUp
- ED195: CMP AX,TOP_PAGE
- JNZ ED200
- MOV BH,TOP_MARG
- JMP ED500
- ;------- PageDown
- ED200: CMP AX,BOT_PAGE
- JNZ ED205
- MOV BH,BOT_MARG
- JMP ED500
- ;
- ;******* Control-RightArrow and Control-LeftArrow
- ;------- Check for Control-RightArrow and set increment
- ED205: CMP AX,CTL_RGT_ARW
- JNZ ED210
- MOV CL,1 ; Set increment to go forward
- JMP ED213
- ;------- Check for Control-LeftArrow and set increment
- ED210: CMP AX,CTL_LFT_ARW
- JNZ ED220
- CMP BL,LEFT_MARG
- JLE ED219
- MOV CL,-1 ; Set increment to go backward
- DEC BL ; Begin one char to left
- ;------- Get and save character at current position
- ED213: MOV DX,BX ; Use DX for cursor for READ_CHAR
- CALL READ_CHAR ; Get char at current position
- MOV CH,AL ; Save current char in CH
- ;------- Move one character location and check if margin violated
- ED215: ADD DL,CL ; Move over one character
- CMP DL,RIGHT_MARG ; Stop at left/right margins
- JGE ED218
- CMP DL,LEFT_MARG
- JLE ED218
- ;------- Test for change from space to non-space
- CALL READ_CHAR ; Read current character
- CMP CH,' ' ; Branch if original...
- JNZ ED216 ; ...was not a space
- CMP AL,' ' ; Is this a space?
- JZ ED215 ; Yes, branch and repeat
- JMP ED217 ; No, stop
- ;------- Test for change from non-space to space
- ED216: CMP AL,' ' ; Is this a space?
- JNZ ED215 ; No, branch and repeat
- ;------- If we were going towards left then move to the right by one char
- ED217: CMP CL,-1
- JNZ ED218
- ADD DL,1
- ;------- Place new cursor position in BX
- ED218: MOV BX,DX
- ;------- Branch to end of key processing loop
- ED219: JMP ED500
- ;
- ;******* Erase remainder of line
- ;------- Test for, and go to next case if not, DEL_TO_EOL key
- ED220: CMP AX,DEL_TO_EOL
- JNZ ED240
- ;------- Use ERASE_LINE proc to erase rest of line
- MOV DX,BX
- CALL ERASE_LINE
- ;------- Branch to end of key processing loop
- JMP ED500
- ;
- ;******* Backspace
- ;------- Test for, and go to next case if not, BACKSPACE key
- ED240: CMP AX,BACKSPACE
- JNZ ED260
- ;------- Move to left one space
- DEC BL
- ;------- Test and branch if we didn't move off screen
- CMP BL,LEFT_MARG
- JGE ED250
- ;------- Put cursor at left margin and go to bottom of processing loop
- MOV BL,LEFT_MARG
- JMP ED500
- ;------- Jump to Delete key processing to the actual delete
- ED250: JMP ED270
- ;
- ;******* Delete key
- ED260 LABEL NEAR
- ;------- Test for and branch if not Del key
- CMP AX,DELETE
- JNZ ED280
- ;------- Set CX to number of spaces to right of current position
- ED270: MOV CL,RIGHT_MARG
- SUB CL,BL
- XOR CH,CH
- ;------- Set DX to current cursor position
- MOV DX,BX
- ;------- Branch if CX is zero
- JCXZ ED275
- ;------- Loop which moves CX characters one space to left
- ED272: INC DL
- CALL READ_CHAR
- DEC DL
- CALL WRITE_CHAR
- INC DL
- LOOP ED272
- ;------- Place BLANK at current cursor position
- ED275: MOV AX,BLANK
- CALL WRITE_CHAR
- ;------- Branch to end of key processing loop
- JMP ED500
- ;
- ;******* Insert key
- ED280 LABEL NEAR
- ;------- Test for, and go to next case if not, Insert key
- CMP AX,CHAR_INS
- JNZ ED300
- ;------- Set DX to right margin of current row
- MOV DH,BH
- MOV DL,RIGHT_MARG
- ;------- Set CX to number of spaces to right of current position
- MOV CL,DL
- SUB CL,BL
- XOR CH,CH
- ;------- Branch if CX is zero
- JCXZ ED290
- ;------- Loop which moves CX characters one space to right
- ED285: DEC DL
- CALL READ_CHAR
- INC DL
- CALL WRITE_CHAR
- DEC DL
- LOOP ED285
- ;------- Place BLANK at current cursor position
- ED290: MOV AX,BLANK
- CALL WRITE_CHAR
- ;------- Branch to end of key processing loop
- JMP ED500
- ;
- ;******* LINE_INS key
- ED300 LABEL NEAR
- ;------- Test for, and go to next case if not, LINE_INS key
- CMP AX,LINE_INS
- JNZ ED320
- ;------- Start at the bottom margin
- MOV DH,BOT_MARG
- ;------- Start at the left margin
- ED305: MOV DL,LEFT_MARG
- ;------- Test for and branch if we're on the current line
- CMP DH,BH
- JZ ED315
- ;------- Assign loop counter
- XOR CX,CX
- MOV CL,RIGHT_MARG
- INC CX
- ;------- Loop to move row of char/attr down
- ED310: DEC DH
- CALL READ_CHAR ; Get the character
- INC DH
- CALL WRITE_CHAR ; And put it back one line higher
- INC DL ; Move right one character
- LOOP ED310
- ;------- Now move up a line and do it again
- DEC DH
- JMP ED305
- ;------- Erase the current line
- ED315: CALL ERASE_LINE
- ;------- Branch to end of key processing loop
- JMP ED500
- ;
- ;******* LINE_DEL key
- ED320 LABEL NEAR
- ;------- Test for, and go to next case if not, LINE_DEL key
- CMP AX,LINE_DEL
- JNZ ED340
- ;------- Start at the left margin
- ED325: MOV DL,LEFT_MARG
- ;------- Test for and branch if we're on the last line
- CMP DH,BOT_MARG
- JZ ED335
- ;------- Assign loop counter
- XOR CX,CX
- MOV CL,RIGHT_MARG
- INC CX
- ;------- Loop to move row of char/attr up
- ED330: INC DH
- CALL READ_CHAR ; Get the character
- DEC DH
- CALL WRITE_CHAR ; And put it back one line lower
- INC DL ; Move right one character
- LOOP ED330
- ;------- Now move down a line and do it again
- INC DH
- JMP ED325
- ;------- Erase bottom line on display
- ED335: CALL ERASE_LINE ; And wipe out the bottom line
- ;------- Branch to end of key processing loop
- JMP ED500
- ;
- ;******* First MARK_CHAR
- ED340 LABEL NEAR
- ;------- Test for, and go to next case if not, `mark' hotkey
- CMP AX,MARK_CHAR
- JNZ ED400
- ;------- Put cursor position in DX
- MOV DX,BX
- ;------- Test for and loop around if already marking
- CMP MARK,-1
- JNZ ED350
- ;------- Save cursor location in MARK
- MOV MARK,BX
- ;------- Branch to end of key processing loop
- JMP ED500
- ;
- ;******* Second MARK_CHAR
- ;------- Store current location as FEED_END1 address in SCRNSAVE buffer
- ED350: CALL CONVERT_LOC
- MOV FEED_END1,AX
- ;------- Store previous mark location as feed end address SCRNSAVE buffer
- MOV DX,MARK
- CALL CONVERT_LOC
- MOV FEED_END2,AX
- ;------- Ensure that FEED_END1 is less than or equal to FEED_END2
- MOV CX,FEED_END1
- CMP CX,AX
- JNA ED360
- MOV FEED_END1,AX
- MOV FEED_END2,CX
- ;------- Increase FEED_END2 by one cell
- ED360: MOV AX,FEED_END2
- ADD AX,2
- MOV FEED_END2,AX
- ;------- Trim unmarked chars from screen
- CALL TRIM_SCREEN
- ;------- Branch to exit routine
- JMP ED800
- ;
- ;******* ASCII char -- write at current position
- ED400: MOV AH,ATTR
- CALL W_CHAR
- INC BL ; Move over one position
- ;
- ;******* Adjust cursor position
- ;------- Right margin
- ED500: CMP BL,RIGHT_MARG
- JLE ED520
- MOV BL,RIGHT_MARG
- ;------- Left margin
- ED520: CMP BL,LEFT_MARG
- JGE ED540
- MOV BL,LEFT_MARG
- ;------- Top margin
- ED540: CMP BH,TOP_MARG
- JGE ED560
- MOV BH,TOP_MARG
- ;------- Bottom margin
- ED560: CMP BH,BOT_MARG
- JLE ED600
- MOV BH,BOT_MARG
- ;------- Save new cursor position in CURSOR_POS
- ED600: MOV CURSOR_POS,BX
- ;------- Move cursor to the new position
- MOV DX,BX
- CALL PUT_CURSOR
- ;------- Jump to beginning of processing loop
- JMP ED100
- ;
- ;******* End routine
- ED800: RET
- ;
- EDITOR ENDP
-
-
- ;======= Proc PUT_CURSOR
- ;
- ; Place cursor at location in DX
- ;
- PUT_CURSOR PROC NEAR
- ;------- If we are in mark mode, set the screen square to inverse video
- CALL SHADE_SCRN
- MOV AH,02H ; SET_CUR_POS service
- PUSH BX
- XOR BX,BX ; Page 0
- INT 10H
- POP BX
- RET
- PUT_CURSOR ENDP
-
- UP_LEFT LABEL WORD
- ULHC_C DB 0
- ULHC_R DB 0
- LW_RIGHT LABEL WORD
- LRHC_C DB 0
- LRHC_R DB 0
- ATTRIB DB 0
- SAVE_AX DW 0
- SAVE_DX DW 0
-
- ;======= Proc SHADE_SCRN
- ;
- ; Assigns INV_ATTR to characters in box defined by
- ; MARK and CURSOR_POS. Called by PUT_CURSOR.
- ;
- SHADE_SCRN PROC NEAR
- ;
- ;******* Initialization
- ;------- Test for, and branch to routine end, if not marking
- CMP MARK,-1 ; Is a mark set?
- JZ SS450
- ;------- Save AX and DX registers
- MOV SAVE_AX,AX
- MOV SAVE_DX,DX
- ;------- First set the attribute to inverse
- MOV ATTRIB,INV_ATTR
- ;
- ;******* Place upper left-hand corner of shaded box in UP_LEFT
- ;------- Place current position in BX and marked position in AX
- MOV BX,CURSOR_POS
- MOV AX,MARK
- ;------- Place upper left-hand corner column value in AL
- CMP BL,AL
- JA SS100
- MOV AL,BL
- ;------- Place upper left-hand corner row value in AH
- SS100: CMP BH,AH
- JA SS200
- MOV AH,BH
- ;------- Store upper left-hand corner in UP_LEFT
- SS200: MOV UP_LEFT,AX
- ;
- ;******* Place lower right-hand corner of shaded box in LW_RIGHT
- ;------- Place marked position in AX
- MOV AX,MARK
- ;------- Place column value in AL
- CMP BL,AL
- JBE SS300
- MOV AL,BL
- ;------- Place row value in AH
- SS300: CMP BH,AH
- JBE SS400
- MOV AH,BH
- ;------- Store LRH corner in LW_RIGHT
- SS400: MOV LW_RIGHT,AX
- ;
- ;******* Call SS_COMMON to do the shading
- CALL SS_COMMON
- ;
- ;******* Return to caller
- SS450: RET
- SHADE_SCRN ENDP
-
-
- ;======= Proc UNSHAD_SCRN
- ;
- ; Assign ATTR to attributes of characters in the box defined
- ; by UP_LEFT and LW_RIGHT. Called by EDITOR, at the beginning
- ; of key processing.
- ;
- UNSHAD_SCRN PROC NEAR
- ;
- ;------- Test for, and branch to routine end, if not marking
- CMP MARK,-1 ; Here we unshade the shaded area
- JZ SS475
- ;------- Save AX and DX registers
- MOV SAVE_AX,AX
- MOV SAVE_DX,DX
- ;------- Set the attribute to normal
- MOV ATTRIB,ATTR ; Change the box back to normal
- ;------- Call SS_COMMON to do the shading
- CALL SS_COMMON
- ;------- Return to caller
- SS475: RET
- ;
- UNSHAD_SCRN ENDP
-
-
- ;======= Proc SS_COMMON
- ;
- ; Assign ATTRIB to attributes of characters in the box defined
- ; by UP_LEFT and LW_RIGHT.
- ;
- SS_COMMON PROC NEAR
- ;
- ;******* Initialization
- ;------- Put box corners in BX and DX registers
- MOV DX,UP_LEFT ; DX is variable -- loc to change attr
- MOV BX,LW_RIGHT ; BX is constant
- ;
- ;******* Change attributes of row in DH
- ;------- Test and branch if past last column
- SS500: CMP DL,BL
- JA SS600
- ;------- Change the attribute
- MOV AH,ATTRIB
- CALL WRITE_ATTR
- ;------- Point to next char on row and branch to top
- INC DL
- JMP SS500
- ;
- ;******* Prepare to do next row
- ;------- Point to next row
- SS600: INC DH
- ;------- Branch if past last row
- CMP DH,BH
- JA SS700
- ;------- Put first column in DL and branch
- MOV DL,ULHC_C
- JMP SS500
- ;
- ;******* End program
- ;------- Restore AX and DX
- SS700: MOV AX,SAVE_AX
- MOV DX,SAVE_DX
- ;------- Return
- RET
- ;
- SS_COMMON ENDP
-
-
- ;======= Proc TRIM_SCREEN
- ;
- ; Trims the right margin of screen after the second mark
- ;
- TRIM_SCREEN PROC NEAR
- ;
- ;******* Initialization
- ;------- First clear mark
- MOV MARK,-1
- ;------- Test and branch to return if at right-hand edge of screen
- MOV DL,LRHC_C
- CMP DL,RIGHT_MARG
- JZ TS200
- ;------- Put space to right of upper right-hand corner in BX
- MOV BH,ULHC_R
- MOV BL,LRHC_C
- INC BL
-
- ;******* Loop to erase to right of box
- ;------- Place lower right-hand corner in DX
- TS100: MOV DX,LW_RIGHT
- ;------- Branch to end if BH equals DH
- CMP BH,DH
- JZ TS200
- ;------- Erase end of current line
- MOV DX,BX
- CALL ERASE_LINE
- ;------- Increment current line and repeat
- INC BH
- JMP TS100
- ;
- ;******* End routine
- TS200: RET
- TRIM_SCREEN ENDP
-
-
- ;======= Proc TRIM_BUF
- ;
- ; Trims blanks from first and last row in the feed area
- ;
- TRIM_BUF PROC NEAR
- ;
- ;******* Exit unless buffer holds data
- MOV BX,FEED_END2
- CMP BX,FEED_END1
- JZ TB070
- ;
- ;******* Trim trailing blanks off last row
- ;------- Set CX to number of chars in a row
- XOR CX,CX
- MOV CL,LRHC_C
- SUB CL,ULHC_C
- INC CX
- ;------- Move backwards until first non-blank is found
- TB010: MOV AX,[BX-2]
- CMP AL,' '
- JNZ TB020
- SUB BX,2
- LOOP TB010
- ;------- Reassign FEED_END2
- TB020: MOV FEED_END2,BX
- ;
- ;******* Check for, and skip over, a blank first line
- ;------- Branch and end if feed area corresponds to one row
- MOV AX,UP_LEFT
- CMP AH,LRHC_R
- JZ TB070
- ;------- Set CX to number of chars in a row
- XOR CX,CX
- MOV CL,LRHC_C
- SUB CL,ULHC_C
- INC CX
- ;------- Point BX to start of feed area
- MOV BX,FEED_END1
- ;------- Check for, and branch to end, if a non-blank char is found
- TB030: MOV AX,[BX]
- CMP AL,' '
- JNZ TB070
- ADD BX,2
- LOOP TB030
- ;------- Set AX to number of chars from left side to carriage return
- XOR AX,AX
- MOV AL,RIGHT_MARG
- INC AL
- SUB AL,ULHC_C
- ;------- Convert to words and add to FEED_END1
- SHL AX,1
- ADD FEED_END1,AX
-
- ;******* End routine
- TB070: RET
- ;
- TRIM_BUF ENDP
-
-
- ;======= Proc READ_CURSOR
- ;
- ; Find the current cursor location and place in DX
- ;
- READ_CURSOR PROC NEAR
- MOV AH,03H
- PUSH BX
- XOR BX,BX
- INT 10H
- POP BX
- RET
- READ_CURSOR ENDP
-
-
- ;======= Proc READ_CHAR
- ;
- ; Read character on screen at location in DX and place in AX
- ;
- READ_CHAR PROC NEAR
- ;------- Covert the row and column into location
- CALL CAL_VID_LOC
- ;------- Get the character and attribute at that location
- MOV AX,ES:[DI]
- RET
- READ_CHAR ENDP
-
-
- ;======= Proc R_CHAR
- ;
- ; Read character on screen at current cursor location and place in AX
- ;
- R_CHAR PROC NEAR
- MOV AH,08H
- PUSH BX
- XOR BH,BH
- INT 10H
- POP BX
- RET
- R_CHAR ENDP
-
- ;======= Proc WRITE_CHAR
- ;
- ; Write character and attribute in AX to screen at location in DX
- ;
- WRITE_CHAR PROC NEAR
- PUSH AX ; Save the attrib from destruction
- CALL CAL_VID_LOC ; Convert the row and col into location
- POP AX
- MOV ES:[DI],AX
- RET
- WRITE_CHAR ENDP
-
-
- ;======= Proc WRITE_ATTR
- ;
- ; Write attrib in AX to screen location in DX
- ;
- WRITE_ATTR PROC NEAR
- PUSH AX
- CALL CAL_VID_LOC
- POP AX
- MOV ES:[DI+1],AH
- RET
- WRITE_ATTR ENDP
-
-
- ;======= Proc W_CHAR
- ;
- ; Write character and attribute in AX at current cursor location
- ;
- W_CHAR PROC NEAR
- ;------- Save registers
- PUSH BX
- PUSH CX
- ;------- Do the write using INT 10H
- MOV BL,AH ; Place attribute in BL
- XOR BH,BH ; Page 0
- MOV CX,1 ; Count = 1
- MOV AH,09H ; WRITE_CHAR_ATTR service
- INT 10H
- ;------- Restore registers
- POP CX
- POP BX
- ;------- Exit
- RET
- W_CHAR ENDP
-
- ;======= Proc GET_CHAR
- ;
- ; Get character from keyboard into AX
- ;
- GET_CHAR PROC NEAR
- MOV AH,0
- PUSHF
- CALL OLDINT16
- RET
- GET_CHAR ENDP
-
- ;======= Proc ERASE_LINE
- ;
- ; Erase the current line on the screen from DX to RIGHT_MARG, inclusive
- ;
- ERASE_LINE PROC NEAR
- ;------- Set CX to number of columns to erase
- XOR CX,CX
- MOV CL,RIGHT_MARG
- SUB CL,DL
- INC CL
- ;------- Loop to blank row
- ER100: MOV AX,BLANK
- CALL WRITE_CHAR
- INC DL
- LOOP ER100
- ;------- Exit routine
- RET
- ERASE_LINE ENDP
-
-
- ;======= Proc CONVERT_LOC
- ;
- ; Convert a location on the screen (in DX) into an offset in
- ; the SCRNSAVE buffer (in AX).
- ;
- CONVERT_LOC PROC NEAR
- ;
- ;******* Initialize
- ;------- Place line length (in bytes) in BX
- XOR BX,BX
- MOV BL,RIGHT_MARG
- INC BX
- INC BX
- SHL BX,1
- ;------- Place location in CX
- MOV CX,DX
- ;------- Point AX at beginning of SCRNSAVE buffer
- MOV AX,OFFSET SCRNSAVE
- ;
- ;******* Loop to find row
- ;------- Test and branch if CH equals top row of window
- CL100: CMP CH,TOP_MARG
- JZ CL200
- ;------- Add a row to AX and repeat test
- ADD AX,BX
- DEC CH
- JMP CL100
- ;
- ;******* Loop to find column
- ;------- Test and branch if CL equals left margin of window
- CL200: CMP CL,LEFT_MARG
- JZ CL300
- ;------- Add a column and repeat
- ADD AX,2
- DEC CL
- JMP CL200
- ;
- ;******* Exit
- CL300: RET
- CONVERT_LOC ENDP
-
-
- ;======= Proc CAL_VID_LOC
- ;
- ; Convert the screen location (row and column) in DX into an
- ; offset into the video display buffer in DI
- ;
- CAL_VID_LOC PROC NEAR
- ;------- Initialize AX, CX, DI to zero
- PUSH CX ; Save CX -- some callers need it
- XOR AX,AX ; AX holds line length
- XOR CX,CX ; CX is temp for location
- XOR DI,DI ; DI holds offset
- ;------- Set AX to line length in chars
- MOV AL,RIGHT_MARG
- INC AX
- ;------- Set CX to row number and branch if zero
- MOV CL,DH ; Put the number of rows into cx
- JCXZ CVL200
- ;------- Increment DI by the line length times the row number
- CVL100: ADD DI,AX
- LOOP CVL100
- ;------- Increment DI by the column number
- CVL200: MOV AL,DL
- ADD DI,AX
- ;------- End routine
- POP CX ; Restore CX
- SHL DI,1 ; Now convert this into byte offset
- MOV ES,DISPLAY_SEG
- RET
- CAL_VID_LOC ENDP
-
-
- ;-------------------------------
- ;======= Replacement for INT 16H
- ;-------------------------------
- ;
- ASSUME CS:COMSEG, DS:NOTHING, ES:NOTHING
- BEGIN PROC FAR
- ;
- ;======= Initial processing -- figure out what to do
- ;
- ;******* Check if in middle of feeding characters
- MAINLOOP LABEL NEAR
- ;------- Save caller's AX register
- MOV REQUEST,AX
- AND AH,0EFH
- MOV REQUEST2,AH
- ;------- Branch if we're in the middle of feeding characters
- MOV AX,FEED_START ; Are we in the middle of feeding...
- CMP AX,FEED_STOP ; ...chars to the application?
- JZ NOFEED ; No, loop around
- JMP FEED ; Yes, branch
- ;
- ;******* Test for type-0 request and return if not
- NOFEED LABEL NEAR
- ;------- Restore caller's AX
- MOV AX,REQUEST
- ;------- Check for type-0 request -- only interested in char requests
- CMP REQUEST2,0
- JZ CONTINU
- ;------- Jump to old INT 16 routine, which will return to application
- JMP OLDINT16
- ;
- ;******* Now check for a hot key -- return if not
- CONTINU LABEL NEAR
- ;------- Call old INT 16H (emulate interrupt)
- PUSHF
- CALL OLDINT16
- ;------- Check for Alt-Fn9
- CMP AX,CUT_KEY
- JZ GOT_CUT_KEY
- ;------- Check for Ctl-Fn9
- CMP AX,PASTE_KEY
- JZ PASTE_CHAR
- ;------- Not a hotkey -- provide keystroke to caller
- IRET
- ;
- ;======= `Cut' hotkey processing
- ;
- ;******* Setup for subroutine calls
- GOT_CUT_KEY LABEL NEAR
- ;------- Save stack and point SS:SP to top of PSP
- MOV SAVSTAKSS,SS
- MOV SAVSTAKSP,SP
- MOV AX,CS
- MOV SS,AX
- MOV SP,100H
- ;------- Enable interrupts while processing characters
- STI
- ;------- Set up a stack frame
- PUSH BP
- MOV BP,SP
- ;------- Save registers
- SUB SP,0EH
- CALL SAVEREG
- ;------- Set DS to COMSEG
- MOV DS,AX
- ASSUME DS:COMSEG
- ;
- ;******* Call EDITOR and other subroutines
- ;------- Calculate window extremeties
- CALL CALC_WINDOW
- ;------- Save the cursor for later restoring
- CALL READ_CURSOR
- MOV OLD_CUR_POS,DX
- ;------- Save screen in buffer SCRNSAVE
- CALL WINDOW_SAVE
- ;------- Restore cursor in edit window
- MOV DX,CURSOR_POS
- CALL PUT_CURSOR
- ;------- Edit in the window
- CALL EDITOR
- ;------- Save cursor in edit window for next edit
- CALL READ_CURSOR
- MOV CURSOR_POS,DX
- ;------- Put back whatever was originally there
- CALL WINDOW_SWAP
- ;------- Trim blanks from end of buffer
- CALL TRIM_BUF
- ;------- Restore the cursor position
- MOV DX,OLD_CUR_POS
- CALL PUT_CURSOR
- ;
- ;******* End `cut-key' processing
- ;------- Restore registers
- CALL RESTREG
- ADD SP,0EH
- ASSUME DS:NOTHING
- ;------- Restore stack
- POP BP
- MOV SS,SAVSTAKSS
- MOV SP,SAVSTAKSP
- ;------- End of loop -- jump to beginning
- MOV AX,REQUEST ; Restore request
- JMP MAINLOOP ; Get another char to return to caller
- ;
- ;======= `Paste' hotkey processing
- ;
- ;******* Paste characters into application
- PASTE_CHAR LABEL NEAR
- MOV AX,FEED_END1
- MOV FEED_START,AX
- MOV AX,FEED_END2
- MOV FEED_STOP,AX
- MOV AX,REQUEST ; Restore request
- JMP MAINLOOP ; Go get another character to return
- ;
- ;******* Feed characters to application from the buffer SCRNSAVE
- FEED LABEL NEAR
- ;------- Test and branch for return if a type-2 request
- CMP REQUEST2,1
- JA KSTAT
- ;------- Get next char from SCRNSAVE buffer into AX
- PUSH BX
- MOV BX,AX
- MOV AX,CS:[BX]
- POP BX
- ;------- Loop around if end of screen line
- CMP AX,CAR_RET2
- JZ FEED10
- ;------- Null attribute
- XOR AH,AH
- ;------- Save in FEED_CHAR
- FEED10: MOV FEED_CHAR,AX
- ;------- Test and branch if type-1 request
- CMP REQUEST2,0
- JNZ FEED_STAT
- ;------- Point to next character
- ADD FEED_START,2
- ;
- ;******* Handle beginning and end of line
- ;------- Test for and loop around if not carriage return
- CMP AL,CAR_RET1
- JNZ FEED20
- ;------- Skip to beginning of the feed area
- PUSH DX
- XOR DX,DX
- MOV DL,ULHC_C
- SHL DX,1 ; In words
- ADD FEED_START,DX
- POP DX
- ;------- Put address of next buffer location in BX
- FEED20: PUSH BX
- MOV BX,FEED_START
- ;------- Test, and branch to return, if at end of feed area
- FEED30: CMP BX,FEED_STOP
- JZ FEED50
- ;------- Test and loop around if next char is space
- MOV AX,CS:[BX]
- CMP AL,' '
- JZ FEED40
- ;------- Test and branch if a non-space char follows on this line
- CMP AX,CAR_RET2
- JNZ FEED50
- ;------- Point to carriage return, skipping over trailing blanks
- MOV FEED_START,BX
- JMP FEED50
- ;------- Point to next char on line and branch to top of loop
- FEED40: INC BX
- INC BX
- JMP FEED30
- ;
- ;******* Exit to caller
- ;------- Exit for type-0 request -- returning character to application
- FEED50 LABEL NEAR
- POP BX ; Restore stack
- MOV AX,FEED_CHAR ; Place char to feed in AX
- IRET ; Return char to application
- ;------- Exit for type-1 request: enable interrupts, feed ZF = NZ and char
- FEED_STAT LABEL NEAR
- STI
- RET 02
- ;------- Exit for type-2 request -- invoke INT 16H to do what he wants
- KSTAT: MOV AX,REQUEST
- JMP OLDINT16
-
- BEGIN ENDP
-
-
- ;======= Proc SAVEREG
- ;------- Save registers on stack frame
- SAVEREG PROC NEAR
- MOV [BP-2],BX
- MOV [BP-4],CX
- MOV [BP-6],DX
- MOV [BP-8],SI
- MOV [BP-0AH],DI
- MOV [BP-0CH],DS
- MOV [BP-0EH],ES
- RET
- SAVEREG ENDP
-
- ;======= Proc RESTREG
- ;------- Now put the registers back
- RESTREG PROC NEAR
- MOV BX,[BP-2]
- MOV CX,[BP-4]
- MOV DX,[BP-6]
- MOV SI,[BP-8]
- MOV DI,[BP-0AH]
- MOV DS,[BP-0CH]
- MOV ES,[BP-0EH]
- RET
- RESTREG ENDP
-
- ;------- Upper limit resident program (paras)
- RESPARA EQU ($-START+100H+15)/16
-
-
- ;-------------------------
- ;======= Installation code
- ;-------------------------
-
- INSTALL LABEL NEAR
- ASSUME CS:COMSEG, DS:COMSEG, ES:COMSEG
-
- ;------- Output 'OK' message
- MOV DX,OFFSET MESSAGE
- MOV AH,09H
- INT 21H
- ;------- Get existing 16H vector using ES:BX
- MOV AX,3516H
- INT 21H
- MOV OLDINT16IP,BX
- MOV OLDINT16CS,ES
- ASSUME ES:NOTHING
- ;------- Now put our routine there using DS:DX
- MOV AX,2516H
- MOV DX,OFFSET BEGIN
- INT 21H
- ;------- Terminate and stay resident
- MOV DX,RESPARA
- MOV AX,3100H
- INT 21H
-
- MESSAGE DB 10,13,'CUTPASTE installed',10,13
- DB ' Alt-Fn9 to enable cut ',10,13
- DB ' Start/stop marking: Fn1',10,13
- DB ' Move 1 space (4 ways): Cursor keys', 10,13
- DB ' Move 1 word (2 ways): Ctl-LeftArw, Ctl-RgtArw', 10,13
- DB ' Move to screen edge (4 ways): Home, End, PgUp, PgDn', 10,13
- DB ' Erase to End of Line: Fn6', 10,13
- DB ' Erase Line: Fn7', 10,13
- DB ' Add Line: Enter', 10,13
- DB ' Move text to right/left: Ins, Del, Bksp', 10,13
- DB ' Ctl-Fn9 to paste',10,13,'$'
-
- COMSEG ENDS
- END START
-