NAME msscmd ; File MSSCMD.ASM include mssdef.h ; Edit history: ; Last edit 14 Jan 1990 ; 21 Nov 1988 Version 2.32 ; 17 Oct 1988 Make command keyword search failure yield global kstatus of ; failure status, to inform Take/Macros of a defective command. ; 4 Aug 1988 Fix keyword count initialization in help display. ; 1 July 1988 Version 2.31 ; 7 June 1988 Add comand.impdo flag to permit a keyword search failure to ; retry as a DO cmd (macro table). Used only by main Kermit command level. ; 27 May 1988 Allow "-" as line continuation pair and let "\-" ; stand for "-". Add comand.cmblen to sense buffer overflow on ; calls to cmtxt; if comand.cmblen is left at zero then use 128 byte limit ; (comand.cmblen is cleared at command end). ; 15 May 1988 Make :label keywords no-ops, make query ordinary char in TAKEs. ; 6 May 1988 Show ambiguous keywords at parse time, do graceful interaction. ; 28 March 1988 Permit '\%x' (x = '0' or above) in commands as 'variables' ; (substituted string of text). Words are obtained from Macro table mcctab. ; DEF MAC and DO MAC define variables. DEF macro uses comand.cmper > 0 to ; allow '\%x'to be stored as a literal. Variables work in any command except ; DEF MAC. Major redesign of whole parser. [jrd] ; 4 March 1988 Rewrite keyword parsing to permit non-alphabetized tables ; and 8-bit characters. Add byte comand.cmwhite which when non-zero permits ; leading whitespace in cmline and cmword commands; it is reset at command ; completion. Move procedure Prompt here from mssker. [jrd] ; 27 Feb 1988 Add capability of stdin being a file. [jrd] ; 1 Jan 1988 version 2.30 public comnd, comand, prserr, isdev, iseof, prompt, tolowr public parstate, pardone, parfail, nparam, param, lparam, ninter public inter, atparse, atpclr, atdispat, cspb data segment public 'data' extrn flags:byte, taklev:byte, takadr:word, mcctab:byte extrn kstatus:byte ; Start Patch structure. Must be first. dspb db 128 dup (0) ; data segment patch buffer ; with space for other material, if req'd ; end of Patch structure comand cmdinfo <> cmer00 db cr,lf,'?Program internal error, recovering$' cmer01 db cr,lf,'?More parameters are needed$' cmer02 db cr,lf,'?Word "$' cmer03 db '" is not usable here$' cmer04 db '" is ambiguous$' cmer07 db cr,lf,'?Ignoring extra characters "$' cmer08 db '"$' cmer09 db cr,lf,'?Text exceeded available buffer capacity$' cmin00 db ' Press ENTER to execute command$' cmin01 db ' One of the following:',cr,lf,'$' stkmsg db cr,lf,bell,'?Exhausted work space! Circular definition?$' crlf db cr,lf,'$' ctcmsg db 5eh,'C$' errflag db 0 ; non-zero to suppress cmcfrm errors kwstat db 0 ; get-keyword status prevch db 0 ; previous char read by cmgetc noparse db 0 ; semicolons not special, if non-zero subcnt db 0 ; count of chars matched in '\%' cmsflg db 0 ; Non-zero when the last char was a space cmdbuf db 255 DUP (0) ; Buffer for command parsing even cmdstk dw 0 ; stack pointer at comand call time cmptab dw 0 ; Address of present keyword table cmhlp dw 0 ; Address of present help cmwptr dw 0 ; Pointer for next char write cmrptr dw 0 ; Pointer for next char read cmsiz dw 0 ; Size info of user input cmsptr dw 0 ; Place to save a pointer temp dw 0 ; temp (counts char/line so far) even ; Control sequence storage area maxparam equ 16 ; number of ESC and DCS Parameters maxinter equ 16 ; number of ESC and DCS Intermediates parstate dw 0 ; parser state, init to startup pardone dw 0 ; where to jmp after Final char seen parfail dw 0 ; where to jmp if parser fails nparam dw 0 ; number of received Parameters param dw maxparam dup (0) ; Parameters for ESC lparam db 0 ; a single letter Parameter for ESC ninter dw 0 ; number of received Intermediates inter db maxinter dup (0) ; Intermediates for ESC data ends code segment public 'code' extrn ctlu:near, cmblnk:near, locate:near, takrd:near extrn takclos:near, docom:near, prtasz:near assume cs:code, ds:data, es:nothing ; Patch area. Must be first in MSK's Code Seg cspb dw 256 dup(?) ; code segment patch buffer ; end of Patch area ; This routine parses the specified function in AH. Any additional ; information is in DX and BX. ; Returns carry clear on success and carry set on failure COMND PROC NEAR mov cmdstk,sp ; save stack ptr for longjmp exit mov noparse,0 ; recognize semicolons in Take files cmp ah,cmeol ; Parse a confirm? jne cm2 ; nz = no jmp cmcfrm ; get a Carriage Return end of line cm2: cmp ah,cmkey ; Parse a keyword? jne cm3 jmp cmkeyw ; Try and get one cm3: cmp ah,cmline ; parse line of text jne cm4 jmp cmtext cm4: cmp ah,cmword ; parse arbitrary word jne cm5 jmp cmfil0 cm5: mov ah,prstr ; Else give error mov dx,offset cmer00 ; "?Program internal error" int dos jmp prserr COMND ENDP ; This routine parses a keyword from the table pointed at by DX, help text ; point to by BX. Format of the table is as follows (use macro mkeyw): ; addr: db N ; Where N is the # of entries in the table ; db M ; M is the size of the keyword (excl '$') ; db 'string$' ; String is the keyword ; dw value ; Value is data to be returned ; Keywords may be in any order and in mixed case. ; Return is rskp for success and ret for failure. ; cmptab: pointer to keyword table (supplied by caller) ; cmhlp: pointer to help message (supplied by caller) ; cmsptr: pointer to current user word text ; cmsiz: length of user text, excluding terminator ; comand.cmcr: 0 = empty lines not allowed, 1 = empty lines allowed ; comand.cmwhite: non-zero allows leading whitespace for cmline and cmword, ; reset automatically at end of call ; cmwptr: buffer write pointer to next free byte ; cmrptr: buffer read pointer for next free byte ; comand.cmper: 0 to do \%x substitution. Set to 0 at end of call ; comand.impdo: non-zero permits keyword failure to retry as DO command, reset ; automatically at time of failure. cmkeyw proc near mov cmsiz,0 ; user word length mov ax,cmrptr ; get command reading pointer mov cmsptr,ax ; set pointer for start of user word mov cmhlp,bx ; save the help pointer mov cmptab,dx ; save the beginning of keyword table mov bx,dx cmp byte ptr[bx],0 ; get number of entries in table jne cmky1 jmp cmky7 ; e = no keywords to check, error cmky1: mov cmsflg,0ffh ; skip leading spaces/tabs call cmgtch ; get char from the user into ah jc cmky3 ; c = terminator mov dx,cmrptr ; next byte to read dec dx ; where we just read a char mov cmsptr,dx ; remember start of keyword inc cmsiz ; start counting user chars cmky2: call cmgtch ; read until terminator jc cmky3 ; c = terminator inc cmsiz ; count user chars jmp short cmky2 ; no terminator yet cmky3: cmp ah,'?' ; need help? jne cmky4 ; ne = no jmp cmkyhlp ; do help and exit cmky4: cmp ah,escape ; escape? jne cmky6 ; ne = no call cmkyesc ; process escape jc cmky5 ; c = failure (no unique keyword yet) mov comand.cmper,0 ; reset to variable recognition mov comand.cmkeep,0 mov comand.impdo,0 ; clear flag to prevent loops mov comand.cmquiet,0 ; permit echoing again clc ret ; return successfully to user cmky5: cmp cmsiz,0 ; started a word yet? je cmky1 ; e = no, ignore escape, keep looking jmp cmkyhlp ; ne = yes, show type of error cmky6: cmp cmsiz,0 ; length of user's text, empty? je cmky7 ; e = yes, parse error push bx mov bx,cmsptr ; point at first user character cmp byte ptr[bx],':' ; start of a label? pop bx jne cmky6a ; ne = no, return success mov cmsiz,1 ; say just one byte cmky6a: call getkw ; get unique kw, point to it with bx jc cmky8 ; c = not found add bl,[bx] ; add length of keyword text (CNT) adc bh,0 add bx,2 ; point at value field mov bx,[bx] ; bx = return value following keyword mov comand.cmper,0 ; reset to variable recognition mov comand.cmkeep,0 mov comand.impdo,0 ; clear flag to prevent loops mov comand.cmquiet,0 ; permit echoing again mov errflag,0 clc ret ; return successfully ; all other terminators come here cmky7: cmp cmsiz,0 ; empty table or empty user's text? jne cmky8 ; ne = no cmp comand.cmcr,0 ; empty lines allowed? jne cmky10 ; ne = yes, do not complain push dx mov ah,prstr mov dx,offset cmer01 ; command word expected int dos pop dx mov comand.cmquiet,0 ; permit echoing again mov comand.impdo,0 ; clear flag to prevent loops stc ; failure ret cmky8: cmp comand.impdo,0 ; failed here, ok to try Macro table? je cmky8a ; e = no, use regular exit path mov comand.impdo,0 ; yes, but clear flag to prevent loops mov cmrptr,offset cmdbuf ; reinit read pointer mov comand.cmquiet,1 ; suppress echoing of same keyword mov bx,offset docom ; return DO as "found" keyword clc ret ; return success to invoke DO cmky8a: mov errflag,1 ; say already doing error recovery or kstatus,1 ; global command status, failure mov comand.cmquiet,0 ; permit echoing again call isdev ; reading pretyped lines? jnc cmky9 ; nc = yes, consume rest of line cmp taklev,0 ; in a Take file? jne cmky9 ; ne = yes call cmskw ; display offending keyword dec cmrptr ; interactive, backup to terminator mov bx,cmrptr ; look at it cmp byte ptr [bx],' ' ; got here on space terminator? jne cmky10 ; ne = no, (cr,lf,ff) exit failure mov ah,prstr ; start a fresh line mov dx,offset crlf int dos call bufreset ; cut back buffer to just before term jmp repars ; reparse interactive lines cmky9: call cmcfrm ; get formal end of command line ; to maintain illusion of typeahead ; and let user backspace to correct ; mistakes (we reparse everything) call cmskw ; display offending keyword cmky10: mov comand.cmquiet,0 ; permit echoing again stc ; say failure ret cmkeyw endp ;;;;;; start support routines for keyword parsing. cmkyesc proc near ; deal with escape terminator call bufreset ; reset buffer to end just before ESC cmp cmsiz,0 ; user word length, empty? jne cmkye2 ; ne = have user text, else complain cmkye1: call esceoc ; do normal escape end-of-command stc ; say failure to fill out word ret ; add unique keyword to buffer cmkye2: call getkw ; is there a matching keyword? jc cmkye1 ; c = ambiguous or not found push bx ; unique, bx points to structure push si mov cl,[bx] ; length of keyword mov ch,0 inc bx ; point to first letter mov si,cmwptr ; where next char goes mov dx,cmsiz ; length of user word add bx,dx ; add chars known so far sub cx,dx ; calculate number yet to add add cmsiz,cx jcxz cmkye4 ; z = none mov ah,conout ; display new char cmkye3: mov al,[bx] ; get a keyword letter inc bx call tolowr ; lowercase mov [si],al ; store it inc si mov dl,al int dos ; display it loop cmkye3 ; do all new chars cmkye4: mov byte ptr[si],' ' ; insert space terminator in buffer mov dl,' ' ; display it mov ah,conout int dos inc si mov cmrptr,si ; move token pointer after the space mov cmwptr,si ; next free slot is after the space mov cmsflg,0ffh ; set space-seen flag pop si pop bx ; bx = keyword structure add bl,[bx] ; add length of keyword text adc bh,0 add bx,2 ; point at value field mov bx,[bx] ; bx = return value following keyword clc ; carry clear for success ret cmkyesc endp esceoc proc near ; do normal escape end-of-command push ax push dx mov ah,conout ; ring the bell mov dl,bell int dos pop dx pop ax call bufreset ; reset buffer stc ; say error condition ret esceoc endp ; Help. Question mark entered by user. Display all the keywords that match ; user text. If text is null then use external help if available; otherwise, ; display all keywords in the table. Removes question mark from buffer and ; invokes reparse of command line to-date. User word starts at .cmsptr and ; is .cmsiz bytes long. cmkyhlp proc near mov cx,0 ; clear number of keyword (none yet) cmp cmsiz,0 ; user text given? jne cmkyh1 ; ne = yes, use matching keywords cmp cmhlp,0 ; external help given? jne cmkyh6 ; yes, use it instead of full table cmkyh1: mov temp,0 ; count # chars printed on this line mov bx,cmptab ; beginning of kw table mov ch,[bx] ; length of table mov cl,0 ; no keywords or help displayed yet inc bx ; point at CNT field cmkyh2: cmp cmsiz,0 ; length of user word je cmkyh3 ; e = null, use full table call cmpwrd ; compare keyword with user word jc cmkyh5 ; c = no match, get another keyword cmkyh3: mov al,[bx] ; length of table keyword add byte ptr temp,al ; count chars printed so far cmp temp,76 ; will this take us beyond column 78? jbe cmkyh4 ; be = no, line has more room mov byte ptr temp,al ; reset the count mov ah,prstr mov dx,offset crlf ; break the line int dos cmkyh4: cmp cl,0 ; any keywords found yet? jne cmkyh4a ; ne = yes mov dx,offset cmin01 ; start with One of the following: msg mov ah,prstr int dos inc cl ; say one keyword has been found cmkyh4a:mov dl,spc ; put two spaces before each keyword mov ah,conout int dos int dos add temp,2 ; count output chars mov dx,bx ; get current keyword structure inc dx ; text part mov ah,prstr int dos ; display it cmkyh5: dec ch ; are we at end of table? jle cmkyh7 ; le = yes, quit now add bl,[bx] ; next keyword, add CNT chars to bx adc bh,0 add bx,4 ; skip CNT, '$' and 16 bit value jmp cmkyh2 ; go examine this keyword cmkyh6: mov dx,cmhlp ; external help text mov ah,prstr int dos inc cl ; say gave help already cmkyh7: cmp cl,0 ; found any keywords? jne cmkyh9 ; ne = yes mov cx,cmsiz ; length of word cmp cx,0 jg cmkyh8 ; g = something to show push dx mov ah,prstr mov dx,offset cmer01 ; command word expected int dos pop dx jmp prserr cmkyh8: mov kwstat,0 ; set keyword not-found status call cmskw ; display offending keyword cmkyh9: mov ah,prstr ; start a fresh line mov dx,offset crlf int dos call bufreset ; cut back buffer to just before '?' jmp repars cmkyhlp endp ; See if keyword is ambiguous or not from what the user has typed in. ; Return carry set if word is ambiguous or not found, carry clear otherwise. ; Uses table pointed at by comand.cmptab, user text pointed at by ; comand.cmsptr and length in comand.cmsiz. cmambg proc near push bx push cx push dx mov dl,0 ; count keyword matches so far mov bx,cmptab ; look at start of keyword table mov cl,[bx] ; get number of entries in table mov ch,0 ; use cx as a counter jcxz cmamb8 ; z = no table so always ambiguous inc bx ; look at CNT byte of keyword cmamb4: call cmpwrd ; user vs table words, same? jc cmamb6 ; c = no match inc dl ; count this as a match cmp dl,1 ; more than one match? ja cmamb8 ; a = yes, quit now cmamb6: add bl,[bx] ; add CNT chars to bx adc bh,0 add bx,4 ; skip CNT, '$' and 16 bit value loop cmamb4 ; do rest of keyword table cmp dl,1 ; how many matches were found? jne cmamb8 ; ne = none or more than 1: ambiguous pop dx ; restore main registers pop cx pop bx clc ret ; ret = not ambiguous cmamb8: pop dx ; restore main registers pop cx pop bx stc ret ; return ambiguous or not found cmambg endp ; Compare user text with keyword, abbreviations are considered a match. ; Enter with bx pointing at keyword table CNT field for a keyword. ; Return carry clear if they match, set if they do not match. User text ; pointed at by comand.cmsptr and length is in comand.cmsiz. ; Registers preserved. cmpwrd proc near push cx mov cx,cmsiz ; length of user's text jcxz cmpwrd2 ; z: null user word matches no keyword cmp cl,[bx] ; user's text longer than keyword? ja cmpwrd2 ; a = yes, no match push ax push bx push si inc bx ; point at table's keyword text mov si,cmsptr ; buffer ptr to user input cld cmpwrd1:lodsb ; user text mov ah,[bx] ; keyword text inc bx ; next keyword letter call tolowr ; force lower case on both chars cmp ah,al ; same? loope cmpwrd1 ; e = same so far pop si pop bx pop ax jne cmpwrd2 ; ne = mismatch pop cx ; recover keyword counter clc ; they match ret cmpwrd2:pop cx ; recover keyword counter stc ; they do not match ret cmpwrd endp ; Get pointer to keyword structure using user text. Uses keyword table ; pointed at by comand.cmptab and comand.cmsiz holding length ; of user's keyword (cmpwrd needs comand.cmsptr pointing at user's ; keyword and length of comand.cmsiz). Structure pointer returned in BX. ; Return carry clear for success and carry set for failure. Modifies BX. getkw proc near push cx mov kwstat,0 ; keyword status, set to not-found cmp cmsiz,0 ; length of user word, empty? je getkw3 ; e = yes, fail mov bx,cmptab ; table of keywords mov cl,[bx] ; number of keywords in table mov ch,0 jcxz getkw3 ; z = none, fail inc bx ; point to first getkw1: call cmpwrd ; compare user vs table words jc getkw2 ; c = failed to match word, try next mov kwstat,1 ; say found one keyword, maybe more push dx mov dx,cmsiz ; users word length cmp [bx],dl ; same length (end of keyword)? pop dx je getkw4 ; e = yes, exact match. Done call cmambg ; ambiguous? jnc getkw4 ; nc = unique, done, return with bx mov kwstat,2 ; say more than one such keyword getkw2: add bl,[bx] ; next keyword, add CNT chars to bx adc bh,0 add bx,4 ; skip CNT, '$' and 16 bit value loop getkw1 ; do all, exhaustion = failure getkw3: pop cx stc ; return failure ret getkw4: pop cx clc ; return success ret getkw endp ; show offending keyword message. Comand.cmsptr points to user word, ; comand.cmsiz has length. Modifies AX, CX, and DX. cmskw proc near cmp comand.cmquiet,0 ; Quiet mode? je cmskw0 ; e = no, regular mode ret ; else say nothing cmskw0: mov ah,prstr ; not one of the above terminators mov dx,offset cmer02 ; '?Word "' int dos mov cx,cmsiz ; length of word jcxz cmskw3 ; z = null mov ah,conout push si mov si,cmsptr ; point to word cld cmskw1: lodsb cmp al,' ' ; control code? jae cmskw2 ; ae = no push ax mov dl,5eh ; caret int dos pop ax add al,'A'-1 ; plus ascii bias cmskw2: mov dl,al ; display chars in word int dos loop cmskw1 pop si cmskw3: mov dx,offset cmer03 ; '" not usable here.' cmp kwstat,1 ; kywd status from getkw, not found? jb cmskw4 ; b = not found, a = ambiguous mov dx,offset cmer04 ; '" ambiguous' cmskw4: mov ah,prstr int dos ret cmskw endp ;;;;;;;;;; end of support routines for keyword parsing. ; Parse arbitrary text up to a CR. Enter with BX = pointer to output buffer, ; DX pointing to help text. Produces asciiz string. Return updated pointer in ; BX and output size in AH. Leading spaces are omitted unless comand.cmwhite ; is non-zero (cleared upon exit). It does not need to be followed by the ; usual call to confirm the line. Byte comand.cmblen can be used to specify ; the length of the caller's buffer; cleared to zero by this command to ; imply a length of 127 bytes (default) and if zero at startup use 127 bytes. cmtext proc near mov cmptab,bx ; save pointer to data buffer mov cmhlp,dx ; save the help message mov cx,0 ; init the char count cmp comand.cmblen,0 ; length of user's buffer given? jne cmtxt0 ; ne = yes mov comand.cmblen,127 ; else set 127 byte limit plus null cmtxt0: mov cmsflg,0ffh ; skip initial spaces cmp comand.cmwhite,0 ; allow leading whitespace? je cmtxt1a ; e = no cmtxt1: mov cmsflg,0 ; get all spaces cmtxt1a:call cmgtch ; get a char jnc cmtxt5 ; nc = non-terminator, put in buffer cmp ah,' ' ; space? je cmtxt5 ; e = yes, record it cmp ah,escape ; escape? jne cmtxt2 ; ne = no call esceoc ; do normal escape end-of-command jmp cmtxt0 ; try again cmtxt2: cmp ah,'?' ; asking a question? je cmtxt3 ; e = yes cmp ah,cr ; formal carriage return? je cmtxt2a ; e = yes inc cmrptr ; accept char into buffer jmp cmtxt5 ; and record the char cmtxt2a:mov ah,cl ; return count in AH mov bx,cmptab ; return updated pointer mov byte ptr[bx],0 ; put terminator into the buffer mov comand.cmwhite,0 ; clear leading whitespace flag mov comand.cmper,0 ; reset to variable recognition mov comand.cmblen,0 ; set user buffer length to unknown mov comand.cmkeep,0 clc ret ; Help processor cmtxt3: inc cmrptr ; count the ? cmp cx,0 ; Is "?" first char? jne cmtxt5 ; ne = no, just add to buffer dec cmrptr mov cmsiz,0 ; no keyword for help mov comand.cmwhite,0 ; clear leading whitespace flag cmp cmhlp,0 ; external help given? jne cmtxt3a ; ne = yes mov cmhlp,offset cmin00 ; confirm with c/r msg mov comand.cmblen,0 ; set user buf length to unknown cmtxt3a:jmp cmkyhlp ; do help process cmtxt5: inc cx ; increment the count mov bx,cmptab ; pointer into destination array mov [bx],ah ; put char into the buffer inc bx mov al,0 mov [bx],al ; insert null terminator mov cmptab,bx cmp ch,0 ; overflowed into high byte? jne cmtxt6 ; ne = yes cmp cl,comand.cmblen ; buffer filled? ja cmtxt6 ; a = yes, declare error jb cmtxt5a ; a = not filled yet mov ah,conout ; notify user that the buffer is full mov dl,bell int dos cmtxt5a:jmp cmtxt1 cmtxt6: mov ah,prstr mov dx,offset cmer09 int dos jmp prserr ; declare parse error cmtext endp ; Parse arbitrary text up to whitespace. Enter with DX pointing to output ; buffer and BX pointing to help text. Produces asciiz string. Return updated ; pointer in DX and input size in AH. Skips leading whitespace unless ; comand.cmwhite is non-zero (cleared upon exit). Does a return skip exit. cmfil0 proc near mov cmptab,dx ; save pointer to data buffer mov cmhlp,bx ; save the help message mov cmsiz,0 ; init the char count cmfil0a:cmp comand.cmwhite,0 ; allow leading whitespace? jne cmfil1 ; ne = yes mov cmsflg,0ffh ; omit leading space cmfil1: call cmgtch ; get a char jc cmfi1a ; c = terminator jmp cmfil5 ; put char into the buffer cmfi1a: cmp ah,escape ; escape? je cmfi1b ; e = yes jmp cmfil2 ; process other terminators cmfi1b: call esceoc ; do normal escape end-of-command jmp cmfil0a ; try again cmfil2: cmp ah,'?' ; asking a question? je cmfil3 ; e = yes xchg dx,bx ; re-interchange bx and dx mov comand.cmwhite,0 ; clear whitespace flag mov comand.cmper,0 ; reset to variable recognition mov comand.cmkeep,0 ; do not keep Take file open mov bx,cmptab ; pointer into destination array mov byte ptr[bx],0 ; put null terminator into the buffer inc bx mov ah,byte ptr cmsiz ; return count in AH mov dx,cmptab ; return updated pointer xchg dx,bx ; re-interchange bx and dx clc ret ; return success cmfil3: inc cmrptr ; count the ? cmp cmsiz,0 ; Is "?" first char? jne cmfil5 ; ne = no, just add to buffer dec cmrptr mov cmsiz,0 cmp cmhlp,0 ; external help given? jne cmfil3a ; ne = yes mov cmhlp,offset cmin00 ; confirm with c/r msg cmfil3a:jmp cmkyhlp ; do help process cmfil5: inc cmsiz ; increment the count mov bx,cmptab ; pointer into destination array mov [bx],ah ; put char into the buffer inc bx mov cmptab,bx jmp cmfil1 ; the end of cmfil0 cmfil0 endp ; This routine gets a confirm (CR) and displays any extra non-blank text. ; errflag non-zero means suppress "extra text" display in this routine ; because another routine is handling errors. cmcfrm proc near mov comand.cmper,1 ; do not react to \%x substitutions cmcfr1: mov cmsflg,0ffh ; set space-seen flag (skip spaces) call cmgtch ; get a char push cmrptr pop temp ; remember first non-space position jc cmcfr4 ; c = terminator dec temp ; backup to text char cmcfr3: mov cmsflg,0ffh ; set space-seen flag (skip spaces) call cmgtch jnc cmcfr3 ; read until terminator cmcfr4: cmp ah,' ' je cmcfr3 ; ignore ending on space cmp ah,escape ; escape? jne cmcfr5 ; ne = no call esceoc ; do standard end of cmd on escape mov ax,cmrptr cmp ax,temp ; started text yet? je cmcfr1 ; e = no jmp short cmcfr3 ; try again cmcfr5: cmp ah,'?' ; curious? jne cmcfr6 ; ne = no mov cmhlp,offset cmin00 ; msg Confirm with c/r mov cmsiz,0 ; no keyword mov errflag,0 jmp cmkyhlp ; do help cmcfr6: cmp ah,cr ; the confirmation char? jne cmcfr3 ; ne = no cmp errflag,0 ; already doing one error? jne cmcfr7 ; ne = yes, skip this one mov cx,cmrptr ; pointer to terminator mov dx,temp ; starting place sub cx,dx ; end minus starting point = length cmp cx,0 ; string present? jle cmcfr7 ; le = nothing to display push dx ; save source pointer mov ah,prstr mov dx,offset cmer07 ; ?Ignoring extras int dos pop dx mov bx,1 ; stdout handle, cx=count, dx=src ptr mov ah,write2 ; allow embedded dollar signs int dos mov ah,prstr mov dx,offset cmer08 ; trailer msg int dos cmcfr7: mov errflag,0 mov comand.cmper,0 ; reset to variable recognition mov comand.cmkeep,0 clc ; return confirmed ret cmcfrm endp ;;; Routines to get and edit incoming text. ; Detect '\%x' (x = '0' or above) and substitute the matching Macro string ; in place of the '\%x' phrase in the user's buffer. If comand.cmper != 0 ; then treat '\%' as literal characters. If no matching parameter exists ; just remove '\%x'. Returns carry clear if nothing done, else carry set and ; new text already placed in user's buffer. comand.cmwptr and comand.cmcnt ; are updated. Uses depth-first recursion algorithm. All registers preserved. subst proc near cmp comand.cmper,0 ; should we recognize '\%'? jne subst2 ; ne = no, treat as literals cmp ah,'\' ; is it the first char of the pattern? jne subst1 ; ne = no, try next mov subcnt,1 ; say first is matched jmp short subst2 ; exit successfully subst1: cmp subcnt,1 ; first char matched already? ja subst3 ; a = first two have been matched jb subst2 ; b = none yet inc subcnt ; assume a match follows cmp ah,'%' ; second match char, same? je subst2 ; e = yes mov subcnt,0 ; mismatch, clear match counter subst2: clc ; carry clear = no substitution done ret subst3: mov subcnt,0 ; clear match counter cmp ah,'0' ; third char is '0' or above? jb subst2 ; b = out of range, no match push bx ; save working regs push cx push es sub cmrptr,3 ; reread commands where backslash was call bufreset ; reset buffer to this point push cmptab ; save current keyword parsing parms push cmsptr push cmsiz mov bx,cmrptr ; points at backslash mov cmsptr,bx ; direct keyword routine to it mov cmsiz,3 ; three bytes (\%x) of user text mov cmptab,offset mcctab ; use Macro table for new text call getkw ; get ptr, bx, to matching keyword pop cmsiz ; restore borrowed keyword parameters pop cmsptr pop cmptab jc substx ; c = not found, keep after pops mov cl,[bx] ; length of found word mov ch,0 add cx,2 ; plus count field and '$' add bx,cx ; point to 16 bit value (string ptr) mov es,[bx] ; point to string structure segment mov bx,0 mov cl,es:[bx] ; length of string mov ch,0 inc bx ; skip length byte, es:bx=string addr jcxz substx ; z = nothing left to transfer cld subst4: mov ah,es:[bx] ; get a char inc bx push di ; assume di is used by other routines mov di,cmrptr mov [di],ah ; store char (without es:di) inc di mov cmwptr,di ; where to store next char mov cmrptr,di ; move read pointer too cmp di,offset cmdbuf+size cmdbuf ; reached max buffer size? pop di jae subst6 ; ae = yes, no more room cmp sp,20*2 ; still some stack space? jle subst6 ; le = insufficient room call SUBST ; rescan what we stored (recursion) jnc subst5 ; nc = no substitution, so no kbd test push ax ; break out of loops with Control-C push dx mov ah,constat ; check console status for Control-C int dos ; our control-break handler sees it pop dx ; and cmgetc reads it pop ax subst5: loop subst4 substx: pop es pop cx pop bx stc ; set carry to say have stored chars ret subst6: mov ah,prstr mov dx,offset stkmsg ; out of work space msg int dos jmp prserr ; and declare parse error subst endp ; Read chars from Take file, keyboard, or redirected stdin. Edit and remove ; BS & DEL, Tab becomes space, act on Control-C, pass Control-U and Control-W. ; Do echoing unless comand.cmquiet is non-zero. Do semicolon comments in Take ; and indirect stdin files (\; means literal semicolon). Return char in AL. CMGETC proc near ; Basic raw character reader cmget01:cmp prevch,0 ; left over char yet to be exported? je cmget02 ; e = no mov al,prevch ; get old char mov prevch,0 ; clear storage jmp cmget6 ; analyze it cmget02:cmp taklev,0 ; in a Take file? jne cmget1 ; ne = yes, do Take reader section call isdev ; is stdin a device or a file? jnc cmget20 ; nc = file (redirection of stdin) jmp cmget10 ; c = device, do separately cmget20:call iseof ; see if file is empty jc cmget21 ; c = EOF on disk file mov ah,coninq ; read the char from file, not device int dos cmp al,cr ; is it a cr? je cmget01 ; yes, ignore and read next char cmp al,ctlz ; Control-Z? je cmget21 ; e = yes, same as EOF here cmp al,lf ; LF's end lines from disk files jne cmget8 ; ne = not LF, pass along as is mov al,cr ; make LF a CR for this parser call iseof ; see if this is the last char in file jnc cmget8 ; nc = not EOF, process new CR cmget21:mov flags.extflg,1 ; EOF on disk file, set exit flag jmp short cmget6 ; do echoing and return cmget1: push bx ; read from Take file mov bx,takadr ; offset of this Take structure cmp [bx].takcnt,0 ; bytes remaining in Take buffer jne cmget4 ; ne = not empty cmp [bx].taktyp,0feh ; type of Take (file?) jne cmget3 ; ne = no (macro) call takrd ; read another buffer cmp [bx].takcnt,0 ; anything in the buffer? jne cmget4 ; ne = yes cmget3: pop bx ; clear stack jmp cmget5 ; close take file cmget4: push si push es mov es,[bx].takbuf ; segment of Take buffer mov si,[bx].takptr ; current offset in Take buffer mov al,es:[si] ; read a char from Take buffer inc si mov [bx].takptr,si ; move buffer pointer dec [bx].takcnt ; decrease number of bytes remaining pop es pop si pop bx cmp al,ctlz ; Control-Z? jne cmget6 ; ne = no cmget5: cmp comand.cmkeep,0 ; keep Take/macro open after eof? jne cmget5a ; ne = yes call takclos ; close take file cmget5a:mov al,cr ; report cr as last char mov noparse,0 ; and say end of comment ; start common code cmget6: cmp al,lf ; line feed? jne cmget8 ; ne = no jmp cmget01 ; yes, ignore and read another char ; handle comments (echo but not parse) cmget8: cmp noparse,0 ; parsing? jne cmget9 ; ne = yes, do echo and no parse cmp prevch,0 ; have previous char to analyze? jne cmget8c ; ne = yes cmp al,'\' ; start of '\;'? jne cmget8a ; ne = no mov prevch,al ; yes, maybe. save '\' til later jmp cmget02 ; read next char cmget8a:cmp al,';' ; possible start of comment? jne cmget8e ; no, export al mov al,' ' ; replace ';' with space for comment jmp cmget9 ; go start a comment cmget8c:cmp al,';' ; end of '\;'? je cmget8d ; e = yes, omit leading backslash xchg prevch,al ; no, save new, recover old '\' jmp short cmget8e ; export '\' cmget8d:mov prevch,0 ; clear old '\' cmget8e:jmp cmget12 ; do parsing ; echo comment cmget9: cmp flags.takflg,0 ; echoing take files? je cmget9a ; e = no push ax push dx mov ah,conout ; echo current char mov dl,al int dos pop dx pop ax cmget9a:mov noparse,0 ; cr ends comment cmp al,cr ; end of comment? je cmget13 ; e = yes, export cr mov noparse,1 ; still in comment jmp cmget01 ; read more chars ; read from tty device cmget10:mov ah,coninq ; Get a char from device, not file int dos ; with no echoing or al,al jnz cmget12 ; ignore null bytes of special keys int dos ; read and discard scan code byte jmp cmget10 ; try again cmget12:cmp al,'C'and 1Fh ; Control-C? je cmget14 ; e = yes cmp al,TAB ; tab is replaced by space jne cmget13 ; ne = not tab mov al,' ' ret cmget13:cmp al,LF ; LF becomes CR interactively jne cmget13a mov al,CR cmget13a:ret ; normal exit, char is in AL cmget14:mov ah,prstr ; Control-C handler push dx mov dx,offset ctcmsg ; show Control-C int dos pop dx mov prevch,0 mov flags.cxzflg,'C' ; tell others the news mov sp,cmdstk ; restore command entry stack pointer stc ret ; and fail immediately (a longjmp) cmgetc endp ; Read chars from user (cmgetc). Detect terminators. Reads from buffer ; comand.cmbuf. Set read pointer comand.cmrptr to next free buffer byte if ; char is not a terminator: chars CR, LF, FF, '?' (returns carry set for ; terminators). Do ^U, ^W editing, convert FF to CR plus clear screen. ; Edit "-" as line continuation, "\-" as "-". ; Return char in AH. CMINBF proc near ; Buffer reader, final editor push di mov di,cmwptr ; write pointer cmp di,offset cmdbuf+size cmdbuf-3 ; max buffer size - 3 pop di jb cminb1 ; b = not full mov ah,conout ; almost full, notify user push dx mov dl,bell int dos mov dx,offset cmdbuf+size cmdbuf cmp cmrptr,dx ; max buffer size? pop dx jb cminb1 ; b = more room mov ah,prstr push dx mov dx,offset cmer09 ; command too long int dos pop dx jmp prserr ; overflow = parse error cminb1: push bx mov bx,cmrptr ; read pointer mov ah,[bx] ; get current command char while here cmp bx,cmwptr ; do we need to read more? pop bx ; no if cmrptr < cmwptr jb cminb2 ; b: cmrptr < cmwptr (have extra here) call cmgetc ; no readahead, read another into al mov ah,al ; keep char in 'ah' push bx mov bx,cmwptr ; Get the pointer into the buffer mov [bx],ah ; Put it in the buffer inc bx mov cmwptr,bx ; inc write pointer pop bx ; Char to be delivered is in ah cminb2: cmp ah,'W' and 1fh ; Is it a ^W? jne cminb3 call cntrlw ; Kill the previous word jnc cminbf ; nc = no change, get another char jmp repars ; need a new command scan (cleans stk) cminb3: cmp ah,'U' and 1fh ; Is it a ^U? jne cminb3a ; ne = no mov cmwptr,offset cmdbuf ; reset buffer write pointer jmp repars ; Go start over (cleans stack) ; BS and DEL cminb3a:cmp ah,DEL ; Delete code? je cminb3b ; e = yes cmp ah,BS ; Backspace (a delete operator)? jne cminb4 ; ne = no cminb3b:call bufdel ; delete char from buffer jc cminb3c ; c = did erasure jmp cminbf ; no erasure, ignore BS, get more cminb3c:jmp repars ; could have deleted previous token cminb4: push bx ; look for hyphen or \hyphen cmp ah,cr ; check for hyphen line continuation jne cminb4b ; ne = not end of line mov bx,cmwptr ; Get the pointer into the buffer cmp bx,offset cmdbuf-2 ; do we have a previous char? jb cminb4b ; b = no cmp byte ptr[bx-2],'-' ; previous char was a hyphen? jne cminb4b ; ne = no pop bx call bufdel ; delete the hyphen jmp repars cminb4b:pop bx ; Echoing done here cmp comand.cmquiet,0 ; quiet mode? jne cminb5 ; yes, skip echoing cmp taklev,0 ; in a take file? je cminb4a ; e = no cmp flags.takflg,0 ; echo take file? je cminb5 ; e = no cminb4a:push ax ; save the char cmp ah,' ' ; printable? jae cminb4c ; yes, no translation needed cmp ah,cr ; this is printable je cminb4c cmp ah,lf je cminb4c cmp ah,escape ; escape? je cminb4d ; do not echo this character push ax ; show controls as caret char push dx mov dl,5eh ; caret mov ah,conout int dos pop dx pop ax add ah,'A'-1 ; make control code printable cminb4c:push dx mov dl,ah mov ah,conout int dos ; echo it ourselves pop dx cminb4d:pop ax ; and return char in ah cminb5: cmp ah,cr ; Is it a carriage return? je cminb6 cmp ah,lf ; Is it a line feed? je cminb6 cmp ah,ff ; Is it a formfeed? jne cminb7 ; none of the above, report bare char call cmblnk ; FF: clear the screen and push bx push cx push dx call locate ; Home the cursor mov bx,cmwptr ; make the FF parse like a cr mov byte ptr [bx-1],cr ; pretend a carriage return were typed pop dx pop cx pop bx cminb6: cmp cmwptr,offset cmdbuf ; parsed any chars yet? jne cminb7 ; ne = yes cmp comand.cmcr,0 ; bare cr's allowed? jne cminb7 ; ne = yes jmp prserr ; If not, just start over cminb7: clc ret cminbf endp ; Read chars from cminbf. Comand.cmrptr points to next char to be read. ; Compresses repeated spaces if cmsflg is non-zero. Exit with cmrptr pointing ; at a terminator or otherwise at next free slot. ; Non-space then space acts as a terminator but cmrptr is incremented. ; Substitution variables, '\%x', are detected and expanded. Return char in AH. CMGTCH proc near ; return char in AH, from rescan buf call cminbf ; get char from buffer or user push bx mov bx,cmrptr ; get read pointer into the buffer mov ah,[bx] ; read the next char inc bx mov cmrptr,bx ; where to read next time pop bx call subst ; examine for text substitution jnc cmgtc1 ; nc = no substitutions done jmp repars ; reparse line with new material cmgtc1: cmp ah,' ' ; Is it a space? jne cmgtc3 ; ne = no cmp cmsflg,0 ; space flag, was last char a space? jne cmgtch ; ne = yes, get another char mov cmsflg,0FFH ; Set the space(s)-seen flag mov ah,' ' ; character for caller stc ; set carry for terminator ret ; return space as a terminator cmgtc3: mov cmsflg,0 ; clear the space-seen flag cmp ah,escape ; terminators remain in buffer but je cmgtc4 ; are ready to be overwritten cmp ah,'?' ; Is the user curious? jne cmgtc3a ; ne = no cmp taklev,0 ; in a Take file? jne cmgtc3b ; ne = yes, make query ordinary char je cmgtc4 cmgtc3a:cmp ah,cr je cmgtc4 cmp ah,lf je cmgtc4 cmp ah,ff je cmgtc4 cmgtc3b:clc ; carry clear for non-terminator ret cmgtc4: dec cmrptr ; point at terminating char stc ; set carry to say it is a terminator ret cmgtch endp ; Reset comand.cmdbuf write pointer (.cmwptr) to where the read pointer ; (.cmrptr) is now. Discards material not yet read. bufreset proc near push cmrptr ; where next visible char is read pop cmwptr ; where new char goes in buffer ret bufreset endp ; Delete character from screen and adjust buffer. Returns carry clear if ; no erasure, carry set otherwise. bufdel proc near dec cmrptr ; remove previous char from buffer cmp cmrptr,offset cmdbuf ; back too far? jae bufde2 ; ae = no, material can be erased mov cmrptr,offset cmdbuf ; set to start of buffer call bufreset ; reset buffer clc ; say no erasure ret bufde2: call bufreset ; reset buffer stc ; say did erasure ret bufdel endp ; Come here is user types ^W when during input. Remove word from buffer. cntrlw proc near push ax push cx push dx mov cx,cmrptr ; char beyond what user sees mov cmwptr,cx ; truncate buffer there sub cx,offset cmdbuf ; compute chars in buffer clc ; say have not yet modified line jcxz ctlw2 ; z = nothing to do, exit no-carry push es std ; scan backward mov ax,ds mov es,ax ; point to the data are mov di,cmwptr ; looking from here dec di mov al,' ' repe scasb ; look for non-space je ctlw1 ; all spaces, nothing to do inc di ; move back to non-space inc cx repne scasb ; look for a space jne ctlw1 ; no space, leave ptrs alone inc di inc cx ; skip back over space ctlw1: inc di pop es cld ; reset direction flag mov cmwptr,di ; update pointer stc ; set carry to say modified line ctlw2: pop dx pop cx pop ax ret cntrlw endp ; Jump to REPARS to do a rescan of the existing buffer. ; Jump to PRSERR on a parsing error (quits command, clears old read material) PRSERR PROC NEAR mov cmwptr,offset cmdbuf ; initialize write pointer mov ah,prstr mov dx,offset crlf ; leave old line, start a new one int dos ; reparse current line REPARS: mov cmrptr,offset cmdbuf ; reinit read pointer mov comand.cmper,0 ; reset to variable recognition mov cmsflg,0FFH ; strip leading spaces cmp taklev,0 ; in Take cmd? je prser2 ; e = no cmp flags.takflg,0 ; echo contents of Take file? je prser3 ; e = no prser2: call ctlu ; clear display's line, reuse it mov dx,comand.cmprmp ; display the asciiz prompt call prtasz prser3: mov bx,0ffffh ; returned keyword value mov sp,comand.cmostp ; set new sp to old one jmp comand.cmrprs ; jump to just before the prompt call PRSERR ENDP ; This routine prints the prompt and specifies the reparse address. ; Enter with pointer to prompt string in dx. PROMPT PROC NEAR mov comand.cmprmp,dx ; save the prompt pop ax ; Get the return address mov comand.cmrprs,ax ; Save as address to go to on reparse mov comand.cmostp,sp ; Save for later restoration push ax ; Put it on the stack again mov ax,offset cmdbuf mov cmwptr,ax ; reset buffer read/write pointers mov cmrptr,ax mov ax,0 mov comand.cmper,0 ; allow substitutions mov cmsflg,0FFH ; remove leading spaces cmp flags.takflg,0 ; look at Take flag jne promp1 ; ne=supposed to echo, skip this check cmp taklev,0 ; inside a take file? je promp1 ; no, keep going ret ; yes, return promp1: mov ah,prstr mov dx,offset crlf int dos mov dx,comand.cmprmp ; prompt pointer call prtasz ; show asciiz prompt string clc ret PROMPT ENDP ISDEV PROC NEAR ; Set carry if STDIN is non-disk push ax push bx push dx xor bx,bx ; handle 0 is stdin xor al,al ; get device info mov ah,ioctl int dos rcl dl,1 ; put ISDEV bit into the carry bit pop dx ; carry is set if device pop bx pop ax ret ; carry set if device ISDEV ENDP ISEOF PROC NEAR ; Set carry if STDIN is at EOF push ax ; but only if stdin is a non-device push bx push dx xor bx,bx ; handle 0 is stdin xor al,al ; get device info mov ah,ioctl int dos mov ah,ioctl mov al,6 ; get handle input status, set al test dl,80h ; bit set if handle is for a device jnz iseof1 ; nz = device, always ready (al != 0) int dos iseof1: or al,al ; EOF? pop dx pop bx pop ax jnz iseof2 ; nz = no stc ; set carry for eof ret iseof2: clc ; clear carry for not-eof ret ISEOF ENDP ; Convert ascii characters in al and ah to lowercase. [jrd] ; All registers are preserved except AX, of course. TOLOWR PROC NEAR cmp ah,'A' ; less that cap A? jl tolow1 ; l = yes. leave untouched cmp ah,'Z'+1 ; more than cap Z? jns tolow1 ; ns = yes or ah,20H ; convert to lowercase tolow1: cmp al,'A' ; less that cap A? jl tolow2 ; l = yes. leave untouched cmp al,'Z'+1 ; more than cap Z? jns tolow2 ; ns = yes or al,20H ; convert to lowercase tolow2: ret TOLOWR endp ; Parse control sequences and device control strings. ; Expect CSI, Escape [, or DCS lead-in characters to have been read. ; Puts numerical Parameters in array param (16 bits, count is nparam) and ; a single letter Parameter in lparam, (Parameters are all ASCII column 3) ; Intermediate characters in array inter (count is ninter), (ASCII column 2) ; Final character in AL (ASCII columns 4-7). ; Invoke by setting state to offset atparse, set pardone to offset of ; procedure to jump to after reading Final char (0 means do just ret) ; and optionally setting parfail to address to jump to if parsing failure. ; When the Final char has been accepted this routine jumps to label held in ; pardone for final action. Before the Final char has been read successful ; operations return carry clear. ; Failure exits are carry set, and an optional jump through parfail (if ; non-zero) or a return. atparse proc near mov bx,parstate ; get parsing state or bx,bx ; have any state? jnz atpars1 ; nz = have a state call atpclr ; do initialization mov parstate,offset atparm ; next state is get Parameters mov bx,parstate ; get initial state atpars1:call bx ; execute it jc atpfail ; c = failure cmp parstate,offset atpdone ; parsed final char? je atpdone ; e = yes ret ; no, wait for another char ; successful conclusion, final char is in AL atpdone:mov parstate,0 ; reset parsing state cmp pardone,0 ; separate return address defined? jne atpdon1 ; ne = yes clc ret ; else just return atpdon1:clc jmp pardone ; jmp to supplied action routine atpfail:mov parstate,0 ; failed, reset parser to normal state cmp parfail,0 ; jump address specified? je atpfail1 ; e = no jmp parfail ; yes, exit this way atpfail1:stc ret ; parsing workers atparm: cmp ninter,0 ; Parameter, started intermediate yet? jne atinter ; ne = yes, no more parameters cmp al,';' ; argument separator? jne atparm3 ; ne = no mov ax,nparam ; number of Parameters inc ax ; say a new one cmp ax,maxparam ; too many? jb atparm2 ; b = no, continue stc ; set carry to say failed ret ; too many, ignore remainder atparm2:mov nparam,ax ; say doing another Parameter clc ret atparm3:mov ah,al ; copy char and ah,not 0fh ; ignore low nibble cmp ah,30h ; column 3, row 0? (30h='0') jne atparm8 ; ne = no, check Intermediate/Final cmp al,'9' ; digit? ja atparm5 ; a = no, check letter Parameters sub al,'0' ; ascii to binary mov bx,nparam ; current parameter number shl bx,1 ; convert to word index mov cx,param[bx] ; current parameter value shl cx,1 ; multiply by 10. 2 * cl push bx mov bx,cx ; save 2 * cl shl cx,1 ; 4 * cl shl cx,1 ; 8 * cl add cx,bx ; 10 * cl pop bx add cl,al ; add new digit adc ch,0 jnc atparm4 ; nc = no carry out (65K or below) mov cx,0ffffh ; set to max value atparm4:mov param[bx],cx ; current Parameter value clc ret ; check non-numeric Parameters atparm5:cmp al,'?' ; within column 3? ja atfinal ; a = no, check Final char mov lparam,al ; store non-numeric Parameter clc ret atparm8:inc nparam ; non-column 3, end of Parameters cmp al,3fh ; column 4 and above? ja atfinal ; a = yes, check Final char ; Intermediate chars, all in Column 2 atinter:mov parstate,offset atinter ; next state (intermediate) cmp al,';' ; argument separator? jne atinte1 ; ne = no mov ax,ninter ; number of Intermediates cmp ax,maxinter ; too many? jb atinte2 ; b = no, continue stc ; carry = failed ret ; too many, ignore remainder atinte1:test al,not 2fh ; column two = 20h - 2fh? jnz atfinal ; nz = not an Intermediate, try Final mov bx,ninter ; current Intermediate slot number mov inter[bx],al ; current Intermediate value atinte2:inc ninter ; say doing another Intermediate clc ret atfinal:cmp al,40h ; Final character, range is 40h to 7fh jb atfina1 ; b = out of range cmp al,7fh ja atfina1 ; a = out of range mov parstate,offset atpdone ; next state is "done" clc ; success, final char is in AL ret atfina1:stc ; c = failed ret atparse endp ; Clear Parameter, Intermediate arrays in preparation for parsing atpclr proc near push ax push cx push di push es mov lparam,0 ; clear letter Parameter mov nparam,0 ; clear Parameter count mov cx,maxparam ; number of Parameter slots mov di,offset param ; Parameter slots push ds pop es ; use data segment for es:di below cld ; set direction forward xor ax,ax ; get a null rep stosw ; clear the slots mov ninter,ax ; clear Intermediate count mov cx,maxinter ; number of Intermediate slots mov di,offset inter ; Intermediate slots rep stosb ; clear the slots pop es pop di pop cx pop ax ret atpclr endp ; Dispatch table processor. Enter with BX pointing at table of {char count, ; address of action routines, characters}. Jump to matching routine or return. ; Enter with AL holding received Final char. atdispat proc near mov cl,[bx] ; get table length from first byte xor ch,ch mov di,bx ; main table add di,3 ; point di at first char in table push es push ds pop es ; use data segment for es:di below cld ; set direction forward repne scasb ; find matching character pop es je atdisp2 ; e = found a match, get action addr ret ; ignore escape sequence atdisp2:sub di,bx ; distance scanned in table sub di,4 ; skip count byte, address word, inc shl di,1 ; convert to word index inc bx ; point to address of action routines mov bx,[bx] ; get address of action table jmp word ptr [bx+di] ; dispatch to the routine atdispat endp code ends end