home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Professional
/
OS2PRO194.ISO
/
os2
/
editor
/
alias
/
keystrin.asm
< prev
next >
Wrap
Assembly Source File
|
1994-01-30
|
38KB
|
1,966 lines
;
; KEYSTRIN.ASM
;
; A DYNLINK LIBRARY KBD REPLACEMENT SUBSYSTEM ALLOWING COMMAND RECALL,
; LINE EDITING, AND ALIAS REPLACEMENT.
;
TITLE KEYSTRIN
.286P
EXTRN DOSDEVIOCTL:FAR, DOSOPEN:FAR, DOSCLOSE:FAR, DOSBEEP:FAR
EXTRN DOSWRITE:FAR, DOSGETINFOSEG:FAR, KBDGETSTATUS:FAR
EXTRN VIOWRTTTY:FAR, VIOGETCURPOS:FAR, VIOSETCURPOS:FAR
EXTRN VIOGETCURTYPE:FAR, VIOSETCURTYPE:FAR, VIOWRTNCHAR:FAR
EXTRN VIOWRTCHARSTR:FAR
;
LBUFF SEGMENT WORD PUBLIC 'KBUFFER'
KEYLEN EQU 2048
SYNLEN EQU 2048
KEYBUFF DB KEYLEN DUP(0) ; BUFFER FOR COMMAND RECALL
KEYTAIL DW 0 ; POINTER TO END OF BUFFER
CURRPTR DW 0 ; POINTER TO CURRENT COMMAND
FUNCBUFF DB 256 DUP(0) ; BUFFER FOR FUNCTION KEY RECALL
FUNCPTR DW 0 ; POINTER TO CHAR IN FUNCBUFF
FUNCMAX DW 0 ; END OF FUNCBUFF
WORKBUFF DB 256 DUP(0) ; WORK BUFFER
WORKPTR DW 0 ; POINTER TO WORKBUFF
WORKTAIL DW 0 ; POINTER TO END OF WORKBUFF
WORKMAX DW 0 ; MAX SIZE FOR WORKBUFF
XMITBUFF DB 256 DUP(0) ; BUFFER FOR RETURN FROM CALL
EDIT_FLAG DW 0 ; ALLOW COMMAND EDITING
CHANGE_FLAG DW 0 ; FLAG FOR LINE CHANGE
INIT_CUR_ROW DW 0 ; INITIAL CURSOR ROW
INIT_CUR_COL DW 0 ; INITIAL CURSOR COLUMN
CURR_CUR_ROW DW 0 ; CURRENT CURSOR ROW
CURR_CUR_COL DW 0 ; CURRENT CURSOR COLUMN
LAST_LENGTH DW 0 ; LENGTH OF LAST DISPLAYED COMMAND
THIS_LENGTH DW 0 ; LENGTH OF THIS COMMAND
INSERT_STATE DW 0 ; STATE OF INSERT
KEYDEVBUF DB 20 DUP(?) ; BUFFER FOR KEYBOARD REQUEST
KEYDEVPRM DW 1 ; PARAMETER FOR KEYBOARD CALL
KEYNAME DB 'KBD$',0 ; NAME OF KEYBOARD
KEYACT DW ? ; KEYBOARD ACTION
KEYHAND DW 0 ; KEYBOARD HANDLE
BLANK DB ' ' ; BLANK (SPACE) CHARACTER
O_CUR_SLINE DW 0 ; OLD CURSOR START LINE
O_CUR_ELINE DW 0 ; OLD CURSOR END LINE
O_CUR_WIDTH DW 0 ; OLD CURSOR WIDTH
O_CUR_ATTR DW 0 ; OLD CURSOR ATTRIBUTE
CUR_SLINE DW 0 ; CURSOR START LINE
CUR_ELINE DW 0 ; CURSOR END LINE
CUR_WIDTH DW 0 ; CURSOR WIDTH
CUR_ATTR DW 0 ; CURSOR ATTRIBUTE
KBD_STATE EQU $
KBD_ST_SIZE DW 0 ; SIZE OF KBD STATE
KBD_ST_MASK DW 0 ; KBD STATE MASK
KBD_ST_TAC DW 0 ; KBD TURNAROUND CHARACTER
KBD_ST_INTFL DW 0 ; KBD INT FL
KBD_ST_SHIFT DW 0 ; KBD SHIFT STATE
SPECTABL DW DO_F1 ; 0X3B
DW DO_F2 ; 0X3C
DW DO_F3 ; 0X3D
DW KEYLOOP ; 0X3E
DW KEYLOOP ; 0X3F
DW KEYLOOP ; 0X40
DW KEYLOOP ; 0X41
DW KEYLOOP ; 0X42
DW KEYLOOP ; 0X43
DW KEYLOOP ; 0X44
DW KEYLOOP ; 0X45
DW KEYLOOP ; 0X46
SPECTABL1 DW DO_HOME ; 0X47
DW DO_UP ; 0X48
DW KEYLOOP ; 0X49
DW KEYLOOP ; 0X4A
DW DO_LEFT ; 0X4B
DW KEYLOOP ; 0X4C
DW DO_RIGHT ; 0X4D
DW KEYLOOP ; 0X4E
DW DO_END ; 0X4F
DW DO_DOWN ; 0X50
DW KEYLOOP ; 0X51
DW DO_INS ; 0X52
DW DO_DEL ; 0X53
LBUFF ENDS
SBUFF SEGMENT WORD PUBLIC 'SYN'
SYNBUFF DB SYNLEN DUP(0) ; ALIAS BUFFER
SYNHEAD DW 0 ; BUFFER HEAD
SYNTAIL DW 0 ; BUFFER TAIL
PRINT_LINE DB 256 DUP(0) ; BUFFER FOR PRINT LINE
WRITTEN DW 0
SBUFF ENDS
;
ASSUME CS:KEYREP, DS:LBUFF, ES:SBUFF
KEYREP SEGMENT BYTE PUBLIC 'CODE'
;
START PROC FAR ; INITIALIZATION ROUTINE FOR DLL
PUSH DS
MOV AX,SEG LBUFF
MOV DS,AX ; SET UP DATA SEGMENT
PUSH DS
PUSH OFFSET KEYNAME ; FAR PTR TO NAME
PUSH DS
PUSH OFFSET KEYHAND ; FAR PTR TO HANDLE
PUSH DS
PUSH OFFSET KEYACT ; FAR PTR TO ACTION
PUSH 0
PUSH 0 ; LONG SIZE
PUSH 0 ; NORMAL FILE
PUSH 1 ; OPEN FLAG
PUSH 1C0H ; OPEN MODE
PUSH 0
PUSH 0
CALL DOSOPEN ; OPEN KEYBOARD
CMP AX,0
JNE BADOPEN
MOV LAST_LENGTH,0
MOV THIS_LENGTH,0
POP DS
MOV AX,1 ; SHOW SUCCESS
RET
BADOPEN:
POP DS
MOV AX,0 ; SHOW FAILURE
RET
START ENDP
;
; KEYSTRIN IS THE ACTUAL REPLACEMENT FUNCTION FOR THE KBDSTRINGIN
; SUBFUNCTION.
;
PUBLIC KEYSTRIN
KEYSTRIN PROC FAR
PUSH BP
MOV BP,SP
; ON ENTRY STACK LOOKS LIKE:
; [BP+0] - BP
; [BP+2] - OS2 FAR RETURN ADDR
; [BP+6] - CALLER'S DS
; [BP+8] - NEAR ENTRY POINT
; [BP+10] - FUNCTION NUMBER
; [BP+12] - FAR RETURN TO CALLER
; [BP+16] - KBDHANDLE
; [BP+18] - IOWAIT
; [BP+20] - LENGTH
; [BP+24] - POINTER TO CHAR BUFFER
;
CMP WORD PTR [BP+10],05
JE OURFUNC ; MAKE SURE THIS IS OUR FUNCTION
JMP NOT_OURS
;
OURFUNC:
PUSH DI
PUSH SI
PUSH DS
PUSH ES
PUSH AX
PUSH BX
PUSH CX
PUSH DX
PUSHF
MOV AX,SEG LBUFF ; SET UP DATA SEGMENT
MOV DS,AX
CMP WORD PTR [BP+18],0 ; IS THIS A WAIT CALL
JE CHK_STATE ; YES, WE CAN HANDLE IT
JMP NOT_OURS ; NO, PASS IT BACK ON TO KBD SYSTEM
;
CHK_STATE:
PUSH DS
PUSH OFFSET KBD_STATE ; FAR PTR TO KBDSTATE
PUSH 0
CALL KBDGETSTATUS ; GET KBD STATE
MOV AX,KBD_ST_MASK
AND AX,100B ; WE ONLY HANDLE COOKED MODE
CMP AX,0
JE DO_FUNC
JMP NOT_OURS ; LET SOMEONE ELSE DO THIS
;
DO_FUNC: ; FINALLY WE CAN START
MOV CHANGE_FLAG,0 ; MARK UNCHANGED
PUSH DS
PUSH OFFSET O_CUR_SLINE ; FAR PTR TO CURSOR TYPE
PUSH 0
CALL VIOGETCURTYPE ; GET CURSOR TYPE
;
MOV AX,[BP+22] ; SEGMENT OF INPUT BUFFER LENGTH
MOV ES,AX
MOV BX,[BP+20] ; OFFSET OF INPUT BUFFER LENGTH
MOV AX,ES:[BX] ; INPUT BUFFER LENGTH
MOV WORKMAX,AX
MOV AX,ES:[BX+2] ; EDITING FLAG
MOV EDIT_FLAG,AX
;
GET_CUR:
PUSH DS
PUSH OFFSET INIT_CUR_ROW ; FAR PTR TO CURSOR ROW
PUSH DS
PUSH OFFSET INIT_CUR_COL ; FAR PTR TO CURSOR COLUMN
PUSH 0
CALL VIOGETCURPOS ; GET INITIAL CURSOR POSITION
;
MOV AX,INIT_CUR_ROW
MOV CURR_CUR_ROW,AX
MOV AX,INIT_CUR_COL
MOV CURR_CUR_COL,AX
XOR AX,AX
MOV WORKPTR,AX
INC AX
MOV WORKTAIL,AX
PUSH DS
POP ES ; MAKE SEGMENTS THE SAME
CLD ; SET DIRECTION JUST TO BE SAFE
;
KEYLOOP: ; MAJOR WAIT FOR KEY LOOP
CALL GETKEY
CMP AX,0
JE FUNC_OK
JMP BAD_FUNC
;
FUNC_OK:
MOV SI,OFFSET KEYDEVBUF
LODSW ; SCAN_CODE AND CHAR_CODE
CMP AL,0 ; SPECIAL KEY?
JNE AT_KEY
JMP SPEC_KEY
;
AT_KEY: CMP AL,0E0H ; 101 KEY SPECIAL KEY?
JNE NORM_KEY ; NO
JMP SPEC_KEY
;
NORM_KEY:
CMP AL,0DH ; THIS REALLY SHOULD BE TAC
JNE IS_ESC
JMP DO_CR
IS_ESC: CMP AL,1BH
JNE IS_BS
JMP DO_ESC
IS_BS: MOV CHANGE_FLAG,1 ; SHOW LINE HAS CHANGED
CMP AL,08H
JNE ASC_KEY
JMP DO_BS
;
; AT ASK_KEY WE HAVE A NORMAL CHARACTER, CHECK INSERT MODE AND
; DO KEY HANDLING
;
ASC_KEY:
MOV CX,WORKTAIL
CMP CX,WORKMAX ; DO WE HAVE MAX CHARACTERS?
JNE ASC_KEY1 ; NO
JMP TOO_MANY ; YES
;
ASC_KEY1:
CMP INSERT_STATE,0
JE OVERWRITE
JMP INSERT
OVERWRITE:
MOV DI,WORKPTR ; CURR CHARACTER
ADD DI,OFFSET WORKBUFF
STOSB ; SAVE CHARACTER
SUB DI,OFFSET WORKBUFF
MOV AX,1 ; UPDATE CURSOR BY 1 POSITION
CALL DISPTAIL ; DISPLAY
MOV WORKPTR,DI ; SAVE WORKPTR
MOV FUNCPTR,DI ; SAVE FOR FUNCTION KEY RECALL
CMP WORKTAIL,DI ; ARE WE INSIDE LINE OR AT END?
JNE O1 ; INSIDE LINE, DO NOT EXTEND BUFFER
INC WORKTAIL ; INC LINE LENGTH
INC THIS_LENGTH
MOV AX,THIS_LENGTH
CMP AX,LAST_LENGTH
JLE O1
INC LAST_LENGTH
;
O1: JMP KEYLOOP ; AND LOOP
;
INSERT:
PUSH AX ; SAVE CHARACTER
MOV DI,WORKTAIL ; GET END OF BUFFER
DEC DI ; LESS ONE
MOV SI,DI ; TO SOURCE REGISTER
DEC SI ; LESS ONE
MOV CX,DI
SUB CX,WORKPTR ; COUNT OF CHARACTERS TO MOVE
ADD DI,OFFSET WORKBUFF
ADD SI,OFFSET WORKBUFF
PUSHF ; SAVE FLAGS (WE NEED TO CHANGE DIR)
STD
REP MOVSB ; MOVE CHARACTERS
POPF ; RESTORE FLAGS (DIRECTION)
MOV DI,WORKPTR ; GET CHAR PTR
POP AX ; RESTORE CHARACTER
ADD DI,OFFSET WORKBUFF
STOSB ; STASH CHARACTER IN BUFFER
MOV AX,1 ; UPDATE CURSOR BY 1 POSITION
CALL DISPTAIL ; DO DISPLAY
INC WORKPTR
INC WORKTAIL ; EXTEND LINE LENGTH
JMP KEYLOOP
;
; AT DO_ESC WE HAVE READ AN ESCAPE KEY, CLEAR THE INPUT LINE AND
; RESTORE CURSOR TO ORIGINAL POSITION.
;
DO_ESC:
PUSH DS
PUSH OFFSET BLANK ; FAR PTR TO BLANK CHARACTER
MOV AX,WORKTAIL
DEC AX
ADD AX,OFFSET WORKBUFF
PUSH AX ; NUMBER OF CHARACTERS TO WRITE
MOV AX,INIT_CUR_ROW
PUSH AX
MOV AX,INIT_CUR_COL
PUSH AX
PUSH 0
CALL VIOWRTNCHAR ; WRITE N CHARACTERS
MOV AX,INIT_CUR_ROW
MOV CURR_CUR_ROW,AX ; RESET CURSOR POSITION
PUSH AX
MOV AX,INIT_CUR_COL
MOV CURR_CUR_COL,AX
PUSH AX
PUSH 0
CALL VIOSETCURPOS
XOR AX,AX
MOV WORKPTR,AX
MOV FUNCPTR,AX
INC AX
MOV WORKTAIL,AX
PUSH DS
PUSH OFFSET O_CUR_SLINE ; FAR PTR TO CURSOR TYPE
XOR AX,AX
MOV INSERT_STATE,AX ; CLEAR INSERT MODE
PUSH AX
CALL VIOSETCURTYPE
MOV THIS_LENGTH,0
MOV CHANGE_FLAG,0
MOV FUNCPTR,0
JMP KEYLOOP
;
; AT DO_BS WE HANDLE A BACKSPACE CHARACTER
;
DO_BS:
MOV AX,WORKPTR
CMP AX,0
JNE BS1
JMP KEYLOOP ; AT START OF LINE
;
BS1:
MOV CX,WORKTAIL
DEC CX
CMP CX,AX ; AT END OF LINE?
JE BS2 ; YES, EASY CASE
JMP BS3 ; NO, HARDER CASE
;
BS2:
DEC AX ; BACKUP WORKPTR
MOV WORKPTR,AX
MOV FUNCPTR,AX
DEC WORKTAIL
MOV DI,AX
ADD DI,OFFSET WORKBUFF
MOV AL,' '
STOSB ; BLANK CHARACTER
MOV AX,CURR_CUR_COL
DEC AX
CMP AX,-1 ; DID WE WRAP A LINE?
JNE BS2A ; NO
DEC CURR_CUR_ROW ; YES
MOV AX,79
BS2A:
MOV CURR_CUR_COL,AX
PUSH CURR_CUR_ROW
PUSH CURR_CUR_COL
PUSH 0
CALL VIOSETCURPOS
MOV AX,0 ; DO NOT UPDATE CURSOR POSITION
CALL DISPTAIL
DEC THIS_LENGTH
JMP KEYLOOP
;
BS3:
DEC AX
MOV WORKPTR,AX
MOV FUNCPTR,AX
MOV DI,AX ; DEST = WORKPTR
INC AX
MOV SI,AX ; SOURCE = WORKPTR + 1
ADD DI,OFFSET WORKBUFF
ADD SI,OFFSET WORKBUFF
MOV CX,WORKTAIL
DEC CX
SUB CX,WORKPTR ; NUMBER OF CHARACTERS TO MOVE
REP MOVSB
DEC WORKTAIL
MOV BX,WORKTAIL
DEC BX
MOV AL,' '
MOV WORKBUFF[BX],AL
MOV AX,CURR_CUR_COL
DEC AX
CMP AX,-1
JNE BS3A
DEC CURR_CUR_ROW
MOV AX,79
;
BS3A:
MOV CURR_CUR_COL,AX
PUSH CURR_CUR_ROW
PUSH CURR_CUR_COL
PUSH 0
CALL VIOSETCURPOS
MOV AX,0 ; DON'T UPDATE CURSOR POSITION
CALL DISPTAIL
JMP KEYLOOP
;
; AT DO_CR WE HAVE READ A FULL LINE. CLEAR UP OUT DATA AND PASS THE
; STRING BACK TO THE CALLING PROGRAM. MAKE CURRPTR POINT TO THE
; END OF THIS STRING (FOR RECALL).
;
DO_CR:
CMP CHANGE_FLAG,0
JNE DO_CR1 ; LINE HAS CHANGED, SAVE FOR RECALL
JMP SEND_BUFF
;
DO_CR1:
MOV AX,WORKTAIL
CMP AX,4
JGE IS_FIRST
JMP SEND_BUFF1 ; DON'T SAVE LINES OF < 3 CHARS
;
IS_FIRST:
MOV DI,KEYTAIL
INC DI
AND DI,KEYLEN-1 ; DEST = END OF KEYBUFF
MOV SI,OFFSET WORKBUFF
MOV CX,WORKTAIL
DEC CX ; NUMBER OF CHARS TO STORE
;
MOVE_LOOP:
PUSH DI
ADD DI,OFFSET KEYBUFF
MOVSB
POP DI
INC DI
AND DI,KEYLEN-1 ; HANDLE BUFFER WRAP
LOOP MOVE_LOOP
;
ADD DI,OFFSET KEYBUFF
MOV AL,0
STOSB ; MAKE ASCIIZ
SUB DI,OFFSET KEYBUFF
MOV KEYTAIL,DI
MOV CURRPTR,DI ; FOR COMMAND RECALL
JMP SEND_BUFF1
;
SEND_BUFF:
MOV SI,CURRPTR
ADD SI,OFFSET KEYBUFF
SEND_BUFF0:
LODSB
CMP AL,0
JNE SEND_BUFF0
SUB SI,OFFSET KEYBUFF
MOV CURRPTR,SI
SEND_BUFF1:
MOV AL,0DH
MOV DI,WORKTAIL
DEC DI
MOV LAST_LENGTH,DI ; LENGTH OF LAST LINE
ADD DI,OFFSET WORKBUFF
STOSB ; STORE CR
MOV AX,WORKTAIL
ADD AX,INIT_CUR_COL
CMP AX,80
JL SEND_BUFF2
SUB AX,80
INC CURR_CUR_ROW
SEND_BUFF2:
MOV CURR_CUR_COL,AX
PUSH CURR_CUR_ROW
PUSH CURR_CUR_COL
PUSH 0
CALL VIOSETCURPOS
MOV AX,DI
DEC AX
SUB DI,OFFSET WORKBUFF
PUSH DS
PUSH AX ; FAR PTR TO CR
PUSH 1 ; NUMBER OF CHARACTERS TO WRITE
XOR AX,AX
MOV THIS_LENGTH,AX ; NEW LINE LENGTH
PUSH AX ; REQUIRED ZERO
CALL VIOWRTTTY ; DISPLAY CR
PUSH ES
CALL ALIAS ; CHECK FOR ALIAS SUBSTITUTION
MOV SI,OFFSET WORKBUFF
CMP AX,1
JE SEND_BUFF3 ; NO SUBSTITUTION
MOV SI,OFFSET XMITBUFF ; SUBSTITUTION MADE USE XMITBUFF
SEND_BUFF3:
MOV AX,WORD PTR [BP+26] ; SEGMENT OF RECEIVING BUFFER
MOV ES,AX
MOV DI,WORD PTR [BP+24] ; OFFSET OF RECEIVING BUFFER
MOV CX,0 ; CLEAR COUNT
SEND_BUFF4:
LODSB ; GET CHAR
CMP AL,0DH ; LAST CHAR?
JE SEND_BUFF5
STOSB ; SEND CHAR
INC CX
JMP SEND_BUFF4
SEND_BUFF5:
STOSB ; SEND CR
MOV AX,[BP+22] ; SEGMENT OF RETURNED BUFFER LENGTH
MOV ES,AX
MOV BX,[BP+20] ; OFFSET OF RETURNED BUFFER LENGTH
MOV ES:[BX+2],CX ; LENGTH (LESS CR)
POP ES
JMP KEYDONE ; DO CLEANUP
;
; AT SPEC_KEY WE HAVE READ A SPECIAL KEY
;
SPEC_KEY:
MOV AL,AH
XOR AH,AH
CMP AX,3BH
JGE IN_TAB1
JMP KEYLOOP ; UNUSED KEY
;
IN_TAB1:
CMP AX,47H
JGE IN_TAB2
JMP DO_TAB1 ; KEY IN TABLE 1
;
IN_TAB2:
CMP AX,54H
JGE IS_CLFT
JMP DO_TAB2 ; KEY IN TABLE 2
IS_CLFT:
CMP AX,73H
JNE IS_CRT
JMP DO_CLFT
IS_CRT:
CMP AX,74H
JNE IS_CPUP
JMP DO_CRT
IS_CPUP:
CMP AX,84H
JNE IS_CPDN
JMP DO_CPUP
IS_CPDN:
CMP AX,76H
JNE NOT_IMP
JMP DO_CPDN
;
NOT_IMP:
JMP KEYLOOP ; NOT AN ASSIGNED KEY
;
DO_TAB1:
SUB AX,3BH ; MAKE OFFSET INTO TABLE
SHL AX,1 ; FOR WORD POINTERS
MOV BX,AX
MOV AX,SPECTABL[BX]
JMP AX ; DISPATCH
;
DO_TAB2:
SUB AX,47H ; OFFSET INTO TABLE
SHL AX,1
MOV BX,AX
MOV AX,SPECTABL1[BX]
JMP AX ; DISPATCH
;
;
; DO_CLFT - MOVE ONE WORD LEFT
;
DO_CLFT: ; MOVE ONE WORD CHARACTER LEFT
MOV DL,' '
MOV DH,'\'
MOV AX,WORKPTR
CMP AX,0
JNE CLEFT1
JMP KEYLOOP ; AT LEFT BORDER
CLEFT1: ADD AX,OFFSET WORKBUFF
MOV BX,AX
;
CLEFT2: DEC BX ; LOOP TO FIND NON-DELIMITER
CMP BX,OFFSET WORKBUFF ; AT BEGINNING OF LINE
JE CLEFT6 ; YES
CMP [BX],DL ; IS THIS A SPACE
JE CLEFT2 ; YES LOOP
CMP [BX],DH ; IS THIS A '\'
JE CLEFT2
;
CLEFT3: DEC BX ; FOUND A NON-DELIMITER NOW FIND THE
CMP BX,OFFSET WORKBUFF ; NEXT DELIMITER
JE CLEFT6 ; AT BEGINNING OF LINE
CMP [BX],DL ; SPACE
JE CLEFT4
CMP [BX],DH ; '\'
JNE CLEFT3
;
CLEFT4: INC BX
SUB BX,OFFSET WORKBUFF
MOV CX,WORKPTR
SUB CX,BX ; HOW FAR WE HAVE MOVED
MOV WORKPTR,BX
MOV FUNCPTR,BX
MOV AX,CURR_CUR_COL
SUB AX,CX ; PAST BEGINNING OF LINE
CMP AX,0
JGE CLEFT5
ADD AX,80 ; TRICK COLUMN NUMBER
MOV CURR_CUR_COL,AX
MOV AX,CURR_CUR_ROW
DEC AX ; ADJUST ROW
MOV CURR_CUR_ROW,AX
JMP CLEFT7
;
CLEFT5: MOV CURR_CUR_COL,AX
JMP CLEFT7
;
CLEFT6: MOV BX,0
MOV WORKPTR,BX
MOV FUNCPTR,BX
MOV AX,INIT_CUR_COL
MOV CURR_CUR_COL,AX
MOV AX,INIT_CUR_ROW
MOV CURR_CUR_ROW,AX
;
CLEFT7: PUSH CURR_CUR_ROW
PUSH CURR_CUR_COL
PUSH 0
CALL VIOSETCURPOS
JMP KEYLOOP
;
;
; AT DO_CRT WE WANT TO LOOK RIGHT UNTIL WE FIND A SPACE THEN KEEP LOOKING
; UNTIL WE FIND A NON-SPACE
;
DO_CRT: MOV BX,WORKPTR
MOV AX,WORKTAIL
MOV DL,' '
MOV DH,'\'
DEC AX
CMP AX,BX
JNE CRT1
JMP KEYLOOP ; AT END OF LINE
;
CRT1: INC BX ; NEXT CHAR
CMP AX,BX ; AT END?
JNE CRT2 ; NO
JMP CRT5 ; YES
;
CRT2: CMP WORKBUFF[BX],DL ; IS THIS A DELIMITER
JE CRT3
CMP WORKBUFF[BX],DH ;
JNE CRT1 ; NO, KEEP LOOKING
;
CRT3: INC BX ; YES, PASS IT
CMP AX,BX ; AT END?
JNE CRT4 ; NO
JMP CRT5 ; YES
;
CRT4: CMP WORKBUFF[BX],DL ; IS THIS A SPACE
JE CRT3 ; YES, KEEP ON TRUCKING
CMP WORKBUFF[BX],DH
JE CRT3
;
CRT5: MOV CX,BX
MOV BX,WORKPTR
MOV WORKPTR,CX
MOV FUNCPTR,CX
SUB CX,BX ; LENGTH MOVED
MOV AX,CURR_CUR_COL
ADD AX,CX
CMP AX,80
JL CRT6
SUB AX,80
MOV CURR_CUR_COL,AX
MOV AX,CURR_CUR_ROW
INC AX
MOV CURR_CUR_ROW,AX
JMP CRT9
;
CRT6: MOV CURR_CUR_COL,AX
;
CRT9: PUSH CURR_CUR_ROW
PUSH CURR_CUR_COL
PUSH 0
CALL VIOSETCURPOS
JMP KEYLOOP
;
; AT DO_LEFT WE SIMPLY MOVE THE CURSOR ONE CHARACTER TO THE LEFT
;
DO_LEFT:
MOV AX,WORKPTR
CMP AX,0
JNE LEFT1
JMP KEYLOOP ; AT BEGINNING OF LINE
;
LEFT1: DEC AX
MOV WORKPTR,AX
MOV FUNCPTR,CX
MOV AX,CURR_CUR_COL
CMP AX,0
JNE LEFT2
MOV AX,80
MOV BX,CURR_CUR_ROW
DEC BX
MOV CURR_CUR_ROW,BX
;
LEFT2: DEC AX
MOV CURR_CUR_COL,AX
PUSH CURR_CUR_ROW
PUSH CURR_CUR_COL
PUSH 0
CALL VIOSETCURPOS
JMP KEYLOOP
;
; AT DO_RIGHT WE SIMPLY MOVE THE CURSOR ONE CHARACTER TO THE RIGHT
;
DO_RIGHT:
MOV AX,WORKPTR
INC AX
CMP AX,WORKTAIL
JNE RIGHT1
JMP KEYLOOP ; AT END OF LINE
;
RIGHT1: MOV WORKPTR,AX
MOV FUNCPTR,AX
MOV AX,CURR_CUR_COL
INC AX
CMP AX,80
JNE RIGHT2
MOV AX,0
MOV BX,CURR_CUR_ROW
INC BX
MOV CURR_CUR_ROW,BX
;
RIGHT2: MOV CURR_CUR_COL,AX
PUSH CURR_CUR_ROW
PUSH CURR_CUR_COL
PUSH 0
CALL VIOSETCURPOS
JMP KEYLOOP
;
; AT DO_HOME WE MOVE TO THE BEGINNING OF THE LINE
;
DO_HOME:
XOR AX,AX
MOV WORKPTR,AX
MOV FUNCPTR,AX
MOV AX,INIT_CUR_COL
MOV CURR_CUR_COL,AX
MOV BX,INIT_CUR_ROW
MOV CURR_CUR_ROW,BX
PUSH BX
PUSH AX
PUSH 0
CALL VIOSETCURPOS
JMP KEYLOOP
;
; AT DO_END WE MOVE THE THE END OF THE LINE
;
DO_END: MOV AX,WORKTAIL
DEC AX
CMP AX,WORKPTR
JNE END1
JMP KEYLOOP ; ALREADY AT END
;
END1:
CMP AX,0
JNE END2
JMP KEYLOOP ; NO LINE
;
END2: MOV WORKPTR,AX
MOV FUNCPTR,AX
MOV BX,INIT_CUR_COL
ADD AX,BX
CMP AX,80
JL END3
SUB AX,80
MOV BX,INIT_CUR_ROW
INC BX
MOV CURR_CUR_ROW,BX
;
END3: MOV CURR_CUR_COL,AX
PUSH CURR_CUR_ROW
PUSH CURR_CUR_COL
PUSH 0
CALL VIOSETCURPOS
JMP KEYLOOP
;
; AT DO_INS WE TOGGLE THE INSERT_STATE AND CHANGE CURSOR SHAPE
;
DO_INS: PUSH DS
PUSH OFFSET CUR_SLINE
PUSH 0
CALL VIOGETCURTYPE
;
MOV AX,INSERT_STATE
CMP AX,1
JE INS1
MOV AX,1 ; NOW INSERT
MOV INSERT_STATE,AX
MOV AX,CUR_SLINE
SUB AX,2
MOV CUR_SLINE,AX
JMP INS2
;
INS1: MOV AX,0 ; NOW OVERWRITE
MOV INSERT_STATE,AX
MOV BX,O_CUR_SLINE ; GET ORIG. CUR
MOV AX,O_CUR_ELINE
MOV CUR_SLINE,BX
MOV CUR_ELINE,AX
;
INS2: PUSH DS
PUSH OFFSET CUR_SLINE
PUSH 0
CALL VIOSETCURTYPE
JMP KEYLOOP
;
; AT DO_DEL WE WANT TO DELETE THE CHARACTER AT THE CURSOR
;
DO_DEL: MOV AX,WORKPTR
INC AX
CMP AX,WORKTAIL
JNE DEL1
JMP KEYLOOP ; AT END OF LINE
;
DEL1: MOV DI,WORKPTR
MOV SI,DI
INC SI
ADD DI,OFFSET WORKBUFF
ADD SI,OFFSET WORKBUFF
MOV CX,WORKTAIL ; END OF BUFFER
DEC CX ; LESS 1
MOV WORKTAIL,CX
SUB CX,WORKPTR ; LENGTH OF CHARACTERS TO MOVE
PUSH CX ; WE WILL NEED THIS IN A SEC
REP MOVSB ; MOVE LINE IN BUFFER
;
POP CX ; RESTORE LENGTH
MOV BX,WORKTAIL ; PAST END OF LINE
DEC BX
MOV AL,20H
MOV WORKBUFF[BX],AL
MOV AX,0
CALL DISPTAIL
JMP KEYLOOP
;
INC CX ; NEED TO SHOW SPACE AT END OF LINE
PUSH DS ; SEGMENT OF LINE TO REDISPLAY
MOV AX,WORKPTR
ADD AX,OFFSET WORKBUFF
PUSH AX ; OFFSET OF LINE
PUSH CX
PUSH 0 ; VIO HANDLE
CALL VIOWRTTTY
;
DEC THIS_LENGTH
PUSH CURR_CUR_ROW
PUSH CURR_CUR_COL
PUSH 0
CALL VIOSETCURPOS
JMP KEYLOOP
;
; AT DO_F1 WE WANT TO DUPLICATE THE OS/2 F1 KEY WHICH DISPLAYS THE PREVIOUS
; LINE ONE CHARACTER AT A TIME
;
DO_F1: MOV BX,WORKPTR
CMP BX,FUNCMAX
JGE DO_F1A
MOV AL,FUNCBUFF[BX] ; LOAD NEXT KEY
CMP AL,0 ; IS IT END OF THE LINE
JE DO_F1A ; YES, DO NOTHING ELSE
INC BX ; NO, UPDATE FUNCPTR
MOV FUNCPTR,BX
JMP ASC_KEY ; AND PRETEND THE KEY CAME FROM USER
;
DO_F1A: JMP KEYLOOP
;
; AT DO_F2 WE WANT TO COPY CHARACTERS FROM FUNCBUFF UNTIL WE FIND
; THE KEY WE ARE LOOKING FOR
;
DO_F2: CALL GETKEY
CMP AX,0
JE DO_F2A
JMP BAD_FUNC
;
DO_F2A: MOV SI,OFFSET KEYDEVBUF
LODSW ; KEY SCAN_CODE AND CHAR_CODE
CMP AL,0
JNE DO_F2B
JMP KEYLOOP
;
DO_F2B: MOV SI,FUNCPTR
ADD SI,OFFSET FUNCBUFF
MOV DI,WORKPTR
ADD DI,OFFSET WORKBUFF
MOV AH,AL ; SAVE TARGET CHARACTER
MOV CX,0
MOV BX,SI
MOV DX,FUNCMAX
ADD DX,OFFSET FUNCBUFF
LODSB ; ALWAYS MATCH FIRST CHAR
CMP AL,0
JE DO_F2E ; UNLESS IT ZERO
;
DO_F2C: CMP SI,DX
JGE DO_F2E
LODSB
INC CX
CMP AL,AH
JE DO_F2D
CMP AL,0
JE DO_F2E ; DO NOT MOVE IF NOT FOUND
JMP DO_F2C
;
DO_F2D: MOV SI,BX
MOV AX,CX ; CX CONTAINS COUNT TO MOVE
PUSH AX
REP MOVSB
MOV AL,0
STOSB
DEC DI
POP AX
SUB DI,OFFSET WORKBUFF
PUSH DI
INC DI
MOV WORKTAIL,DI
SUB SI,OFFSET FUNCBUFF
MOV FUNCPTR,SI
CALL DISPTAIL
POP DI
MOV WORKPTR,DI
DO_F2E: JMP KEYLOOP
;
; AT DO_F3 WE COPY THE REMAINDER OF FUNCBUFF INTO WORKBUFF
;
DO_F3: MOV SI,FUNCPTR
ADD SI,OFFSET FUNCBUFF
MOV DI,WORKPTR
ADD DI,OFFSET WORKBUFF
MOV BX,FUNCMAX
ADD BX,OFFSET FUNCBUFF
MOV AL,[SI]
CMP AL,0
JNE DO_F3B
JMP KEYLOOP
;
DO_F3B: CMP SI,BX
JGE DO_F3D
LODSB
CMP AL,0
JE DO_F3C
STOSB
JMP DO_F3B
;
DO_F3C: MOV ES:[DI],AL
SUB SI,OFFSET FUNCBUFF
DEC SI
MOV FUNCPTR,SI
SUB DI,OFFSET WORKBUFF
PUSH DI
MOV AX,DI
SUB AX,WORKPTR
INC DI
MOV WORKTAIL,DI
CALL DISPTAIL
POP DI
MOV WORKPTR,DI
DO_F3D: JMP KEYLOOP
;
; AT DO_UP CURRPTR WILL EITHER POINT TO THE END (ZERO) OF THE LAST LINE
; ENTERED (FOR A NEW LINE), OR TO THE FIRST CHARACTER OF THE LAST
; LINE RECALLED. IN ORDER TO RECALL A LINE WE MUST BACK CURRPTR
; UP TO THE BEGINNING OF A LINE. WE DO THIS BY SCANNING BACKWARDS
; UNTIL WE FIND A NON-ZERO CHARACTER AND THEN
; CONTINUING UNTIL WE FIND THE NEXT ZERO CHARACTER.
; NOTE THAT DO_UP WILL LEAVE CURRPTR POINTING TO THE FIRST CHAR
; OF THE LINE WE JUST RECALLED.
; ALSO NOTE THAT AT DO_UP, WE DECREMENT CURRPTR BEFORE WE START
; WHEREAS IN DO_DOWN WE START SCANNING AT CURRPTR.
;
DO_UP: MOV CHANGE_FLAG,0 ; CLEAR CHANGE FLAG
MOV BX,CURRPTR
;
UP_LOOP1:
DEC BX
CMP BX,-1
JNE UP_LOOP2
MOV BX,KEYLEN-1
UP_LOOP2:
MOV AL,KEYBUFF[BX]
CMP AL,0
JNE UP_LOOP3
CMP BX,CURRPTR
JNE UP_LOOP1
JMP DO_ESC ; WE WENT THROUGH BUFFER, NO LINES
;
UP_LOOP3: ; NON-ZERO BYTE
CMP BX,-1
JNE UP_LOOP4
MOV BX,KEYLEN
UP_LOOP4:
MOV AL,KEYBUFF[BX]
DEC BX
CMP AL,0
JNE UP_LOOP3
;
; FOUND THE NEXT ASCII ZERO, THIS IS THE END OF A LINE. SAVE NEW CURRPTR
;
UP_LOOP5:
INC BX ; FIX LATE DECREMENT
INC BX ; POINT PAST ASCII ZERO
AND BX,KEYLEN-1
MOV CURRPTR,BX ; MAKE THIS CURRENT LINE
;
; NOW MOVE THIS STRING (UP TO WORKMAX CHARACTERS) INTO WORKBUFF
;
MOV DI,OFFSET WORKBUFF
MOV CX,WORKMAX
;
UP_LOOP6:
AND BX,KEYLEN-1
MOV AL,KEYBUFF[BX]
CMP AL,0
JE UP_LOOP7
STOSB
INC BX
LOOP UP_LOOP6
;
; AT UP_LOOP7 WE EITHER FELL OUT OF THE LOOP WITH AN ASCII ZERO OR
; WORKMAX CHARACTERS
;
UP_LOOP7:
SUB DI,OFFSET WORKBUFF
MOV WORKPTR,DI ; SET UP POINTERS
MOV FUNCPTR,DI
INC DI
MOV WORKTAIL,DI ; INTO WORKBUFF
;
; NOW JOIN COMMON CODE TO DISPLAY WORKBUFF
;
JMP DISPBUFF
;
; AT DO_DOWN WE WANT TO RECALL THE NEXT LINE FROM OUR CIRCULAR BUFFER.
; CURRPTR WILL EITHER POINT TO THE ZERO BEFORE THE LINE WE WISH
; TO RECALL OR IT WILL POINT TO THE FIRST CHARACTER OF THE LINE
; BEFORE THE ONE WE WISH TO RECALL. IN EITHER EVENT WE SCAN FOR
; A ZERO THEN FOR THE FIRST NON-ZERO. THAT IS THE FIRST CHARACTER
; OF THE LINE WE ARE SEEKING.
; NOTE THAT AT DO_DOWN WE START SCANNING AT CURRPTR WHILE IN DO_UP
; WE DECREMENT CURRPTR BEFORE WE START SCANNING.
;
;
DO_DOWN:
MOV CHANGE_FLAG,0 ; CLEAR CHANGE FLAG
MOV BX,CURRPTR
;
DOWN_LOOP1: ; WE NEED TO SCAN AHEAD UNTIL WE FIND
MOV AL,KEYBUFF[BX] ; A ZERO CHARACTER
CMP AL,0
JE DOWN_LOOP2 ; FOUND IT
INC BX ;
AND BX,KEYLEN-1 ; KEEP IN RANGE
CMP BX,CURRPTR
JNE DOWN_LOOP1
JMP KEYLOOP ; NOTHING IN BUFFER
;
DOWN_LOOP2: ; NOW LOOK FOR NON-ZERO
MOV AL,KEYBUFF[BX]
CMP AL,0
JNE DOWN_LOOP2A
INC BX
AND BX,KEYLEN-1
CMP BX,CURRPTR
JNE DOWN_LOOP2
JMP KEYLOOP ; NOTHING IN BUFFER
;
DOWN_LOOP2A:
; FIRST NON-ZERO CHAR
; WE FOUND THE END OF THIS LINE
; SAVE CURRPTR AND SCAN TO FIRST
; REAL CHARACTER OF THIS LINE
MOV CURRPTR,BX ; SAVE CURRPTR FOR RECALL
MOV DI,OFFSET WORKBUFF
MOV CX,WORKMAX
;
DOWN_LOOP3:
AND BX,KEYLEN-1 ; KEEP POINTER IN RANGE
MOV AL,KEYBUFF[BX]
CMP AL,0
JE DOWN_LOOP4
STOSB
INC BX
LOOP DOWN_LOOP3
;
; AT DOWN_LOOP4, WE EITHER RAN OUT OF WORKMAX CHARACTERS OR WE FOUND
; AN ASCII ZERO.
;
DOWN_LOOP4:
SUB DI,OFFSET WORKBUFF
MOV WORKPTR,DI
MOV FUNCPTR,DI
INC DI
MOV WORKTAIL,DI
;
; AT DISPBUFF WE NEED TO DISPLAY THE CHARACTER STRING WE JUST MOVED INTO
; WORKBUFF.
;
DISPBUFF:
PUSH INIT_CUR_ROW
PUSH INIT_CUR_COL
PUSH 0 ; RESET
CALL VIOSETCURPOS
PUSH DS
PUSH OFFSET BLANK
PUSH LAST_LENGTH ; LENGTH OF LAST LINE
PUSH INIT_CUR_ROW
PUSH INIT_CUR_COL
PUSH 0
CALL VIOWRTNCHAR
PUSH DS
PUSH OFFSET WORKBUFF
PUSH WORKPTR
PUSH 0
CALL VIOWRTTTY
PUSH DS
PUSH OFFSET CURR_CUR_ROW
PUSH DS
PUSH OFFSET CURR_CUR_COL
PUSH 0
CALL VIOGETCURPOS
MOV AX,WORKPTR
MOV LAST_LENGTH,AX
ADD AX,INIT_CUR_COL
CMP AX,80
JL DISPBUFF1
MOV AX,INIT_CUR_ROW
CMP AX,CURR_CUR_ROW
JNE DISPBUFF1
DEC INIT_CUR_ROW
DISPBUFF1:
JMP KEYLOOP
;
; AT DO_CPUP WE WANT TO CLEAR THE ENTIRE RECALL BUFFER
;
DO_CPUP:
MOV DI,OFFSET KEYBUFF
MOV CX,KEYLEN
MOV AL,0
REP STOSB
MOV KEYTAIL,0
MOV CURRPTR,0
JMP DO_ESC ; CLEAR LINE
;
; AT DO_CPDN WE NEED TO DELETE THE CURRENT LINE (POINTED TO BY CURRPTR).
; NOTE THAT CURRPTR WILL POINT TO THE FIRST CHAR OF THE CURRENTLY
; RECALLED LINE. IF IT POINTS TO A ZERO, WE HAVE NOT DONE A RECALL
; SO SHOULD NOT ALLOW THE DELETION
;
DO_CPDN:
MOV BX,CURRPTR ; POINT TO CURRENT LINE
;
DO_CPDN1:
MOV AL,KEYBUFF[BX]
CMP AL,0 ; IF ZERO WE ARE DONE
JE DO_CPDN2
MOV AL,0 ; CLEAR THIS CHAR
MOV KEYBUFF[BX],AL
INC BX ; POINT TO NEXT
AND BX,KEYLEN-1 ; KEEP IN RANGE
CMP BX,CURRPTR ; HAVE WE LOOPED
JE DO_CPDN2 ; YES
JMP DO_CPDN1 ; NO, KEEP CLEARING
;
DO_CPDN2:
JMP DO_UP
;
; AT TOO_MANY WE ALREADY HAVE AS MANY KEYS AS WE WILL ACCEPT
;
TOO_MANY:
PUSH 300
PUSH 16
CALL DOSBEEP
PUSH 600
PUSH 16
CALL DOSBEEP
JMP KEYLOOP
;
; AT KEYDONE WE HAVE FINISHED ALL EDITING FUNCTIONS. MOVE THE NEW LINE
; INTO THE FUNCTION KEY BUFFER. CLEAN UP THE STACK AND GO HOME.
;
KEYDONE:
MOV DI,OFFSET FUNCBUFF
MOV SI,OFFSET WORKBUFF
MOV CX,WORKTAIL
MOV FUNCMAX,CX
DEC CX
REP MOVSB
MOV AL,0
STOSB
MOV FUNCPTR,0
;
PUSH DS
PUSH OFFSET O_CUR_SLINE
PUSH 0
CALL VIOSETCURTYPE
POPF
POP DX
POP CX
POP BX
POP AX
POP ES
POP DS
POP SI
POP DI
POP BP
MOV AX,0
RET
NOT_OURS:
POPF
POP DX
POP CX
POP BX
POP AX
POP ES
POP DS
POP SI
POP DI
POP BP
NOT_OURS1:
MOV AX,-1
RET
BAD_FUNC:
PUSH DS
PUSH OFFSET O_CUR_SLINE
PUSH 0
CALL VIOSETCURTYPE
POPF
POP DX
POP CX
POP BX
POP AX
POP ES
POP DS
POP SI
POP DI
POP BP
MOV AX,-1
RET
KEYSTRIN ENDP
;
; GETKEY IS THE CALL TO READ ANOTHER KEY FROM DEVICE DRIVER
;
GETKEY PROC NEAR
PUSH DS
PUSH OFFSET KEYDEVBUF
PUSH DS
PUSH OFFSET KEYDEVPRM
PUSH 74H ; READ CHARACTER FUNCTION
PUSH 04H ; KEYBOARD CONTROL CATEGORY
MOV AX,KEYHAND
PUSH AX
CALL DOSDEVIOCTL
RET
GETKEY ENDP
;
; DISPTAIL WILL (RE)DISPLAY WORKBUFF FROM WORKPTR TO WORKTAIL
; IF AX == 0 THE CURRENT CURSOR POSITION WILL NOT BE UPDATED UNLESS
; A LINE WRAP OCCURRED, THEN CURR_CUR_ROW AND INIT_CUR_ROW WILL BE
; FIXED. IF AX != 0 CURSOR WILL BE BUMPED BY AX POSITIONS.
; THIS_LENGTH WILL ALWAYS BE UPDATED
;
DISPTAIL PROC NEAR
PUSH BX
PUSH CX
PUSH DX
PUSH AX
MOV AX,WORKTAIL
DEC AX
MOV THIS_LENGTH,AX
CMP AX,LAST_LENGTH
JLE DISPT1
MOV LAST_LENGTH,AX
DISPT1:
PUSH DS
MOV AX,WORKPTR
ADD AX,OFFSET WORKBUFF
PUSH AX
MOV AX,WORKTAIL
SUB AX,WORKPTR
PUSH AX
XOR AX,AX
PUSH AX
CALL VIOWRTTTY
MOV BX,CURR_CUR_ROW ; SAVE OLD CUR_POS
MOV CX,CURR_CUR_COL
PUSH DS
PUSH OFFSET CURR_CUR_ROW
PUSH DS
PUSH OFFSET CURR_CUR_COL
PUSH 0
CALL VIOGETCURPOS
POP AX ; SHOULD WE UPDATE CUR_POS
CMP AX,0 ; TO END OF LINE
JE NO_UPDATE_CUR ; NO
JMP UPDATE_CUR
;
NO_UPDATE_CUR:
MOV AX,WORKTAIL ; NO UPDATE
ADD AX,INIT_CUR_COL
CMP AX,80 ; DID WE WRAP A LINE?
JL RESET_CUR ; NO
MOV AX,INIT_CUR_ROW ; YES
CMP AX,CURR_CUR_ROW ; DID ROW CHANGE
JNE RESET_CUR ; NO, THE SCREEN DID NOT SCROLL
DEC AX ; YES, THE SCREEN SCROLLED
MOV INIT_CUR_ROW,AX ; MOVE INIT_CUR_ROW BACK ONE
MOV BX,AX ; SHOW CURR_CUR_ROW BACK ONE
RESET_CUR:
MOV CURR_CUR_ROW,BX ; DO NOT UPDATE CURSOR POSITION
MOV CURR_CUR_COL,CX
PUSH BX ; RESET CURSOR POSITION
PUSH CX
PUSH 0
CALL VIOSETCURPOS
JMP DISPTDONE
;
;
UPDATE_CUR:
MOV CURR_CUR_ROW,BX
MOV CURR_CUR_COL,CX
ADD AX,CX
MOV CURR_CUR_COL,AX
CMP AX,80
JL DISPTDONE ; NO LINE WRAP
SUB AX,80
MOV CURR_CUR_COL,AX
INC CURR_CUR_ROW
MOV AX,INIT_CUR_ROW
CMP AX,CURR_CUR_ROW ; THERE WAS A LINE WRAP
JNE DISPTDONE ; BUT THE SCREEN DID NOT SCROLL
DEC AX ; THE SCREEN DID SCROLL
MOV INIT_CUR_ROW,AX ; SHOW INIT_CUR AS BACK ONE LINE
;
DISPTDONE:
PUSH CURR_CUR_ROW
PUSH CURR_CUR_COL
PUSH 0
CALL VIOSETCURPOS
POP DX
POP CX
POP BX
RET
DISPTAIL ENDP
;
; ADDSYN IS THE PUBLIC ENTRY POINT TO THE ALIAS SYSTEM.
; ADDSYN IS CALLED WITH A FAR POINTER TO AN ASCIIZ ALIAS.
; THE ALIAS TAKES THE FORM OF ALIAS REPLACEMENT. ALIAS MUST NOT
; CONTAIN ANY SPACES, REPLACEMENT IS ASCIIZ. ON RETURN AX == 0
; IF SUCCESSUFLLY ADDED, AX != 0 IF BUFFER FULL.
;
; THE ALIAS BUFFER CONSISTS OF SETS OF ALIAS REPLACEMENTS STORED AS FOLLOWS:
; ALIASA,0FFH,REPLACEMENTA,0H,ALIASB,0FFH,REPLACEMENTB,0H...
; ALIASN,0FFH,REPLACEMENTN,0H,0FFH
;
ASSUME CS:KEYREP, DS:SBUFF, ES:LBUFF
PUBLIC ADDSYN
;
ADDSYN PROC FAR
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
PUSH DI
PUSH SI
PUSH ES
PUSH DS
MOV AX,SEG SBUFF
MOV DS,AX
ASSUME ES:SBUFF
;
A0:
; OK, WE ARE LOADED.
; STACK LOOKS LIKE THIS:
; [BP+0] - BP
; [BP+2] - RETURN SEGMENT
; [BP+4] - RETURN OFFSET
; [BP+6] - OFFSET OF ALIAS STRING
; [BP+8] - SEGMENT OF ALIAS STRING
MOV AX,SEG SBUFF
MOV ES,AX
MOV DI,ES:SYNHEAD ; ES:DI POINTS TO ALIAS BUFFER
MOV AX,[BP+8]
MOV DS,AX
MOV SI,[BP+6] ; DS:SI POINTS TO ALIAS STRING
MOV DX,SYNLEN-1
MOV CX,0
PUSH SI
;
A1: ; SCAN FOR LENGTH OF ALIAS
LODSB
INC CX
CMP AL,' '
JE A2
CMP AL,0
JNE A1
JMP DEL_SYN
;
A2:
DEC CX
POP SI
CMP DI,ES:SYNTAIL ; ARE WE AT START OF BUFFER?
JE ADDSYN1 ; YES, JUST DO ADD
CALL CMPSTR ; NO, LOOK FOR ALIAS
CMP AX,0
JNE ADDSYN1
JMP REPLACE_SYN
;
ADDSYN1:
MOV CX,0 ; CLEAR COUNT
PUSH SI ; POINTER TO ALIAS STRING
;
ALIAS_LEN:
LODSB ; GET CHAR
INC CX
CMP AL,0
JNE ALIAS_LEN
;
PUSH CX ; CONTAINS LENGTH OF NEW ALIAS
PUSH DI ; END OF ALIAS BUFFER
ALIAS_LEN1:
INC DI
CMP DI,SYNLEN
JE NO_ROOM
LOOP ALIAS_LEN1
JMP HAVE_ROOM
;
NO_ROOM: ; NOT ENOUGH ROOM FOR NEW ALIAS
POP DI
POP CX
POP SI
JMP ADD_FAIL
;
HAVE_ROOM: ; WE HAVE ROOM
POP DI
POP CX
POP SI
PUSH DI ; SAVE POINTER FOR A MOMENT
;
PUT_ALIAS_IN:
LODSB
STOSB
LOOP PUT_ALIAS_IN
MOV AL,0FFH ; MARK END OF ALIAS
STOSB ; STORE IT
MOV ES:SYNTAIL,DI ; NEW SYNTAIL
POP DI ; RESTORE POINTER TO START
;
FIND_FIRST_SPACE:
MOV AL,ES:[DI]
CMP AL,' ' ; SCAN FOR FIRST SPACE
JE FOUND_FIRST_SPACE
INC DI
JMP FIND_FIRST_SPACE
;
FOUND_FIRST_SPACE:
MOV AL,0FFH
MOV ES:[DI],AL
POP DS
POP ES
POP SI
POP DI
POP DX
POP CX
POP BX
POP BP
MOV AX,0
RET 4
;
; AT REPLACE_SYN, WE NEED TO REPLACE AN EXISTING ALIAS. WHAT WE WILL DO
; IS TO DELETE THIS ALIAS AND SLIDE THE BUFFER CLOSED. WE THEN
; REJOIN THE CODE TO ADD AN ALIAS. ON ENTRY DI POINTS TO THE
; START OF THE REPLACEMENT STRING FOR THIS ALIAS SOURCE. WE NEED
; TO BACK DI UP TO THE START OF THIS ALIAS.
;
REPLACE_SYN:
PUSH DS
PUSH ES
POP DS
R1:
DEC DI
CMP DI,0 ; AT START OF BUFFER?
JE R1A
CMP BYTE PTR [DI],0 ; AT START OF ALIAS
JNE R1 ; NO, KEEP LOOKING
INC DI ; POINT DI TO FIRST CHAR OF ALIAS
R1A:
MOV SI,DI
;
R2: ; SCAN FOR END OF REPLACEMENT
LODSB
CMP AL,0
JNE R2
;
CMP BYTE PTR [SI],0FFH ; WAS THIS LAST STRING?
JNE R3 ; NO
MOV AL,0FFH ; YES, JUST MARK END.
STOSB ; DI STILL POINTS TO START.
MOV SYNTAIL,DI
JMP LAST_ALIAS
;
R3:
MOV CX,SYNTAIL
SUB CX,SI ; COUNT OF CHARACTERS TO MOVE
REP MOVSB
MOV SYNTAIL,DI
;
LAST_ALIAS:
POP DS
JMP A0 ; JOIN CODE FOR ADD.
;
; AT DEL_SYN WE NEED TO REMOVE THIS ALIAS ENTIRELY
; THE LOGIC IS THE SAME AS REPLACE_SYN ABOVE.
;
DEL_SYN:
DEC CX ; CX IS LENGTH OF ALIAS
POP SI ; RESTORE START OF ALIAS
CALL CMPSTR ; LOOK FOR ALIAS
CMP AX,0
JNE DEL_SYN5 ; ALIAS DOES NOT EXIST
PUSH ES
POP DS
DEL_SYN1:
DEC DI
CMP DI,0 ; AT START OF BUFFER?
JE DEL_SYN2
CMP BYTE PTR [DI],0 ; AT START OF ALIAS
JNE DEL_SYN1 ; NO, KEEP LOOKING
INC DI ; POINT DI TO FIRST CHAR OF ALIAS
DEL_SYN2:
MOV SI,DI
;
DEL_SYN3: ; SCAN FOR END OF REPLACEMENT
LODSB
CMP AL,0
JNE DEL_SYN3
;
CMP BYTE PTR [SI],0FFH ; WAS THIS LAST STRING?
JNE DEL_SYN4 ; NO
MOV AL,0FFH ; YES, JUST MARK END.
STOSB ; DI STILL POINTS TO START.
MOV SYNTAIL,DI
JMP DEL_SYN5
;
DEL_SYN4:
MOV CX,SYNTAIL
SUB CX,SI ; COUNT OF CHARACTERS TO MOVE
REP MOVSB
MOV SYNTAIL,DI
;
DEL_SYN5:
POP DS
POP ES
POP SI
POP DI
POP DX
POP CX
POP BX
POP BP
MOV AX,0
RET 4
;
ADD_FAIL:
POP DS
POP ES
POP SI
POP DI
POP DX
POP CX
POP BX
POP BP
MOV AX,1
RET 4
;
ADD_FAIL2:
POP DS
POP ES
POP SI
POP DI
POP DX
POP CX
POP BX
POP BP
MOV AX,2
RET 4
;
ADDSYN ENDP
ASSUME CS:KEYREP, DS:SBUFF, ES:SBUFF
;
; CLEARSYN WILL SIMPLY CLEAR OUT ALL ALIASES
;
PUBLIC CLEARSYN
CLEARSYN PROC FAR
PUSH BX
PUSH CX
PUSH DX
PUSH DS
PUSH ES
;
ASSUME DS:SBUFF
;
C1:
MOV AX,SEG SBUFF
MOV DS,AX
XOR AX,AX
MOV SYNHEAD,AX
MOV SYNTAIL,AX
MOV BX,AX
MOV CX,SYNLEN
CLEAR1: MOV [BX],AL
INC BX
LOOP CLEAR1
;
CLEAR2:
POP ES
POP DS
POP DX
POP CX
POP BX
MOV AX,0
RET
;
CLEAR3:
POP ES
POP DS
POP DX
POP CX
POP BX
MOV AX,1
RET
CLEARSYN ENDP
ASSUME CS:KEYREP, DS:SBUFF, ES:SBUFF
PUBLIC LIST_SYN
;
; LIST_SYN WILL LIST THE CURRENT ALIASES OUT TO STDOUT
;
LIST_SYN PROC FAR
PUSH BP
MOV BP,SP
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH ES
PUSH DS
MOV AX,SEG SBUFF
MOV DS,AX
JMP LIST_SYN1
;
ASSUME ES:SBUFF
;
LIST_SYN1:
MOV AX,DS
MOV ES,AX
MOV SI,SYNHEAD
CMP SI,SYNTAIL
JNE GET_SYN0
JMP NO_SYN_LIST
;
GET_SYN0:
MOV DI,OFFSET PRINT_LINE
MOV CX,0
GET_SYN:
LODSB
CMP AL,0FFH
JE GET_SYN1
STOSB
INC CX
JMP GET_SYN
;
GET_SYN1:
MOV AL,20H
STOSB
INC CX
;
GET_SYN2:
LODSB
CMP AL,0
JE GET_SYN3
STOSB
INC CX
JMP GET_SYN2
;
GET_SYN3:
MOV AL,0DH
STOSB
MOV AL,0AH
STOSB
ADD CX,2
MOV AX,1
PUSH AX
MOV DI,OFFSET PRINT_LINE
PUSH DS
PUSH DI
PUSH CX
PUSH DS
MOV AX,OFFSET WRITTEN
PUSH AX
CALL DOSWRITE
;
CMP BYTE PTR [SI],0FFH
JE GET_SYN4
;
MOV CX,0
JMP GET_SYN
;
GET_SYN4:
POP DS
POP ES
POP DI
POP SI
POP DX
POP CX
POP BX
POP BP
MOV AX,0
RET
;
NO_SYN_LIST:
POP DS
POP ES
POP DI
POP SI
POP DX
POP CX
POP BX
POP BP
MOV AX,1
RET
;
NO_SYN_LIST2:
POP DS
POP ES
POP DI
POP SI
POP DX
POP CX
POP BX
POP BP
MOV AX,2
RET
;
LIST_SYN ENDP
;
; ON ENTRY TO ALIAS BOTH DS AND ES POINT TO LBUFF
; WE WANT TO SET ES TO SYN AND SCAN THROUGH SBUFFER TO FIND A
; MATCHING ALIAS. IF FOUND WE WILL COPY THAT BACK TO THE CALLING
; ROUTINE ALONG WITH THE REMAINDER OF WORKBUFF
;
ASSUME CS:KEYREP, DS:LBUFF, ES:SBUFF
ALIAS PROC
PUSH BX
PUSH CX
PUSH DX
PUSH SI
PUSH DI
PUSH DS
PUSH ES
MOV SI,OFFSET WORKBUFF
PUSH SI
MOV CX,0
FIND_END:
LODSB
INC CX
CMP AL,' '
JE FOUND_END
CMP AL,0DH
JNE FIND_END
FOUND_END:
DEC CX
POP SI
; SI POINTS TO SOURCE TO MATCH
; CX IS LENGTH TO MATCH
; ACTUALLY [SI+CX] == ' '
MOV AX,SEG SBUFF
MOV ES,AX
MOV DX,SYNLEN
DEC DX
MOV DI,ES:SYNHEAD ; START OF SYNBUFF IN ES
CMP DI,ES:SYNTAIL ; ANYTHING IN BUFFER?
JE NOSYN ; NO
CALL CMPSTR ; YES, GO LOOKING
CMP AX,0
JE GOTSYN
JMP NOSYN
;
; AT GOTSYN, WE FOUND AN ALIAS. ES:DI POINTS TO START OF REPLACEMENT
; DS:SI STILL POINTS TO START OF SOURCE AND CX STILL CONTAINS
; LENGTH OF SOURCE
;
GOTSYN: MOV BX,DI ; BX POINTS TO REPLACEMENT
MOV DI,OFFSET XMITBUFF
MOV AX,ES
PUSH DS
POP ES
MOV DS,AX
;
ALOOP4: MOV AL,[BX] ; REPLACEMENT IN DS:[BX]
CMP AL,0 ; XMITBUFF IN ES:[DI]
JE ALOOP5
STOSB
INC BX
AND BX,SYNLEN-1
JMP ALOOP4
;
ALOOP5: PUSH ES
POP DS ; DS NOW POINTS TO BOTH WORKBUFF AND XMITBUFF
ADD SI,CX
;
ALOOP6: LODSB
CMP AL,0DH
JE ALOOP7
STOSB
JMP ALOOP6
;
ALOOP7: STOSB
POP ES
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
MOV AX,0
JMP ALOOPDONE
;
NOSYN:
POP ES
POP DS
POP DI
POP SI
POP DX
POP CX
POP BX
MOV AX,1
;
ALOOPDONE:
RET
ALIAS ENDP
;
; CMPSTR IS A ROUTINE TO COMPARE A SOURCE STRING IN DS:SI OF LENGTH CX
; TO A SET OF STRINGS IN A CIRCULAR BUFFER ES:DI OF LENGTH DX+1.
; THE STRINGS ARE FORMED AS STRINGA,0FFH,STRINGB,0H. WE ATTEMPT TO
; MATCH THE SOURCE STRING WITH STRINGA. THE FINAL STRING SET IS
; TERMINATED WITH A 0H AND A 0FFH.
; ON RETURN, IF AX==0 MATCH FOUND AND DI POINTS TO REPLACEMENT.
; IF AX == 1 NO MATCH FOUND AND DI POINTS TO END OF BUFFER.
;
CMPSTR PROC NEAR
PUSH SI
PUSH CX
S_LOOP: LODSB
CMP AL,61H
JL S_LOOP1
CMP AL,7AH
JG S_LOOP1
SUB AL,20H
S_LOOP1:
MOV AH,AL
MOV AL,ES:[DI]
CMP AL,61H
JL S_LOOP2
CMP AL,7AH
JG S_LOOP2
SUB AL,20H
S_LOOP2:
CMP AL,AH
JNE NO_MATCH
INC DI
AND DI,DX
LOOP S_LOOP
E_LOOP: CMP BYTE PTR ES:[DI],0FFH
JE FOUND_MATCH
JMP NO_MATCH1
NO_MATCH:
INC DI
AND DI,DX
NO_MATCH1:
CMP BYTE PTR ES:[DI],0
JNE NO_MATCH
INC DI
AND DI,DX
CMP BYTE PTR ES:[DI],0FFH
JE FAIL
POP CX
POP SI
PUSH SI
PUSH CX
JMP S_LOOP
;
FOUND_MATCH:
POP CX
POP SI
INC DI
MOV AX,0
RET
;
FAIL: POP CX
POP SI
MOV AX,1
RET
CMPSTR ENDP
KEYREP ENDS
END START