home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
msvp98b1.lzh
/
MSSCMD.ASM
< prev
next >
Wrap
Assembly Source File
|
1993-05-14
|
76KB
|
2,406 lines
NAME msscmd
; File MSSCMD.ASM
include mssdef.h
; Copyright (C) 1985, 1992, Trustees of Columbia University in the
; City of New York. Permission is granted to any individual or institution
; to use this software as long as it is not sold for profit. This copyright
; notice must be retained. This software may not be included in commercial
; products without written permission of Columbia University.
;
; Edit history:
; 6 Sept 1991 version 3.11
; 13 March 1991 version 3.10
; Last edit 18 August 1992
; 5 Jan 1991 Add \$(Environment variable) substitution.
; 9 Sept 1990 Add \v(named variable) substitution.
; 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 "-<cr>" as line continuation pair and let "\-<cr>"
; stand for "-<end of line>". 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, isdev, iseof, prompt, tolowr, valbuf, valtab
public parstate, pardone, parfail, nparam, param, lparam, ninter
public inter, atparse, atpclr, atdispat, cspb, dspb, mprompt, nvaltoa
public keyboard
env equ 2CH ; environment address in psp
braceop equ 7bh ; opening curly brace
bracecl equ 7dh ; closing curly brace
data segment
extrn flags:byte, taklev:byte, takadr:word, mcctab:byte
extrn kstatus:word, oldtak:byte, errlev:byte, psp:word
extrn portval:word, bdtab:byte, tdfmt:byte, machnam:byte
extrn verident:word, kstatus:word, errlev:byte, comptab:byte
extrn termtb:byte
; Start Patch structure. Must be first.
even
dspb dw code ; segment values for patcher
dw code1
dw code2
dw data
db 64 dup (0) ; data segment patch buffer
; with space for other material, if req'd
; end of Patch structure
progm db 'MS-DOS_KERMIT$' ; for \v(program)
system db 'MS-DOS$' ; for \v(system)
keyboard dw 88 ; \v(keyboard) kind of keybd 88/101
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$'
cmunk db 'unknown'
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 '\%'
subtype db 0 ; kind of sub (% or v)
bracecnt db 0 ; curly brace counter
cmsflg db 0 ; Non-zero when last char was a space
cmdbuf db cmdblen 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
mcmprmp dw 0 ; master prompt, string address
mcmrprs dd 0 ; master prompt, reparse address
mcmostp dw 0 ; master prompt, stack pointer
temp dw 0 ; temp (counts char/line so far)
valtab db 1+16 ; table of values for \v(value)
mkeyw 'argc)',1
mkeyw 'count)',2
mkeyw 'date)',3
mkeyw 'ndate)',14
mkeyw 'directory)',5
mkeyw 'errorlevel)',4
mkeyw 'keyboard)',10
mkeyw 'line)',15
mkeyw 'platform)',8
mkeyw 'port)',15
mkeyw 'program)',12
mkeyw 'speed)',11
mkeyw 'status)',13
mkeyw 'system)',9
mkeyw 'terminal)',16
mkeyw 'time)',6
mkeyw 'version)',7
envtab db 1 ; \$(..) Environment table
mkeyw 'An Environment variable)',0 ; reserve 0 in valtab
valtmp dw 0
valbuf db 65 dup (0) ; storage of variable definition
even
envadr dd 0 ; seg:offset of a string in Environemt
envlen dw 0 ; length of envadr's string
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
pcmcfrm dw offset cmcfrm,seg cmcfrm ; FAR pointers to main parser procs
pcmkeyw dw offset cmkeyw,seg cmkeyw ; located in code segment code1
pcmtext dw offset cmtext,seg cmtext
pcmfil0 dw offset cmfil0,seg cmfil0
pprserr dw offset prserr,seg prserr
pcmexit dw offset cm6,seg cm6
pfvaltoa dw offset fvaltoa,seg fvaltoa
data ends
code segment
extrn ctlu:near, cmblnk:near, locate:near, takrd:near, dec2di:near
extrn takclos:near, docom:near, prtasz:near, getenv:near
extrn getbaud:near, strlen:near, prtscr:near
assume cs:code, ds:data, es:nothing
; Patch area. Must be first in MSK's Code Seg
cspb equ this byte
db (208-($-cspb)) dup (0) ; code segment patch buffer
; end of Patch area
fctlu proc far ; FAR callable versions of items in seg code
call ctlu ; for calling from code segment code1 below
ret
fctlu endp
fcmblnk proc far
call cmblnk
ret
fcmblnk endp
fgetbaud proc far
call getbaud
ret
fgetbaud endp
fgetenv proc far
call getenv
ret
fgetenv endp
flocate proc far
call locate
ret
flocate endp
ftakrd proc far
call takrd
ret
ftakrd endp
fdec2di proc far
call dec2di
ret
fdec2di endp
fstrlen proc far
call strlen
ret
fstrlen endp
ftakclos proc far
call takclos
ret
ftakclos endp
fprtasz proc far
call prtasz
ret
fprtasz endp
fprtscr proc far
call prtscr
ret
fprtscr endp
fisdev proc far
call isdev
ret
fisdev endp
fiseof proc far
call iseof
ret
fiseof endp
ftolowr proc far
call tolowr
ret
ftolowr endp
nvaltoa proc near
call dword ptr pfvaltoa
ret
nvaltoa endp
; 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
mov bracecnt,0 ; curly brace counter
mov al,taklev ; Take level now
mov oldtak,al ; remember past internal takclos call
cmp ah,cmeol ; Parse a confirm?
jne cm2 ; nz = no
call dword ptr pcmcfrm ; get a Carriage Return end of line
ret
cm2: cmp ah,cmkey ; Parse a keyword?
jne cm3
call dword ptr pcmkeyw ; try and get one
ret
cm3: cmp ah,cmline ; parse line of text
jne cm4
call dword ptr pcmtext
ret
cm4: cmp ah,cmword ; parse arbitrary word
jne cm5
call dword ptr pcmfil0
ret
cm5: mov ah,prstr ; else give error
mov dx,offset cmer00 ; "?Program internal error"
int dos
jmp dword ptr pprserr ; reparse
; Control-C exit path (far to near)
cm6: mov sp,cmdstk ; restore command entry stack pointer
stc
ret ; and fail immediately (a longjmp)
COMND ENDP
code ends
code1 segment
assume cs:code1
; 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
; dw M ; M is the size of the keyword
; 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 far
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 bx,[bx] ; add length of keyword text (CNT)
add bx,2 ; point at value field
mov bx,[bx] ; bx = return value following keyword
xor ax,ax
mov comand.cmper,al ; reset to variable recognition
mov comand.cmkeep,al
mov comand.impdo,al ; clear flag to prevent loops
mov comand.cmquiet,al ; permit echoing again
mov errflag,al
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
xor al,al
mov comand.cmquiet,al ; permit echoing again
mov comand.impdo,al ; 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,ksgen ; global command status, failure
mov comand.cmquiet,0 ; permit echoing again
call fisdev ; 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 dword ptr pcmcfrm ; 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 cx,[bx] ; length of keyword
add bx,2 ; 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 ftolowr ; 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 bx,[bx] ; add length of keyword text
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
xor cx,cx ; 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
xor cl,cl ; 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 ax,[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: or cl,cl ; any keywords found yet?
jnz cmkyh4a ; nz = 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 di,bx ; get current keyword structure
add di,2 ; text part
push cx
mov cx,[bx] ; string length to cx, offset to di
call fprtscr ; display counted string
pop cx
cmkyh5: dec ch ; are we at end of table?
jle cmkyh7 ; le = yes, quit now
add bx,[bx] ; next keyword, add CNT chars to bx
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: or cl,cl ; found any keywords?
jnz cmkyh9 ; nz = yes
mov cx,cmsiz ; length of word
or cx,cx
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 cmptab, user text pointed at by cmsptr and length
; in cmsiz.
cmambg proc near
push bx
push cx
push dx
xor dl,dl ; count keyword matches so far
mov bx,cmptab ; look at start of keyword table
mov cl,[bx] ; get number of entries in table
xor ch,ch ; 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 bx,[bx] ; add CNT chars to bx
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 cmsptr and length is in 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 cx,[bx] ; user's text longer than keyword?
ja cmpwrd2 ; a = yes, no match
push ax
push bx
push si
add bx,2 ; 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 ftolowr ; 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 cmptab and cmsiz holding length of user's keyword (cmpwrd
; needs comand.cmsptr pointing at user's keyword and length of 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
xor ch,ch
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],dx ; 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 bx,[bx] ; next keyword, add CNT chars to bx
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. Cmsptr points to user word,
; 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 ah,conout
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 far
mov cmptab,bx ; save pointer to data buffer
mov cmhlp,dx ; save the help message
xor cx,cx ; 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 short 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 short cmtxt5 ; and record the char
cmtxt2a:mov bx,cmptab ; return updated pointer
xor ax,ax
mov byte ptr[bx],al ; put terminator into the buffer
mov comand.cmwhite,al ; clear leading whitespace flag
mov comand.cmper,al ; reset to variable recognition
mov comand.cmblen,ax ; set user buffer length to unknown
mov comand.cmkeep,al
mov ax,cx ; return count in AX
call rprompt ; restore master prompt level
clc
ret
; Help processor
cmtxt3: inc cmrptr ; count the ?
or cx,cx ; is "?" the first char?
jnz cmtxt5 ; nz = 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
xor al,al
mov [bx],al ; insert null terminator
mov cmptab,bx
cmp cx,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 far
mov cmptab,dx ; save pointer to data buffer
mov cmhlp,bx ; save the help message
mov cmsiz,0 ; init the char count
cmp comand.cmblen,0 ; length of user's buffer given?
jne cmfil0a ; ne = yes
mov comand.cmblen,127 ; else set 127 byte limit plus null
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 short cmfil5 ; put char into the buffer
cmfi1a: cmp ah,escape ; escape?
je cmfi1b ; e = yes
jmp short cmfil2 ; process other terminators
cmfi1b: call esceoc ; do normal escape end-of-command
jmp short cmfil0a ; try again
cmfil2: cmp ah,'?' ; asking a question?
je cmfil3 ; e = yes
xchg dx,bx ; re-interchange bx and dx
xor ax,ax
mov comand.cmwhite,al ; clear whitespace flag
mov comand.cmper,al ; reset to variable recognition
mov comand.cmkeep,al ; do not keep Take file open
mov comand.cmblen,ax ; set user buffer length to unknown
mov bx,cmptab ; pointer into destination array
mov byte ptr[bx],al ; put null terminator into the buffer
inc bx
mov ax,cmsiz ; return count in AX
mov dx,cmptab ; return updated pointer
xchg dx,bx ; re-interchange bx and dx
call rprompt ; restore master prompt level
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
mov cx,cmsiz ; length of command so far
cmp cx,comand.cmblen ; buffer filled?
ja cmfil7 ; a = yes, declare error
jb cmfil6 ; a = not filled yet
mov ah,conout ; notify user that the buffer is full
mov dl,bell
int dos
cmfil6: jmp cmfil1
cmfil7: mov ah,prstr
mov dx,offset cmer09
int dos
jmp prserr ; declare parse error
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 far
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
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
call rprompt ; restore master prompt level
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'. Ditto for \v(variable). Returns carry clear if nothing
; done, else carry set and new text already placed in user's buffer.
; Includes \v(variable) and \$(Environment variable) and \m(macro name).
; Uses depth-first recursion algorithm. All registers preserved.
subst proc near
cmp comand.cmper,0 ; recognize '\%','\v(','\$(','\m(' ?
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
mov subtype,0
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
mov subtype,ah ; remember kind of substitution
or subtype,20h ; convert to lower case
cmp ah,'%' ; second match char, same?
je subst2 ; e = yes
cmp subtype,'v' ; \v(...)?
je subst2 ; e = yes
cmp subtype,'$' ; \$(..)?
je subst2
cmp subtype,'m' ; \m(..)?
je subst2
subst1a:mov subcnt,0 ; mismatch, clear match counter
mov subtype,0 ; clear substitution kind
subst2: clc ; carry clear = no substitution done
ret
subst3: cmp subtype,'v' ; doing \v(..)?
je subst3a ; e = yes
cmp subtype,'$' ; doing \$(..)?
je subst3a ; e = yes
cmp subtype,'m' ; doing \m(..)?
jne subst3b ; ne = no, do \%<char>
subst3a:cmp ah,'(' ; have leading parenthesis?
jne subst1a ; ne = no, mismatch, exit
jmp subst10 ; process \v(..), \$(..), \m(..)
subst3b:mov subcnt,0 ; do \%<char>, clear match counter
cmp ah,'0' ; third char is '0' or above?
jb subst1a ; 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
cmp taklev,maxtak ; room in take level?
jae subst6 ; ae = no
mov cx,[bx] ; length of found word
add cx,2 ; plus count field
add bx,cx ; point to 16 bit value (string ptr)
mov es,[bx] ; point to string structure segment
xor bx,bx
mov cx,es:[bx] ; length of string
add takadr,size takinfo ; pointer to new Take structure
inc taklev
mov bx,takadr ; pointer to new Take structure
mov [bx].takbuf,es ; segment of Take buffer
mov [bx].takcnt,cx ; number of unread bytes
mov [bx].taktyp,0fdh ; flag as an internal macro
mov [bx].takptr,2 ; init pointer to definition itself
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
; \m(..), \v(..), \$(..)
subst10:push bx ; save working regs
push cx
push es
push cmptab ; save current keyword parsing parms
push cmsptr
push cmsiz
push cmhlp
push dx
mov subcnt,0 ; clear match counter
mov cmhlp,0
mov ax,cmrptr
mov valtmp,ax ; remember current read pointer
mov cmsptr,ax ; start of word
mov cmptab,offset valtab ; table of keywords for \v(..)
cmp subtype,'v' ; \v(..)?
je subst10a ; e = yes
mov cmptab,offset envtab ; Environment variable table \$(..)
cmp subtype,'$' ; \$(..)?
je subst10a ; e = yes
mov cmptab,offset mcctab ; main Macro table for \m(..)
subst10a:mov cmsflg,0 ; see leading spaces/tabs
mov cmsiz,0 ; word size
subst11:call cmgtch ; read a character into ah
jnc subst13 ; nc = non-terminator
cmp ah,'?' ; need help?
jne subst11a ; ne = no
jmp cmkyhlp ; do help and exit
subst11a:cmp ah,escape ; escape?
jne subst12 ; ne = no
mov bx,cmsptr ; where word started
mov cmrptr,bx ; omit word to date
mov cmwptr,bx
call cmkyesc ; process escape
mov dx,1 ; signal valtoa to add trailing space
jnc subst14 ; nc = success (found the keyword)
;
subst12:mov bx,cmsptr ; where word started
sub bx,3 ; back over "\v(" pr "\$(" part
mov cmrptr,bx ; omit "\v(..." or "\$(..." to date
mov cmwptr,bx ; and "\m(..." too
jmp repars ; reparse command without \v(...
;
subst13:inc cmsiz ; count user chars
cmp ah,')' ; end bracket?
jne subst11 ; ne = no, keep looking
dec cmsiz ; omit user's ')' from tests
cmp subtype,'$' ; \$(..)?
je subst13a ; e = yes, no keyword in table
call getkw ; \m(..) and \v(..) test for keyword
jc subst12 ; c = failure
jmp short subst13b ; success
subst13a:call envvar ; search Environment for the word
jc subst12 ; c = failure
mov bx,offset envtab+1 ; Environment data structure
subst13b:mov ax,valtmp ; where word started
mov cmrptr,ax
sub ax,3 ; backup to "\v(" or "\$("
mov cmrptr,ax ; write output where backslash was
mov cmwptr,ax
mov cx,[bx] ; bx = structure pointer, cx=keyw len
add cx,2 ; skip count byte
add bx,cx ; point at 16 bit value field
mov bx,[bx] ; get value to bx for valtoa
xor dx,dx ; signal valtoa to not add trailing sp
subst14:
cmp taklev,maxtak ; room in take level?
jb subst15 ; b = yes
mov dx,offset stkmsg ; out of work space msg
mov ah,prstr ; display error message
int dos
jmp short subst17
subst15:push di
call valtoa ; make text be an internal macro
jc subst16 ; c = failed
add takadr,size takinfo ; pointer to new Take structure
inc taklev ; next Take level
push bx
mov bx,takadr ; address of take structure
mov ax,ds
mov [bx].takbuf,ax ; segment of Take buffer
mov [bx].takptr,offset valbuf+2 ; offset of beginning of def text
mov [bx].takcnt,di ; # of chars in buffer
mov [bx].taktyp,0fdh ; flag as an internal macro
pop bx
subst16:pop di
subst17:pop dx
pop cmhlp
pop cmsiz ; restore borrowed keyword parameters
pop cmsptr
pop cmptab
jmp repars ; reparse cmd line with new material
subst endp
; Make an internal macro defined as the text for one of the value variables.
; Use incoming DX as trailing space suppression flag, if null.
valtoa proc near
push dx ; save trailing space flag
mov di,offset valbuf+2 ; start text here
mov word ptr [di],0 ; fill buffer with sweet nothings
; BX has index of variable
cmp bx,0 ; Environment?
jne valtoa1 ; ne = no
mov cx,envlen ; string length
jcxz valtoa0 ; z = empty
push es
push ds
mov ax,ds
mov es,ax ; destination is es:di
lds si,envadr ; ds:si is source from Environment
cld
rep movsb ; copy string
pop ds ; recover ds
pop es
valtoa0:jmp valtoa20
valtoa1:cmp bx,1 ; ARGC?
jne valtoa2 ; ne = no
call wrtargc ; write argc
jmp valtoa20
valtoa2:cmp bx,2 ; COUNT?
jne valtoa3 ; ne = no
call wrtcnt ; write it
jmp valtoa20
valtoa3:cmp bx,3 ; DATE?
jne valtoa4
call wrtdate
jmp valtoa20
valtoa4:cmp bx,4 ; ERRORLEVEL?
jne valtoa5 ; ne = no
call wrterr
jmp valtoa20
valtoa5:cmp bx,5 ; DIR?
jne valtoa6
call wrtdir
jmp valtoa20
valtoa6:cmp bx,6 ; TIME?
jne valtoa7
call wrttime
jmp valtoa20
valtoa7:cmp bx,7 ; VERSION?
jne valtoa8 ; ne = no
mov ax,version ; get version such as 300
call fdec2di ; convert binary to asciiz
mov word ptr [di],0020h ; space, null
inc di
jmp valtoa20
valtoa8:cmp bx,8 ; PLATFORM?
jne valtoa9 ; ne = no
call wrtplat ; get machine name, e.g. "IBM-PC"
jmp valtoa20
valtoa9:cmp bx,9 ; SYSTEM?
jne valtoa10 ; ne = no
call wrtsystem ; get "MS-DOS" string
jmp valtoa20
valtoa10:cmp bx,10 ; KEYBOARD?
jne valtoa11 ; ne = no
call wrtkbd ; 88 or 101 value
jmp valtoa20
valtoa11:cmp bx,11 ; SPEED?
jne valtoa12 ; ne = no
push di
call fgetbaud ; read baud rate from hardware
pop di
mov bx,portval
mov ax,[bx].baud
cmp al,byte ptr bdtab ; index versus number of table entries
jb valtoa11a ; b = index is in the table
mov si,offset cmunk-2 ; unrecognized value, say "unknown"
mov bx,7 ; length of string
jmp short valtoa11c
valtoa11a:mov si,offset bdtab ; ascii rate table
mov cl,[si] ; number of entries
inc si ; point to an entry
valtoa11b:
mov bx,[si] ; length of text string
cmp ax,[si+bx+2] ; our index vs table entry index
je valtoa11c ; e = match
add si,bx ; skip text
add si,4 ; skip count and index word
loop valtoa11b ; look again
mov si,offset cmunk-2 ; unrecognized value, say "unknown"
mov bx,7 ; length of string
valtoa11c:mov cx,bx ; length of string
add si,2 ; point at string
rep movsb ; copy string
jmp short valtoa20
valtoa12:cmp bx,12 ; PROGRAM?
jne valtoa13 ; ne = no
call wrtprog ; get "MS-DOS_KERMIT" string
jmp short valtoa20
valtoa13:cmp bx,13 ; STATUS?
jne valtoa14 ; ne = no
call wrtstat ; compose status string
jmp short valtoa20
valtoa14:cmp bx,14 ; NDATE?
jne valtoa15 ; ne = no
call wrtndate
jmp short valtoa20
valtoa15:cmp bx,15 ; LINE, PORT?
jne valtoa16 ; ne = no
call wrtport
jmp short valtoa20
valtoa16:cmp bx,16 ; TERMINAL?
jne valtoa19 ; ne = no
call wrtterm
jmp short valtoa20
valtoa19:pop dx ; assume an internal Macro
add takadr,size takinfo ; pointer to new Take structure
inc taklev ; next Take level
push bx
mov ax,bx ; save seg of string here
mov bx,takadr ; address of take structure
mov [bx].takbuf,ax ; segment of Take buffer
mov [bx].takptr,2 ; offset of beginning of def text
push es
mov es,ax ; segment of string definition
mov di,es:[0] ; get length of string text (count)
pop es
mov [bx].takcnt,di ; # of chars in buffer
mov [bx].taktyp,0fdh ; flag as an internal macro
pop bx
jmp short valtoax ; exit early with CARRY SET(!)
valtoa20:pop dx ; trailing space flag
or dx,dx ; leave the spaces?
jnz valtoa21 ; nz = yes
cmp word ptr [di-1],0020h ; trailing space?
jne valtoa21 ; ne = no
dec di ; remove space
valtoa21:sub di,offset valbuf+2 ; di = length of the buffer contents
clc
ret
valtoax:stc
ret
valtoa endp
; Far callable version
fvaltoa proc far
call valtoa
ret
fvaltoa endp
; Set envadr to the string following the <variable=> keyword in the
; Environment and set envlen to its length after removing leading and
; trailing whitespace.
; <variable> starts at ds:<valtmp>, of length cmsiz-1, and can be mixed case.
; Return carry set if can't find the <variable=> line in the Environment.
envvar proc near
push es
mov bx,valtmp ; start of variable name
mov cx,cmsiz ; length of variable name, w/o ')'
or cx,cx ; empty?
jle envvar3 ; le = nothing to look for, fail
push bx
push cx
envvar1:mov al,byte ptr [bx] ; scan variable name in our buffer
cmp al,'a' ; lower case
jb envvar2 ; b = no
cmp al,'z' ; still in lower case range?
ja envvar2 ; a = no
and al,not 20h ; convert to DOS's upper case
mov byte ptr [bx],al ; replace char
envvar2:inc bx
loop envvar1
pop cx
pop bx ; find "<variable>=" in Environment
call fgetenv ; dx = offset in Environment of "="
jnc envvar4 ; nc = success
envvar3:pop es ; no such variable
stc ; c = failure
ret
; dx has offset in Environment of char "="
; ds:valtmp is start of variable name, cmsiz is length + 1 of the name.
; Return seg:offset and length variables so we can copy from there in valtoa
envvar4:push di
push si
xor ax,ax
mov word ptr envadr,ax ; offset in env of variable's string
mov word ptr envadr+2,ax ; seg of same
mov envlen,ax ; length of string
mov es,psp ; our Prog Seg Prefix segment
mov ax,es:word ptr[env] ; pick up Environment address
mov es,ax ; set es: to Environment segment
mov di,dx ; line scan pointer
cmp byte ptr es:[di],'=' ; did we stop on this?
jne envvar5 ; ne = no
inc di ; skip the "=" char
envvar5:mov al,es:[di] ; scan over leading white space
inc di
or al,al ; end of line terminator?
jz envvarf ; z = yes, fail
cmp al,TAB ; HT?
jne envvar6 ; ne = no
mov al,' ' ; HT becomes a space
envvar6:cmp al,' ' ; white space?
je envvar5 ; scan off white space
dec di ; backup to non-white char
mov word ptr envadr,di ; offset of string in Environment
mov word ptr envadr+2,es ; seg of string in Environment
mov si,di ; remember starting offset here
; remove trailing spaces from string
xor al,al ; a null
mov cx,127 ; max length to search
cld
repne scasb ; skip over non-nulls
dec di ; backup to null
dec di ; backup to last string char
mov cx,di ; ending offset
inc cx ; count the char
sub cx,si ; minus starting offset yields length
jcxz envvar9 ; z = empty string
envvar7:mov al,es:[di] ; last char
dec di ; backup one char
cmp al,' ' ; space?
je envvar8 ; e = yes
cmp al,TAB ; HT?
jne envvar9 ; ne = no, end of white space
envvar8:loop envvar7 ; keep looking
envvar9:mov envlen,cx ; store the length
clc ; say success
jmp short envvarx
envvarf:stc ; say failure
envvarx:pop si
pop di
pop es
ret
envvar 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 fisdev ; is stdin a device or a file?
jnc cmget20 ; nc = file (redirection of stdin)
jmp cmget10 ; c = device, do separately
cmget20:call fiseof ; 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 fiseof ; 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 ftakrd ; read another buffer
cmp [bx].takcnt,0 ; anything in the buffer?
jne cmget4 ; ne = yes
cmget3: pop bx ; clear stack
jmp short 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: push bx
mov bx,takadr ; offset of this Take structure
mov ah,[bx].taktyp ; save kind of Take/macro
pop bx
cmp ah,0fdh ; internal macro?
je cmget5b ; e = yes, close but no auto-CR
cmp comand.cmkeep,0 ; keep Take/macro open after eof?
jne cmget5a ; ne = yes
cmget5b:push ax
call ftakclos ; close take file
pop ax
cmp ah,0fdh ; internal macro?
jne cmget5a ; ne = no, file or regular macro
jmp cmgetc ; internal macros have no auto CR
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 taklev,0 ; in a Take file or Macro?
je cmget8e ; e = no, use ";" as a literal
push bx ; treat ";" as literal in int macros
mov bx,takadr ; offset of this Take structure
cmp [bx].taktyp,0fdh ; internal macro?
pop bx
je cmget8e ; e = yes, semicolons are literals
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 short 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 short 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 short 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
jmp dword ptr pcmexit ; fail immediately via longjmp
cmgetc endp
; Read chars from user (cmgetc). Detect terminators. Reads from buffer
; cmbuf. Set read pointer 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 "-<cr>" as line continuation, "\-<cr>" as "-<end of line>".
; Return char in AH.
CMINBF proc near ; Buffer reader, final editor
cmp cmwptr,offset cmdbuf+size cmdbuf-3 ; max buffer size - 3
jb cminb1 ; b = not full for writing
mov ah,conout ; almost full, notify user
push dx
mov dl,bell
int dos
pop dx
cmp cmrptr,offset cmdbuf+size cmdbuf ; reading beyond buffer?
jb cminb1 ; b = no
mov ah,prstr
mov dx,offset cmer09 ; command too long
int dos
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
jmp short cminb1 ; call cmgetc until cmwptr >= cmrptr
; 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 ; carriage return?
je cminb6
cmp ah,lf ; line feed?
je cminb6
cmp ah,ff ; formfeed?
jne cminb7 ; none of the above, report bare char
call fcmblnk ; FF: clear the screen and
push bx
push cx
push dx
call flocate ; 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. 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,' ' ; space?
jne cmgtc3 ; ne = no
cmp bracecnt,0 ; are we within braces?
jne cmgtc3 ; ne = yes, treat space as literal
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,braceop ; opening brace?
jne cmgtc3b ; ne = no
inc bracecnt ; count it
jmp short cmgtc3c
cmgtc3b:cmp ah,bracecl ; closing brace?
jne cmgtc3c ; ne = no
sub bracecnt,1 ; count down and get a sign bit
jns cmgtc3c ; ns = no underflow
mov bracecnt,0 ; catch underflows
cmgtc3c: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 cmgtc3d ; ne = yes, make query ordinary char
je cmgtc4
cmgtc3a:cmp ah,cr
je cmgtc4
cmp ah,lf
je cmgtc4
cmp ah,ff
je cmgtc4
cmgtc3d: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
push ax ; count removed curly braces
push si
mov si,cmrptr ; where to look
mov cx,cmwptr ; last place being removed
sub cx,si ; length to examine
cld
bufres1:lodsb
cmp al,braceop ; opening brace, counted already?
jne bufres2 ; ne = no
dec bracecnt ; uncount it
jmp short bufres3
bufres2:cmp al,bracecl ; closing brace, counted already?
jne bufres3 ; jne = no
inc bracecnt ; uncount it
bufres3:loop bufres1
cmp bracecnt,0 ; negative?
jge bufres4 ; ge = no
mov bracecnt,0
bufres4:pop si
pop ax
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
push ax
push si
mov si,cmrptr
mov al,[si]
cmp al,braceop ; opening brace, counted already?
jne bufdel1 ; ne = no
dec bracecnt ; uncount it
jmp short bufdel2
bufdel1:cmp al,bracecl ; closing brace?
jne bufdel2 ; ne = no
inc bracecnt ; uncount it
bufdel2:cmp bracecnt,0 ; negative?
jge bufdel3 ; ge = no
mov bracecnt,0
bufdel3:pop si
pop ax
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
mov bracecnt,0 ; ensure this is now cleared
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
call bufreset ; truncate buffer at cmrptr
mov cx,cmrptr ; read pointer
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
call rprompt ; restore master prompt level
; 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
mov subcnt,0 ; clear substitution state variables
mov subtype,0
mov bracecnt,0
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 fctlu ; clear display's line, reuse it
mov dx,comand.cmprmp ; display the asciiz prompt
call fprtasz
prser3: mov bx,0ffffh ; returned keyword value
mov sp,comand.cmostp ; set new sp to old one
jmp dword ptr comand.cmrprs ; jump to just before the prompt call
PRSERR ENDP
; Restore prompt material to that of the master prompt. This removes settings
; of local PROMPT calls so we can reprompt at the main Kermit level.
RPROMPT proc near
push ax
mov ax,mcmprmp ; address of prompt string
or ax,ax ; any address given yet?
jz rprompt1 ; z = none, not inited yet
mov comand.cmprmp,ax ; set current address ptr
mov ax,word ptr mcmrprs ; offset of reparse address
mov word ptr comand.cmrprs,ax
mov ax,word ptr mcmrprs+2 ; segment of reparse address
mov word ptr comand.cmrprs+2,ax
mov ax,mcmostp ; stack ptr at reparse time
mov comand.cmostp,ax
rprompt1:pop ax
ret
RPROMPT endp
; write \v(ARGC) contents to ds:di
wrtargc proc near
xor ax,ax
cmp taklev,0 ; in a Take/Macro?
je wrtarg1 ; e = no
mov bx,takadr ; current Take structure
mov ax,[bx].takargc ; get ARGC
wrtarg1:call fdec2di ; write as ascii
mov word ptr [di],0020h ; space and null terminator
inc di
ret
wrtargc endp
; write \v(COUNT) text to ds:di
wrtcnt proc near
xor ax,ax
cmp taklev,0 ; in a Take/Macro?
je wrtcnt1 ; e = no
mov bx,takadr ; current Take structure
mov ax,[bx].takctr ; get COUNT
wrtcnt1:call fdec2di ; write as ascii
mov word ptr [di],0020h ; space and null terminator
inc di
ret
wrtcnt endp
; write \v(DATE) text to ds:di
wrtdate proc near
push cx
push dx
mov ah,getdate ; DOS date (cx= yyyy, dh= mm, dl= dd)
int dos
xor ah,ah
cmp tdfmt,0 ; USA standard mm/dd/yyyy?
jne wrtdat1 ; ne = no
mov al,dh ; month
call wrtdat5 ; output
mov byte ptr [di],'/' ; separate
inc di
xor ah,ah
mov al,dl ; day
call wrtdat5
mov byte ptr [di],'/'
inc di
mov ax,cx
jmp short wrtdat3
wrtdat1:cmp tdfmt,1 ; European standard dd/mm/yyyy?
jne wrtdat2 ; ne = no
xor ah,ah
mov al,dl ; day
call wrtdat5
mov byte ptr [di],'/'
inc di
xor ah,ah
mov al,dh ; month
call wrtdat5
mov byte ptr [di],'/'
inc di
mov ax,cx
jmp short wrtdat3
wrtdat2:mov ax,cx ; Japan yyyy:mm:dd, year
call wrtdat5
mov byte ptr [di],':'
inc di
xor ah,ah
mov al,dh ; month
call wrtdat5
mov byte ptr [di],':'
inc di
xor ah,ah
mov al,dl ; day
wrtdat3:call wrtdat5
mov word ptr [di],0020h ; space and null terminator
inc di
pop dx
pop cx
ret
ret
wrtdat5:cmp ax,10 ; leading tens digit present?
jae wrtdat6 ; ae = yes
mov byte ptr [di],'0' ; insert leading 0
inc di
wrtdat6:call fdec2di ; write decimal asciiz to buffer
ret
wrtdate endp
; write \v(ERRORLEVEL) text to ds:di
wrterr proc near
mov al,errlev ; current Errorlevel
xor ah,ah
call fdec2di ; write as ascii
mov word ptr [di],0020h ; space and null terminator
inc di
ret
wrterr endp
; write \v(KEYBOARD) text to ds:di
wrtkbd proc near
mov ax,keyboard ; 88 or 101 keyboard keys
call fdec2di ; write as ascii
mov word ptr [di],0020h ; space and null terminator
inc di
ret
wrtkbd endp
; write \v(NDATE) text to ds:di
; where NDATE is YYYYMMDD
wrtndate proc near
mov ah,getdate ; DOS date (cx= yyyy, dh= mm, dl= dd)
int dos
push dx ; save dx
mov ax,cx ; year
call fdec2di ; convert it
pop dx ; get mm:dd
push dx
mov al,dh ; months are next
xor ah,ah
cmp al,10 ; less than 10?
ja wrtndat1 ; a = no
mov byte ptr [di],'0' ; leading 0
inc di
wrtndat1:call fdec2di
pop dx
mov al,dl ; get days
xor ah,ah
cmp al,10 ; less than 10?
ja wrtndat2 ; a = no
mov byte ptr [di],'0' ; leading 0
inc di
wrtndat2:call fdec2di
mov word ptr [di],0020h ; space and null terminator
inc di
ret
wrtndate endp
; write \v(DIRECTORY) text to ds:di
wrtdir proc near
push si
mov ah,gcurdsk ; get current disk
int dos
add al,'A' ; make al = 0 == 'A'
mov [di],al
mov word ptr [di+1],'\:'
mov si,di ; work buffer
add si,3 ; end with a colon and backslash
mov ah,gcd ; get current directory
xor dl,dl ; use current drive
int dos ; get ds:si = asciiz path (no drive)
mov dx,di
call fstrlen
add di,cx
cmp cx,3 ; directory added?
je wrtdir1 ; e = no
mov byte ptr [di],'\' ; add slash terminator so filenames
inc di ; can be appended easily
wrtdir1:mov word ptr [di],0020h ; space and null terminator
inc di
pop si
ret
wrtdir endp
; write \v(PLATFORM) text to ds:di
wrtplat proc near
push si
mov si,offset machnam ; machine name in sys dep file
cld
wrtplat1:lodsb ; get a char
cmp al,'$' ; terminator?
je wrtplat2 ; e = yes
mov [di],al ; store char
inc di
jmp short wrtplat1 ; keep going
wrtplat2:mov word ptr [di],0020h ; space and null terminator
inc di
mov temp,di ; place for additional text
pop si
ret
wrtplat endp
wrtport proc near
push bx
push si
mov al,flags.comflg ; get coms port indicator
mov bx,offset comptab ; table of comms ports
mov cl,[bx] ; number of entries
xor ch,ch
inc bx
wrtpor3:mov dx,[bx] ; length of this entry
mov si,bx
add si,2 ; points to entry text string
add si,dx ; point to qualifier
cmp [si],al ; our port?
je wrtpor4 ; e = yes
add bx,[bx] ; add text length
add bx,4 ; plus count and qualifier
loop wrtpor3 ; next entry
jmp short wrtpor5 ; no match, curious
wrtpor4:mov si,bx ; point at entry
add si,2 ; point at string
mov cx,[bx] ; length of string
push es
mov ax,ds
mov es,ax
cld
rep movsb ; copy to DS:DI
pop es
wrtpor5:mov word ptr [di],0020h ; space and null terminator
inc di
pop si
pop bx
ret
wrtport endp
; write \v(PROGRAM) text to ds:si
wrtprog proc near
push si
mov si,offset progm ; source string
cld
wrtprg1:lodsb
cmp al,'$' ; terminator?
je wrtprg2 ; e = yes
mov [di],al ; store the char
inc di
jmp short wrtprg1
wrtprg2:mov word ptr [di],0020h ; space and null terminator
inc di
mov temp,di ; place for additional text
pop si
ret
wrtprog endp
; write \v(STATUS) text to ds:di
wrtstat proc near
mov ax,kstatus ; Kermit status word
call fdec2di
mov word ptr [di],0020h ; space and null terminator
inc di
mov temp,di ; place for additional text
ret
wrtstat endp
; write \v(SYSTEM) text to ds:di
wrtsystem proc near
push si
mov si,offset system ; system string "MS-DOS", dollar sign
cld
jmp wrtplat1 ; use some common code
wrtsystem endp
; write \v(TIME) text to ds:di
wrttime proc near
mov ah,gettim ; DOS tod (ch=hh, cl=mm, dh=ss, dl=.s)
int dos
push dx ; save dx
xor ah,ah
mov al,ch ; Hours
cmp al,10 ; leading digit?
jae wrttim1 ; ae = yes
mov byte ptr [di],'0' ; make our own
inc di
wrttim1:push cx
call fdec2di ; write decimal asciiz to buffer
pop cx
mov byte ptr [di],':'
inc di
xor ah,ah
mov al,cl ; Minutes
cmp al,10 ; leading digit?
jae wrttim2 ; ae = yes
mov byte ptr [di],'0' ; make our own
inc di
wrttim2:call fdec2di ; write decimal asciiz to buffer
mov byte ptr [di],':'
inc di
pop dx
xor ah,ah
mov al,dh ; Seconds
cmp al,10 ; leading digit?
jae wrttim3 ; ae = yes
mov byte ptr [di],'0' ; make our own
inc di
wrttim3:call fdec2di ; write decimal asciiz to buffer
mov word ptr [di],0020h ; space and null terminator
inc di
mov temp,di ; place for additional text
ret
wrttime endp
; write \v(Version) text to ds:di
wrtver proc near
mov si,offset verident ; MS Kermit version string in mssker
cld
wrtver1:lodsb
mov [di],al
inc di
cmp al,'$' ; end of string?
jne wrtver1 ; ne = no, continue copying
dec di
mov word ptr [di],0020h ; space and null terminator
inc di
mov temp,di ; place for additional text
ret
wrtver endp
; write \v(terminal) text to ds:di
wrtterm proc near
mov ax,flags.vtflg ; current terminal type
mov bx,offset termtb ; terminal type table msx...
mov cl,[bx] ; number of entries in our table
xor ch,ch
inc bx ; point to the data
wrtter1:mov si,[bx] ; length of keyword
cmp ax,[bx+si+2] ; value fields match?
je wrtter2 ; e = yes
add bx,si ; add word length
add bx,4 ; skip count and value fields
loop wrtter1 ; keep searching
jmp short wrtter4 ; no match, use just a space
wrtter2:mov cx,[bx] ; get length of counted string
mov si,bx
add si,2 ; look at text
cld
wrtter3:lodsb
mov [di],al ; from ds:si to ds:di
inc di
loop wrtter3
wrtter4:mov word ptr [di],0020h ; space and null terminator
inc di
mov temp,di ; place for additional text
ret
wrtterm endp
code1 ends
code segment
assume cs:code
; Set master prompt level. Enter with DX = offset of prompt string
MPROMPT proc near
mov mcmprmp,dx ; offset of prompt string
pop ax ; get the return address
mov word ptr mcmrprs,ax ; offset to go to on reparse
mov mcmostp,sp ; stack pointer at reparse time
push ax ; put it on the stack again
mov ax,cs ; our current code segment
mov word ptr mcmrprs+2,ax ; segment of reparse address
jmp short prompt ; now set the active prompt material
MPROMPT 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 word ptr comand.cmrprs,ax ; offset to go to on reparse
mov comand.cmostp,sp ; save for later restoration
push ax ; put it on the stack again
mov ax,cs ; our current code segment
mov word ptr comand.cmrprs+2,ax ; segment of reparse address
mov ax,offset cmdbuf
mov cmwptr,ax ; reset buffer read/write pointers
mov cmrptr,ax
xor al,al
mov comand.cmper,al ; allow substitutions
mov cmsflg,0ffh ; remove leading spaces
cmp flags.takflg,al ; look at Take flag, zero?
jne promp1 ; ne=supposed to echo, skip this check
cmp taklev,al ; 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.
; 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 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 atparm6 ; 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
atparm6:cmp nparam,0 ; started a parameter yet?
jne atparm7 ; ne = yes
cmp param,0 ; got anything for param[0]?
je atinter ; e = no
atparm7:inc nparam ; yes, say finished with another
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
xor ax,ax ; get a null
mov parstate,offset atparm ; init parser state
mov lparam,al ; clear letter Parameter
mov nparam,ax ; 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
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