home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
archives
/
ccdos.tar.gz
/
ccdos.tar
/
ccsscp.asm
< prev
next >
Wrap
Assembly Source File
|
1991-09-08
|
84KB
|
1,687 lines
NAME ccsscp
; File CCSSCP.ASM
;CHINESE
ifdef MSDOS
include mssscp.dat
else
include ccsscp.dat
endif
code segment public 'code'
extrn comnd:near, clrbuf:near, prtchr:near, outchr:near, sendbr:near
extrn cptchr:near, serini:near, serrst:near, pcwait:near, katoi:near
extrn cnvstr:near, getmodem:near, isdev:near, isfile:near
extrn takrd:near, takclos:near, tolowr:near, prtasz:near,strlen:near
assume cs:code, ds:datas, es:nothing
; Clear input buffer(s) of serial port
; Clear command
;
SCCLR PROC NEAR
mov kstatus,0 ; global status
mov ah,cmcfm ; get a confirm
call comnd
jmp r ; no confirm
nop
call bufclear ; clear our serial port circular buf
call clrbuf ; clear system serial port buffer too
jmp rskp ; return success
SCCLR ENDP
;
; Echo a line of text to our screen
; Echo text
;
SCECHO PROC NEAR
mov ah,cmtxt ; get a whole line of asciiz text
mov bx,offset line ; where to store in
mov word ptr [bx],0 ; clear line
; mov dx,offset echhlp ; help
mcmsg echhlp,cechhlp
call comnd
jmp rskp ; ignore parse error if no text
nop
mov si,offset line ; start of line
mov di,si ; convert to the same place
mov ah,script.incasv ; save current case state
push ax
mov script.incasv,0ffh ; say no case conversion
call cnvlin ; convert \numbers to binary
pop ax
mov script.incasv,ah ; recover case state
jc echo3 ; carry set means error
mov al,lf ; start with a linefeed
call scdisp ; show it
jcxz echo2 ; z = nothing to show
echo1: push cx ; save loop counter
cld
lodsb ; get a source char into al
push si
call scdisp ; display the char
pop si
pop cx
loop echo1 ; get another
echo2: jmp rskp ; return success
echo3: ret ; error
SCECHO ENDP
; Extract label from command line. Store in LINE, length in slablen.
; Jump to line in Take or Macro following that label.
GOTO PROC NEAR
mov kstatus,0 ; global status
mov ah,cmfile ; get a word
mov dx,offset line ; buffer to hold label
mov bx,0 ; no help (non-interactive command)
mov slablen,bx ; clear label holding buffer
mov comand.cmkeep,1 ; keep Take/macro open after EOF
call comnd
jmp r
nop
mov al,ah ; byte count
mov ah,0
mov slablen,ax ; save count here
mov comand.cmkeep,1
mov ah,cmcfm
call comnd
jmp r
nop
cmp taklev,0 ; in a Take file or Macro?
jne GETTO ; ne = yes, find the label
jmp rskp ; ignore interactive command
; Find line starting just after ":label". Label is in variable LINE
; (length in slablen). Readjust Take read pointer to start of that line.
; Performs file search from beginning of file.
; Exit carry clear if success, carry set otherwise. Local worker routine.
getto proc near
push bx ; global save of bx
mov bx,takadr
cmp [bx].taktyp,0ffh ; get type of take (a Macro?)
je gett2 ; e = yes, a macro
; scan from start of Take file
mov eolchr,LF ; file lines end on LF
mov bx,[bx].takhnd ; rewind the file
mov cx,0
mov dx,0
mov al,0 ; zero displacement from start of file
mov ah,lseek
int dos
jnc gett1
jmp gett20 ; c = failure
gett1: call takrd ; get a buffer of data
mov bx,takadr ; restore bx to working value
jmp short gett4
; Take a Macro
gett2: mov eolchr,CR ; Macro lines end on CR
mov ax,[bx].takptr ; offset of next char to be read
sub ax,[bx].takbuf ; offset of start of buffer
dec ax ; omit count byte at start of buffer
add [bx].takcnt,ax ; original length of text in buffer
mov ax,[bx].takbuf
inc ax ; omit count byte at start of buffer
mov [bx].takptr,ax ; set read pointer to beginning
gett4: call getch ; get a character
jc gett14 ; c = end of file, no char
cmp al,':' ; start of label?
je gett8 ; e = yes
gett6: cmp al,eolchr ; end of line?
je gett4 ; e = yes, seek colon for label
call getch ; get a character
jc gett14 ; c = end of file, no char
jmp short gett6 ; read until end of line
gett8: mov si,offset line ; label to search for
mov cx,slablen ; its length
jcxz gett12 ; no chars to match
cmp byte ptr[si],':' ; user label starts with colon
jne gett10 ; ne = no
inc si ; skip user's colon
dec cx
jcxz gett12 ; no chars to match
gett10: call getch ; read file char into al
jc gett14 ; c = end of file
mov ah,al
cld
lodsb
call tolowr ; convert al and ah to lower case
cmp al,ah ; match?
jne gett6 ; ne = no, goto end of line
loop gett10 ; continue matching
; match obtained
call getch ; read next file character
jc gett13 ; c = end of file, no char
cmp al,' ' ; separator?
je gett12 ; e = yes, unique label found
cmp al,eolchr ; or end of line?
je gett13 ; e = yes
cmp al,CR ; macro eol, also file start eol pair
je gett12 ; e = found match
jmp gett6 ; longer label than target
gett12: call getch ; read past end of line
jc gett13 ; c = end of file, no char
cmp al,eolchr ; end of line character?
jne gett12 ; ne = no, keep reading
gett13: pop bx
clc ; return carry clear
jmp rskp ; Take pointers are ready to read line
gett14: mov ah,prstr ; say label not found
; mov dx,offset laberr ; first part of error message
mcmsg laberr,claberr
int dos
mov dx,offset line
cmp line,':' ; label starts with ":"?
jne gett15 ; ne = no
inc dx ; yes, skip it
gett15: call prtasz ; print asciiz string
mov ah,prstr
; mov dx,offset laberr2 ; trailer of error message
mcmsg laberr2,claberr2
int dos
gett20: pop bx
mov kstatus,1 ; command status, failure
stc ; set carry for failure
ret
getto endp
GOTO ENDP
; Read char from Take buffer. Returns carry clear and char in al, or if end
; of file returns carry set. Enter with bx holding takadr. Local worker.
getch proc near
cmp [bx].takcnt,0 ; buffer empty?
jg getch2 ; g = no
cmp [bx].taktyp,0ffh ; macro?
je getch1 ; e = yes, that's the end
call takrd ; read another buffer
cmp [bx].takcnt,0 ; end of file?
jne getch2 ; ne = no
getch1: stc ; e = yes, exit error
ret
getch2: push si
mov si,[bx].takptr ; read a char from Take buffer
cld
lodsb
mov [bx].takptr,si ; move buffer pointer
pop si
dec [bx].takcnt ; decrease number of bytes remaining
clc ; return carry clear
ret
getch endp
; IF [NOT] {ALARM | COUNT | FAILURE | SUCCESS | ERRORLEVEL \number
; | EQUAL string string | EXIST filespec} command
IFCMD PROC NEAR
mov notflag,0 ; assume NOT keyword is absent
ifcmd1: mov ah,cmkey ; parse keyword
mov dx,offset iftable ; table of keywords
mov bx,0 ; help is the table
call comnd
jmp r
nop
cmp bx,ifnot ; NOT keyword?
jne ifcmd2 ; ne = no
xor notflag,1 ; toggle not flag
jmp short ifcmd1 ; and get next keyword
ifcmd2: cmp bx,ifsuc ; IF SUCCESS?
jne ifcmd4 ; ne = no
cmp kstatus,0 ; do we have success?
jne ifcmdf ; ne = no, no jump
jmp ifcmdp ; yes
ifcmd4: cmp bx,iferr ; IF ERRORLEVEL?
jne ifcmd5 ; ne = no
jmp ifnum ; parse number to binary in line
ifcmd5: cmp bx,ifext ; IF EXIST filespec?
jne ifcmd6 ; ne = no
mov ah,cmfile ; read a filespec
mov dx,offset line ; buffer for filespec
mov bx,0
call comnd
jmp r
nop
mov ax,offset line ; isfile wants pointer in ds:ax
call isfile ; see if file exists
jc ifcmdf ; c = no
jmp short ifcmdp ; yes, do following command
ifcmd6: cmp bx,iffail ; IF FAIL?
jne ifcmd7
test kstatus,not (0) ; check all bits
jz ifcmdf ; z = not that condition, no jump
jmp short ifcmdp
ifcmd7: cmp bx,ifctr ; IF COUNT?
jne ifcmd8 ; ne = no
cmp taklev,0 ; in a Take file?
je ifcmdf ; e = no, fail
push bx
mov bx,takadr ; current Take structure
cmp [bx].takctr,0 ; exhausted count?
je ifcmd7a ; e = yes, dec no more ye counter
dec [bx].takctr ; dec COUNT if non-zero
cmp [bx].takctr,0 ; exhausted now?
je ifcmd7a ; e = yes
pop bx
jmp short ifcmdp ; COUNT > 0 at entry, execute command
ifcmd7a:pop bx
jmp short ifcmdf ; do not execute command
ifcmd8: cmp bx,ifmdf ; IF DEF?
jne ifcmd9 ; ne = no
jmp ifmdef ; do further parsing below
ifcmd9: cmp bx,ifalarm ; IF ALARM?
jne ifcmd10 ; ne = no
jmp ifalrm ; do further parsing below
ifcmd10:cmp bx,ifequal ; IF EQUAL?
jne ifcmdf ; ne = no
jmp ifequ ; do further parsing below
; Jump points for worker routines
; failure
ifcmdf: cmp notflag,0 ; need to apply not condition?
jne ifcmdp2 ; ne = yes, take other exit
ifcmdf2:mov ah,cmtxt ; fail, read and discard rest of line
mov bx,offset line
; mov dx,offset discard ; say not doing anything
mcmsg discard,cdiscard
call comnd
nop
nop
nop
jmp rskp
; success (pass)
ifcmdp: cmp notflag,0 ; need to apply not condition?
jne ifcmdf2 ; ne = yes, take other exit
ifcmdp2:jmp rskp ; do command
IFCMD ENDP
; Compare errlev against user number. Jump successfully if errlev >= number.
; Worker for IF [NOT] ERRORLEVEL number <command>
ifnum proc near
mov ah,cmfile ; get following number
mov dx,offset line+1
mov line,'\' ; in case user forgets backslash
mov word ptr line+1,0 ; clear buffer
; mov bx,offset ifnhlp ; help
mcmsgb ifnhlp,cifnhlp
call comnd
jmp r
nop
mov si,offset line ; put text in compare buffer
cmp line+1,'\' ; did user include backslash?
jne ifnum2 ; ne = no
inc si ; yes, skip our helpful backslash
ifnum2: call katoi ; convert number to binary in ax
jc ifnum4 ; c = failed to convert a number
cmp errlev,al ; at or above this level?
jae ifnum3 ; ae = yes, succeed
jmp ifcmdf ; else fail
ifnum3: jmp ifcmdp ; jump to main command Success exit
ifnum4: mov dx,offset line+1 ; pointer to bad word
mov tempd,dx ; remember starting place for text
call strlen ; get its length
add dx,cx ; skip over current word
mov bx,dx
mov byte ptr [bx],' ' ; space, chopped by parser
inc bx ; new text goes here
mov dx,0 ; help
mov ah,cmtxt ; read rest of line
call comnd
jmp r
nop
cmp ah,0 ; returned byte count
ja ifnum5 ; a = got some
mov byte ptr[bx-1],0 ; remove space separator from above
ifnum5: mov ah,prstr
; mov dx,offset ifnmsg ; error message header
mcmsg ifnmsg,cifnmsg
int dos
mov dx,offset line+1 ; start of user text
call prtasz ; display asciiz string
mov ah,prstr
mov dx,offset ifnmsg2 ; trailer of message
int dos
jmp ifcmdf ; jump to main command Failure exit
ifnum endp
; Process IF [NOT] DEF <macro name> <command>
ifmdef proc near
mov dx,offset line+1 ; point to work buffer
; mov bx,offset ifdfhlp ; help
mcmsgb ifdfhlp,cifdfhlp
mov ah,cmfile ; get macro name
mov comand.cmper,1 ; do not react to \%x
call comnd
jmp r
nop
mov line,ah ; store length in buffer
ifmde2: mov bx,offset mcctab+1 ; table of macro keywords
mov tempd,0 ; tempd = current keyword
cmp byte ptr [bx-1],0 ; any macros defined?
je ifmde9 ; e = no, failure, exit now
; match table keyword and user word
ifmde3: mov si,offset line ; pointer to user's cnt+name
mov cl,[si] ; length of user's macro name
xor ch,ch
inc si ; point to macro name
cmp cl,[bx] ; compare length vs table keyword
jne ifmde7 ; ne = not equal lengths, try another
push si ; lengths match, how about spelling?
push bx
inc bx ; point at start of keyword
ifmde4: mov ah,[bx] ; keyword char
mov al,[si] ; new text char
cmp al,'a' ; map lower case to upper
jb ifmde5
cmp al,'z'
ja ifmde5
sub al,'a'-'A'
ifmde5: cmp al,ah ; test characters
jne ifmde6 ; ne = no match
inc si ; move to next char
inc bx
loop ifmde4 ; loop through entire length
ifmde6: pop bx
pop si
jcxz ifmde10 ; z: cx = 0, found the name
; select next keyword
ifmde7: inc tempd ; number of keyword to test next
mov cx,tempd
cmp cl,mcctab ; all done? Recall, tempd starts at 0
jae ifmde9 ; ae = yes, no match
ifmde8: mov al,[bx] ; cnt (keyword length from macro)
xor ah,ah
add ax,4 ; skip over '$' and two byte value
add bx,ax ; bx = start of next keyword slot
jmp short ifmde3 ; do another comparison
ifmde9: jmp ifcmdf ; jump to main command Failure exit
ifmde10:jmp ifcmdp ; jump to main command Success exit
ifmdef endp
; IF [not] ALARM hh:mm:ss command
ifalrm proc near
call chkkbd ; check keyboard for override
test status,stat_cc ; Control-C?
jz ifalr1 ; z = no
ret ; yes, return failure now
ifalr1: push word ptr timhms
push word ptr timhms+2 ; save working timeouts
mov ax,word ptr alrhms
mov word ptr timhms,ax
mov ax,word ptr alrhms+2
mov word ptr timhms+2,ax ; set alarm value
call chktmo ; check for timeout
pop word ptr timhms+2 ; restore working timeouts
pop word ptr timhms
test status,stat_tmo ; tod past user time (alarm sounded)?
jnz ifalr4 ; nz = yes, succeed
; failure (not at alarm time yet)
ifalr2: cmp notflag,0 ; need to apply not condition?
jne ifalr5 ; ne = yes, take other exit
ifalr3: mov ah,cmtxt ; fail, read and discard rest of line
mov bx,offset line
mov dx,0
call comnd
jmp r
nop
jmp rskp
; success (at or past alarm time)
ifalr4: cmp notflag,0 ; need to apply not condition?
jne ifalr3 ; ne = yes, take other exit
ifalr5: jmp rskp ; pass, do command
ifalrm endp
; IF [NOT] EQUAL word word command
; Permits use of \number, {string}, @filespec
ifequ proc near
mov ah,cmfile ; get a word
mov dx,offset line ; where to store
mov line,0 ; clear first entry
; mov bx,offset ifehlp1 ; help
mcmsgb ifehlp1,cifehlp1
call comnd
jmp rskp ; ignore parse error if no text
nop
mov si,offset line ; start of line
mov di,si ; convert to the same place
call cnvlin ; convert \numbers to binary
jc ifequ9 ; carry set means error
jcxz ifequ9 ; z = empty word
mov tempa,0 ; line length, so far
cld
ifequ1: lodsb
cmp al,' ' ; space or control code?
jbe ifequ2 ; be = yes, end of word
inc tempa ; count char in word
loop ifequ1 ; continue
ifequ2: mov byte ptr[si],0 ; plant terminator
inc si ; skip null terminator
mov temptr,si ; place to start second part
mov dx,si
mov word ptr[si],0 ; clear second part
mov ah,cmfile ; get a word of text
; mov bx,offset ifehlp2 ; help
mcmsgb ifehlp2,cifehlp2
call comnd
jmp rskp ; ignore parse error if no text
nop
mov si,temptr ; start of second line
mov di,si ; convert to the same place
call cnvlin ; convert \numbers to binary
jc ifequ9 ; carry set means error
jcxz ifequ9 ; z = empty word
mov si,temptr ; point at second word
mov dx,0 ; word length so far
cld
ifequ3: lodsb
cmp al,' ' ; space or control code?
jbe ifequ4 ; be = yes, end of word
inc dx ; count char in word
loop ifequ3 ; continue
ifequ4: mov byte ptr[si],0 ; plant terminator
mov cx,dx ; length of second word
cmp tempa,dl ; same lengths?
jne ifequ9 ; ne = no
jcxz ifequ9 ; both are null
push es
push ds
pop es
mov si,offset line ; first word
mov di,temptr ; second word
cld
repe cmpsb ; see if they are the same
pop es
jne ifequ9 ; ne = not the same, fail
jmp ifcmdp ; do IF cmd success
ifequ9: jmp ifcmdf ; do IF cmd failure
ifequ endp
; SET ALARM <time, sec from now or HH:MM:SS>
SETALRM PROC NEAR
mov dx,offset line ; point to work buffer
mov word ptr line,0
mov word ptr line+2,0
; mov bx,offset alrmhlp ; help
mcmsgb alrmhlp,calrmhlp
mov ah,cmfile ; get macro name
call comnd
jmp r
nop
mov ah,cmcfm ; get a confirm
call comnd
jmp r
nop
push word ptr timhms
push word ptr timhms+2 ; save working timeouts
mov si,offset line ; source pointer
call inptim ; get the timeout time, sets si
mov ax,word ptr timhms ; save time in alarm area
mov word ptr alrhms,ax
mov ax,word ptr timhms+2
mov word ptr alrhms+2,ax
pop word ptr timhms+2 ; restore working timeouts
pop word ptr timhms
jmp rskp
SETALRM ENDP
; REINPUT <timeout> <match text>
; Reread material in serial port buffer, seeking a match with user's text
; pattern. If user's pattern is longer than material in buffer then read
; additional characters from the serial port. Use SCINP to do the main work.
SCREINP PROC NEAR
mov reinflg,1 ; say doing REINPUT, not INPUT
jmp short input10
SCREINP ENDP
; Input from port command, match input with text pattern
; Input [timeout] text
;
SCINP PROC NEAR
mov reinflg,0 ; say doing INPUT, not REINPUT
jmp short input10
input10:mov kstatus,0
mov ah,cmtxt ; get a whole line of asciiz text
mov bx,offset line ; place to put text
; mov dx,offset inphlp ; help message
mcmsg inphlp,cinphlp
call comnd ; get the pattern text
jmp r ; nothing, complain
nop
cmp reinflg,0 ; Input command?
jne input1 ; ne = no, Reinput
cmp taklev,0 ; are we in a Take file?
je input0 ; e = no, display linefeed
cmp flags.takflg,0 ; are Take commands being echoed?
je input1 ; e = no, skip display
input0: cmp script.inecho,0 ; Input echo off?
je input1 ; e = yes
mov al,lf ; next line
call scdisp ; display the char
input1: call serini ; initialize the system's serial port
jc input1a ; c = failure
mov status,stat_unk ; clear status flag
mov si,offset line ; source pointer
call inptim ; get the timeout time, sets si
jnc input1b ; nc = legal time value or none
input1a:jmp input5 ; else fail on error
input1b:mov di,offset line ; put text in compare buffer
call cnvlin ; convert \numbers in buf line
mov inplen,cx ; cx = number of bytes in final string
mov parmsk,0ffh ; parity mask, assume 8 bit data
mov di,portval
cmp [di].parflg,parnon ; parity is none?
je input1c ; e = none
mov parmsk,07fh ; else strip parity (8th) bit
input1c:mov di,offset line
mov temptr,di ; pointer to pattern char
mov temptr2,di ; and we need pointer to end of string
add temptr2,cx ; offset of end of string
; setup reinput read pointer & count
mov ax,bufwtptr ; where next new char goes
mov bufpkptr,ax ; set peek-read pointer at oldest char
mov bufpkcnt,prtbuflen ; always look back one full buffer
; see if a pattern needs matching
cmp inplen,0 ; empty pattern? (cnvlin sets cx=cnt)
jne input4 ; ne = not empty
cmp reinflg,0 ; Input command?
je input3 ; e = yes, read and discard chars
jmp input5 ; reinput, just exit timeout
; empty. read, display, and discard
input3: call chkkbd ; check keyboard
test status,stat_cc ; did user type control-c?
jnz input5 ; nz = yes, quit
test status,stat_cr ; did user type cr? [js]
jz input3a ; z = no
jmp inputx ; nz = yes, return success [js]
input3a:call chktmo ; check timeout
test status,stat_tmo
jnz input5 ; nz = timed out, quit
call bufread ; read from serial port buffer into al
jmp input3 ; loop until timeout, exit timeout
; start main read and compare loop
input4: mov di,temptr ; pointer to current pattern char
cmp di,temptr2 ; at end of pattern?
jae inputx ; ae = yes, return success
call chkkbd ; check keyboard
test status,stat_cc ; did user type control-c?
jnz input5 ; nz = yes, quit
test status,stat_cr ; did user type cr? [js]
jz input4a ; z = no
jmp inputx ; nz = yes, return success [js]
input4a:call chktmo ; check timeout
test status,stat_tmo+stat_ok ; timeout or user override
jnz input5 ; nz = timed out, quit
cmp reinflg,0 ; Input command?
jne input4b ; ne = no, a reinput cmd
call bufread ; read from serial port buffer into al
jc input4 ; c = nothing there, keep looking
jmp short input4c ; analyze character
input4b:call peekbuf ; reinput: peek-read from buffer
jc input4 ; c = failed to get a character
; got a char from buffer/port
input4c:cmp al,'a' ; candidate for case conversion? [js]
jb input4d ; b = no [js]
cmp al,'z' ; in lower case set? [js]
ja input4d ; a = no [js]
and al,script.incasv ; apply case conversion mask
input4d:mov di,temptr
mov ah,byte ptr [di] ; get current pattern char again
call matchr ; al=rcvd, ah=pattern, do they match?
jc inpm ; c = no match, try substring
inc temptr ; matched, point to next pattern char
jmp input4
input5: or errlev,2 ; set RECEIVE failure condition
or fsta.xstatus,2 ; set status
cmp reinflg,0 ; Input command?
jne input6 ; ne = no
jmp squit ; exit failure: timeout or control-c
input6: mov kstatus,2 ; failure
jmp squit1 ; skip timeout message, if any
inputx: jmp rskp ; return success
; See if a trailing-subset of the matched chars + new port char can match
; the beginning part of the pattern. That is, if we were to simply "forget"
; the oldest of the matched chars and slide left the apparent port string
; then could we eventually find a match? Example: "Input 10 memema"
; gives the pattern of "memema"; suppose the received chars were "mememema".
; Forgetting one left-most rcv'd char at a time (two in this case) finally
; yields a match, from which we should continue to compare fresh port chars
; with successive pattern chars until either they match through all pattern
; chars or we encounter another break. If there is a later break, repeat this
; algorithm.
; Since we really have only the latest char from the port then pointers to
; the matched pattern chars are used to mimic the earlier received chars:
; they must have been identical to produce a match to date. The quick way
; to "forget" oldest received chars is to scan backward through the matched
; pattern chars looking for the current port char; if the first such find does
; not yield a matching substring then look back further.
; no or partial match then break
; di = temptr = pattern break char
; al = port char causing break
; di - offset line = # chars matched thus far
; avoid cpu-brand side effects with "repne scasb"
inpm: mov tempa,al ; save port char here
inpm1: mov tempd,di ; pattern break loc, where matching failed
mov cx,di ; char at di does not match current port char
sub cx,offset line ; compute count of matched bytes
jcxz inpm4 ; z = 0 = mismatch on the initial pattern char
mov al,tempa ; port char to find (in case we looped here)
inpm2: dec di ; back up one pattern char
mov ah,byte ptr [di]; current pattern character to consider
call matchr ; is port char = earlier pattern char? [js]
jnc inpm3 ; nc = equal values, go construct substring
loop inpm2 ; do cx times, max. (length of match to date)
jmp inpm4 ; get here when there are no matches [js]
inpm3: mov bx,tempd ; get last break location
sub bx,di ; displacement = break - new find of port char
mov tempd,di ; remember new location of a port-like char
; cx has number of chars in test substring
dec cx ; matched one char already [jrs]
jcxz inpm3a ; is there anything left? [jrs]
call matstr ; does this substring match the pattern?
jc inpm1 ; c = no match, try making substring smaller
inpm3a: mov di,tempd ; sub-string matched. Use this shorter match
mov temptr,di ; set di for exit (matstr messes up di)
inc temptr ; matched, point to next pattern char
jmp input4 ; continue with fresh port info
inpm4: mov temptr,offset line; complete failure, restart scanning
jmp input4 ; get something from the port
; worker for SCINP
; compare strings. One starts at offset line, the other starts bx bytes later.
; cx = # chars to compare. Return carry clear if match, else carry set.
matstr: mov si,offset line ; start of pattern string
matstr1:mov ah,byte ptr [si] ; pattern char
mov al,byte ptr [si+bx] ; "old port char" (same as pattern char)
call matchr ; check match of these two characters
jc matstr2 ; c = no match (exit with carry flag set)
inc si ; match, consider next pair
loop matstr1 ; consider rest of substring (cx is counter)
clc ; clear c bit (substrings do match)
matstr2:ret ; preserves flags (c set = no match)
; worker for SCINP
; compare single characters, one in ah and the other in al. Allow the 0ffh
; wild card to match CR and LF individually. Return carry clear if match,
; or carry set if they do not match. Registers preserved.
matchr: cmp ah,al ; do these match?
je matchr6 ; e = yes
cmp ah,0ffh ; the match cr/lf indicator?
je matchr2 ; e = yes
cmp al,0ffh ; the match cr/lf indicator?
jne matchr5 ; ne = no match at all.
matchr2:push ax ; save both chars again
and ah,al ; make a common byte for testing
cmp ah,cr
je matchr4 ; e = cr matches 0ffh
cmp ah,lf
je matchr4 ; e = lf matches 0ffh
pop ax ; recover chars
matchr5:stc ; set carry (no match)
ret
matchr4:pop ax ; recover chars
matchr6:clc ; clear carry (match)
ret
SCINP ENDP
;
; Pause for the specified number of seconds or until a time of day
; Pause [seconds or hh:mm:ss]
;
SCPAU PROC NEAR
mov kstatus,0
mov ah,cmfile ; get a word (number)
mov dx,offset line ; where to store it
mov byte ptr line,0 ; terminate line incase no text
; mov bx,offset ptshlp ; help msg
mcmsgb ptshlp,cptshlp
call comnd
jmp r
nop ; must be at least 3 bytes
mov ah,cmcfm ; get a confirm
call comnd
jmp r
nop
mov si,offset line ; source pointer
call inptim ; parse pause time (or force default)
jc scpau1 ; c = bad time value
mov tempa,0 ; no modem status to detect
jmp swait4 ; finish in common code
scpau1: ret
SCPAU ENDP
;
; Wait for the indicated signal for the specified number of seconds or tod
; WAIT [seconds] \signal where \signal is \cd, \dsr modem status lines.
; Use INPUT-TIMEOUT ACTION for failures.
;
SCWAIT PROC NEAR
mov kstatus,0
mov ah,cmtxt ; get a word (number)
mov bx,offset line ; where to store it
mov byte ptr line,0 ; terminate line incase no text
; mov dx,offset wthlp ; help msg
mcmsg wthlp,cwthlp
call comnd
jmp r
nop ; must be at least 3 bytes
mov tempa,0 ; clear modem status test byte
mov si,offset line ; source pointer
call inptim ; parse pause time (or force default)
jc swait1a ; c = bad time value
mov di,offset line ; put text in compare buffer
call cnvlin ; convert \numbers in buf line
mov si,di ; code below uses si
jnc swait1 ; nc = no error
swait1a:ret ; else return on error
swait1: cmp cx,0 ; number of chars to examine
jle swait4 ; le = none
cld
lodsb ; get a character
dec cx ; reduce count remaining
cmp al,' ' ; white space?
jbe swait1 ; be = yes, skip over it
cmp al,'\' ; backslash signal introducer?
jne swait1 ; ne = no, keep searching
cmp cx,2 ; at least two chars in signal?
jl swait3 ; l = no
mov ax,[si]
or ax,2020h ; upper case to lower, two chars
cmp ax,'dc' ; carrier detect?
jne swait2 ; ne = no, try next signal
or tempa,modcd ; look for the CD bit
add si,2 ; skip this field
sub cx,2 ; three less chars left in the line
jmp short swait1 ; continue the scan
swait2: cmp ax,'sd' ; data set ready?
jne swait3 ; ne = no
mov al,[si+2] ; third letter
or al,20h ; to lower case
cmp al,'r' ; r for dsr?
jne swait3 ; ne = no
or tempa,moddsr ; look for the DSR bit
add si,3 ; skip this field
sub cx,3 ; four less chars left in the line
swait3: cmp ax,'tc' ; clear to send?
jne swait3a ; ne = no
mov al,[si+2] ; third letter
or al,20h ; to lower case
cmp al,'s' ; r for dsr?
jne swait3a ; ne = no
or tempa,modcts ; look for the CTS bit
add si,3 ; skip this field
sub cx,3 ; four less chars left in the line
swait3a:jmp short swait1 ; continue the scan
; SWAIT4 is used by PAUSE command
SWAIT4: cmp taklev,0 ; are we in a Take file
je swait5 ; e = no, print linefeed
cmp flags.takflg,0 ; are commands being echoed
je swait6 ; e = no, skip this
swait5: cmp script.inecho,0 ; Input echoing off?
je swait6 ; e = yes
mov al,lf ; next line
call scdisp ; display the char
swait6: call serini ; initialize the system's serial port
jc swait9 ; c = failure
mov status,stat_unk ; clear status flag
push si
mov parmsk,0ffh ; parity mask, assume 8 bit data
mov si,portval
cmp [si].parflg,parnon ; parity is none?
pop si
je swait7 ; e = none
mov parmsk,07fh ; else strip parity (8th) bit
swait7: call getmodem ; modem handshake status to AL
and al,tempa ; keep only bits to be tested
cmp tempa,0 ; anything to be tested?
je swait7a ; e = no, just do the wait part
cmp al,tempa ; check selected status bits
jne swait7a ; ne = not all selected bits match
jmp rskp ; all match. take successful exit
swait7a:call chkport ; get and show any new port char
call chkkbd ; check keyboard
test status,stat_cc ; control-c?
jnz swait9 ; nz = yes, quit
call chktmo ; check tod for timeout
test status,stat_tmo+stat_ok ; timeout or user override?
jz swait7 ; z = no, continue to wait
cmp tempa,0 ; were we waiting on anything?
jne swait9 ; ne = yes, timeout = failure
jmp rskp ; else timeout = success
swait9: or errlev,2 ; set RECEIVE error condx
or fsta.xstatus,2 ; set status
jmp squit ; take error exit
SCWAIT ENDP
; Output line of text to port, detect \b and \B as commands to send a Break
; on the serial port line.
; Output text
SCOUT PROC NEAR
mov kstatus,0
mov ah,cmtxt ; get a whole line of asciiz text
mov bx,offset line ; store text here
; mov dx,offset outhlp ; help message
mcmsg outhlp,couthlp
call comnd
jmp r
nop
cmp taklev,0 ; is this being done in a Take file?
je outpu0 ; e = no, display linefeed
cmp flags.takflg,0 ; are commands being echoed?
je outp0a ; e = no, skip the display
outpu0: cmp script.inecho,0 ; Input echoing off?
je outp0a ; e = yes
mov al,lf ; next line
call scdisp ; display the char
outp0a: mov al,spause ; wait three millisec or more
add al,3
xor ah,ah
call pcwait ; breathing space for HDX systems
call serini ; initialize the system's serial port
jnc outp0c ; nc = success
or errlev,1 ; set SEND failure condition
or fsta.xstatus,1 ; set status
jmp squit
outp0c: mov status,stat_unk ; clear status flag
mov parmsk,0ffh ; parity mask, assume 8 bit data
mov si,portval
cmp [si].parflg,parnon ; parity is none?
je outp0b ; e = none
mov parmsk,07fh ; else strip parity (8th) bit
outp0b: mov si,portval ; serial port structure
mov bl,[si].ecoflg ; Get the local echo flag
mov lecho,bl ; our copy
mov si,offset line ; get start of line
mov di,offset line ; put results in the same place
mov ah,script.incasv ; save current case state
push ax
mov script.incasv,0ffh ; say no case conversion
call cnvlin ; convert \numbers to binary
pop ax
mov script.incasv,ah ; recover case state
jnc outpu1 ; nc = no error
ret ; return on error
outpu1: mov temptr,offset line ; save pointer here
mov tempd,cx ; save byte count here
mov ttyact,1 ; say interactive style output
outpu2: cmp tempd,0 ; are we done?
jg outpu2a ; g = not done yet
mov ttyact,0 ; reset interactive output flag
jmp rskp ; return success
outpu2a:mov si,temptr ; recover pointer
cld
lodsb ; get the character
dec tempd ; one less char to send
mov temptr,si ; save position on line
mov tempa,al ; save char here for outchr
mov retry,0 ; number of output retries
cmp al,5ch ; backslash?
jne outpu4d ; ne = no
cmp byte ptr [si],'b' ; "\b" for Break?
je outpu4c ; e = yes
cmp byte ptr [si],'B' ; "\B" ?
jne outpu4d ; ne = no
outpu4c:inc temptr ; move scan ptr beyond "\b"
dec tempd
call sendbr ; call msx send-a-break procedure
jmp outpu5 ; resume beyond echoing
outpu4d:inc retry ; count output attempts
cmp retry,maxtry ; too many retries?
jle outpu4g ; le = no
or errlev,1 ; set SEND failure condition
or fsta.xstatus,1 ; set status
jmp squit ; return failure
outpu4g:mov ah,tempa ; outchr gets fed from ah
call outchr ; send the character to the port
jmp outpu4d ; failure to send char
nop ; ensure 3 bytes for rskp of outchr
cmp lecho,0 ; is Local echo active?
je outpu5 ; e = no
mov al,tempa ;
test flags.capflg,logses ; is capturing active?
jz outp4b ; z = no
push ax ; save char
call cptchr ; give it captured character
pop ax ; restore character and keep going
outp4b: cmp script.inecho,0 ; Input echo off?
je outpu5 ; e = yes
call scdisp ; echo character to the screen
;
outpu5: push cx
outpu5a:mov cx,10 ; reset retry counter
outpu5b:call chkkbd ; check keyboard for interruption
test status,stat_cc ; control c interrupt?
jnz outpu6 ; nz = yes, quit now
cmp script.inecho,0 ; Input echo off?
je outpu5c ; e = yes, skip port reading/display
call chkport ; check for char at serial port
test status,stat_ok ; and put any in buffer
jnz outpu5a ; nz = have a char, look for another
mov ax,1 ; wait 1 millisec between rereads
push cx ; protect counter
call pcwait
pop cx
dec cx ; count down retries
jge outpu5b ; ge = keep trying
outpu5c:pop cx ; no more input, recover register
jmp outpu2 ; resume command
outpu6: pop cx ; recover register
or errlev,1 ; set SEND failure condition
or fsta.xstatus,1 ; set status
mov ttyact,0 ; reset interactive output flag
jmp squit ; quit on control c
SCOUT ENDP
; Raw file transfer to host (strips linefeeds)
; Transmit filespec [prompt]
; Optional prompt is the single char expected from the host to ACK each line.
; Default prompt is a linefeed (or a carriage return from us).
;
SCXMIT PROC NEAR
mov kstatus,0
mov ah,cmfile ; get a filename, asciiz
mov dx,offset line ; where to store it
; mov bx,offset xmthlp ; help message
mcmsgb xmthlp,cxmthlp
call comnd
jmp r ; exit on failure
nop
mov ah,cmtxt ; get a prompt string, asciiz
mov bx,offset line+80 ; where to keep it (end of "line")
mov word ptr [bx],0 ; clear and add terminator
; mov dx,offset pmthlp ; Help in case user types "?".
mcmsg pmthlp,cpmthlp
call comnd
jmp r
nop
cmp line,0 ; filename given?
je xmit0a ; e = no
cmp ah,0 ; prompt given?
je xmit0b ; e = no, use line feed default
mov si,offset line+80 ; convert possible numeric prompt
call katoi ; convert number to binary, if number
jnc xmit0 ; nc = got number
mov al,line+80 ; get ascii char from user's prompt
jmp short xmit0
xmit0b: mov al,lf ; default prompt
xmit0: mov tempa,al ; save the code here
mov dx,offset line ; point to filename
mov ah,open2 ; DOS 2 open file
mov al,0 ; open for reading
int dos
mov fhandle,ax ; store file handle here
jnc xmit1 ; nc = successful opening
xmit0a: mov ah,prstr ; give file not found error message
; mov dx,offset xfrfnf
mcmsg xfrfnf,cxfrfnf
int dos
or errlev,1 ; set SEND failure condition
or fsta.xstatus,1 ; set status
jmp squit ; exit failure
xmitx: mov ah,prstr ; error during transfer
; mov dx,offset xfrrer
mcmsg xfrrer,cxfrrer
int dos
xmitx2: mov bx,fhandle ; file handle
mov ah,close2 ; close file
int dos
;; call serrst ; reset serial port
call bufclear ; clear script buffer
call clrbuf ; clear local serial port buffer
or errlev,1 ; set SEND failure condition
or fsta.xstatus,1 ; set status
jmp squit ; exit failure
;
xmity: mov bx,fhandle ; file handle
mov ah,close2 ; close file
int dos
;; call serrst ; reset serial port
call bufclear ; clear buffers
call clrbuf
jmp rskp ; and return success
xmit1: call serini ; initialize serial port
jnc xmit1b ; nc = success
or errlev,1 ; set SEND failure condition
or fsta.xstatus,1 ; set status
jmp squit
xmit1b: call bufclear ; clear script input buffer
call clrbuf ; clear serial port buffer
mov status,stat_unk ; clear status flag
mov parmsk,0ffh ; parity mask, assume 8 bit data
mov si,portval
cmp [si].parflg,parnon ; parity is none?
je xmit1a ; e = none
mov parmsk,07fh ; else strip parity (8th) bit
xmit1a: mov bl,[si].ecoflg ; Get the local echo flag.
mov lecho,bl ; our copy
mov dx,offset crlf ; display cr/lf
mov ah,prstr
int dos
xmit2: mov dx,offset line ; buffer to read into
mov cx,linelen ; # of bytes to read
mov ah,readf2 ; read bytes from file
mov bx,fhandle ; file handle is stored here
int dos
jnc xmit2a ; nc = success
jmp xmitx ; exit failure
xmit2a: mov cx,ax ; number of bytes read
jcxz xmity ; z = none, end of file
;
mov si,offset line ; buffer for file reads
cld
xmit3: lodsb ; get a byte
cmp al,ctlz ; is this a Control-Z?
jne xmit3a ; ne = no
cmp flags.eofcz,0 ; ignore Control-Z as EOF?
jne xmity ; ne = no, we are at EOF
xmit3a: push si ; save position on line
push cx ; and byte count
push ax ; save char around outchr call
xmit4: mov retry,0 ; clear retry counter
xmit4f: pop ax ; recover saved char
push ax ; and save it again
mov ah,al ; outchr wants char in ah
inc retry ; count number of attempts
cmp retry,maxtry ; too many retries?
jle xmit4g ; le = no
or status,stat_cc ; simulate control-c abort
pop ax ; clean stack
xor al,al ; clear char
jmp xmita ; and abort transfer
xmit4g: cmp al,lf ; line feed?
je xmit4h ; e = yes, don't send it
call outchr ; send the character to the port
jmp xmit4f ; failed, try again
nop
xmit4h: pop ax ; recover saved char
cmp lecho,0 ; is local echoing active?
je xmit5 ; e = no
test flags.capflg,logses ; capturing active?
jz xmit4a ; z = no
push ax ; save char
call cptchr ; give it the character just sent
pop ax ; restore character and keep going
xmit4a: call scdisp ; display char on screen
xmit5: cmp al,cr ; did we send a carriage return?
je xmit8 ; e = yes, time to check keyboard
xmit7: pop cx
pop si
loop xmit3 ; finish this buffer full
jmp xmit2 ; read next buffer
xmit8: test status,stat_cc ; Control-C seen?
jnz xmita ; nz = yes
call chkkbd ; check keyboard (returns char in al)
test status,stat_ok ; have a char?
jnz xmita ; nz = yes
cmp tempa,0 ; is prompt char a null?
jne xmit8b ; ne = no
call bufread ; check for char from serial port buf
jnc xmit8 ; nc = a char, read til none
jmp xmit7 ; continue transfer
xmit8b: call bufread ; check for char from serial port buf
jc xmit8 ; c = none
cmp al,tempa ; is port char the ack?
jne xmit8 ; ne = no, just ignore the char
jmp xmit7 ; yes, continue transfer
xmita: test status,stat_cc ; control-c?
jnz xmitc ; nz = yes
test status,stat_cr ; a local ack?
jz xmit8 ; no, ignore local char
mov dx,offset crlf ; display cr/lf
mov ah,prstr
int dos
jmp xmit7 ; continue transfer
xmitc: pop cx ; Control-C, clear stack
pop si ; ...
; mov dx,offset xfrcan ; say canceling transfer
mcmsg xfrcan,cxfrcan
mov ah,prstr
int dos
mov flags.cxzflg,0 ; clear Control-C flag
jmp xmitx2 ; ctrl-c, quit
SCXMIT ENDP
;;;;;;;;;;;;;;;;;; local support procedures ;;;;;;;;;;
;
;worker: copy line from si to di, converting \nnn strings to single chars
; returns carry set if error, else carry clear. Detects leading at-sign
; as an indicator to read command file for one line of text; command files
; may be nested to a depth of 100.
; Items of the form \chars which are not numbers are copied verbatium
; to the output string (ex: \a is copied as \a). The string is first trimmed
; of trailing spaces, then the possible curly brace delimiter pair is
; removed, and finally \numbers are converted to binary. [jrd]
cnvlin proc near
push si ; source ptr
push di ; destination ptr
push ax
mov ax,ds
mov es,ax ; use data segment for es:di
pop ax
mov tempd,0 ; count indirection depth
cnvln0: cmp tempd,100 ; limit to 100 deep
jbe cnvln0a ; be = not too deep yet
jmp cnvln8 ; too deep, quit
cnvln0a:cld
xor cx,cx ; initialize returned byte count
lodsb ; get the first character
cmp al,40h ; at-sign indirection?
je cnvln5 ; e = yes, open the file
dec si ; no, push back char just read
call cnvstr ; convert string's curly braces
cnvln1: xor ah,ah ; clear high byte of number
call katoi ; get a char into al, convert number
jnc cnvln4 ; nc = binary number converted
cmp al,0ffh ; cr/lf wild card?
je cnvln4 ; e = yes, store it
cmp al,0 ; end of line?
jne cnvln3 ; ne = no
jmp cnvlnx ; yes, exit now
cnvln3: cmp al,'a' ; candidate for conversion? [js]
jb cnvln4 ; b = no
cmp al,'z' ; still in lower case set? [js]
ja cnvln4 ; a = no
and al,script.incasv ; else apply case conversion mask
cnvln4: stosb ; save the char
inc cx ; and count it
cmp ah,0 ; was number larger than one byte?
je cnvln1 ; e = no
xchg ah,al ; put high byte into al
stosb ; store it too
inc cx ; count storage
jmp short cnvln1 ; read more
cnvln5: mov dx,si ; get filename ptr from source line
push si
inc tempd ; count indirection depth
mov cx,64 ; max length of a filename.
cnvln5a:cmp byte ptr [si],' ' ; whitespace or control code?
jbe cnvln5b ; be = yes, found termination
inc si ; else look at next char
loop cnvln5a ; limit search
cnvln5b:mov byte ptr [si],0 ; make asciiz
pop si
mov ah,open2 ; DOS 2 open file
mov al,0 ; open for reading
int dos
mov word ptr fhandle,ax ; store file handle
jnc cnvln7 ; nc = open ok, read from file
mov ah,prstr
; mov dx,offset indmis ; file open error msg
mcmsg indmis,cindmis
int dos
xor cx,cx ; say zero bytes read
pop di ; destination ptr
pop si ; source ptr
stc ; set c bit, failure
ret
cnvln7: mov bx,word ptr fhandle ; file handle
mov cx,linelen ; # of bytes to read
mov ah,ioctl ; ioctl, is this the console device?
mov al,0 ; get device info
int dos
and dl,81h ; ISDEV and ISCIN bits needed together
cmp dl,81h ; Console input device?
jne cnvln7d ; ne = no, use regular file i/o
push ds
pop es ; set es:di to datas segment
push di ; save starting pointer
cnvln7b:mov ah,coninq ; read console, no echo
int dos
stosb
cmp al,cr ; end of the line yet?
loopne cnvln7b ; keep reading
cnvln7c:mov byte ptr [di],0 ; insert terminator
pop di ; recover starting pointer
mov dx,di ; simulate read file read
mov ax,linelen
sub ax,cx ; ax = number of chars read
jmp cnvln7e ; close file, finish processing
cnvln7d:mov dx,di ; destination ptr
mov byte ptr [di],0 ; insert null terminator, clears line
mov ah,readf2 ; DOS 2 read from file
int dos
cnvln7e:pushf ; save flags
push ax ; save byte count read
mov ah,close2 ; close file (wanted just one line)
int dos
pop ax
popf ; recover flags now
jc cnvln8 ; c = error
mov cx,ax ; ax = number of bytes read
jcxz cnvln8a ; cx = z = no bytes read
mov al,cr ; look for cr as terminator
cld
repne scasb ; scan while not a cr and cx not zero
jne cnvln7a ; ne = no cr found
dec di ; point at cr
cnvln7a:mov byte ptr [di],0 ; plant terminator on the cr
; or after last read char, if no cr.
pop di ; get original destination ptr
push di ; and save it again
mov si,dx ; new source = this line
; go convert text, as necessary, and
jmp cnvln0 ; allow nested indirection
cnvln8: mov ah,prstr
; mov dx,offset inderr ; error reading file message
mcmsg inderr,cinderr
int dos
cnvln8a:xor cx,cx ; say zero bytes read
pop di
pop si
stc ; set carry for failure
ret ; and do a real return
cnvlnx: pop di ; destination ptr
pop si ; source ptr
clc ; clear c bit, success
ret
cnvlin endp
;
; worker: read the number of seconds to pause or timeout
; returns time of day for timeout in timhms, and next non-space or
; non-tab source char ptr in si. Time is either elapsed seconds or
; a specific hh:mm:ss, determined from context of colons being present.
; Last form can be abbreviated as hh:[mm[:ss]]. Returns carry set if
; hh:mm:ss form has bad construction (invalid time).
inptim proc near
push ax
push bx
push cx
push dx
push di
cld ; decode pure seconds construction
mov di,si ; remember source pointer
mov cx,10 ; multiplier
mov bx,script.indfto ; no numbers yet, use default-timeout
mov al,byte ptr[si]
cmp al,':' ; stray hh:mm:ss separator?
je inptm8 ; e = yes
cmp al,'9' ; start with numeric input?
ja inptm4 ; a = no, use default time
cmp al,'0' ; ditto
jb inptm4
xor ah,ah ; source char holder
xor bx,bx ; accumulated sum
inptm1: mov al,byte ptr[si] ; get a byte into al
cmp al,':' ; hh:mm:ss construction?
je inptm8 ; e = yes
sub al,'0' ; remove ascii bias
cmp al,9 ; numeric?
ja inptm4 ; a = non-numeric, exit loop, bx = sum
xchg ax,bx ; put sum into ax, char in bl
mul cx ; sum times ten
xchg ax,bx ; put char into al, sum in bx
add bx,ax ; add to sum
inc si ; next char
jmp short inptm1 ; loop thru all chars
inptm4: cmp bx,12*60*60 ; half a day, in seconds
jb inptm5 ; b = less than
jmp inptm13 ; more than, error
inptm5: push si ; save ending scan position for return
mov timout,bx ; # seconds of timeout desired
mov ah,gettim ; read DOS tod clock
int dos
mov timhms[0],ch ; hours
mov timhms[1],cl ; minutes
mov timhms[2],dh ; seconds
mov timhms[3],dl ; hundredths of seconds
mov bx,2 ; start with seconds field
inptm6: mov ax,timout ; our desired timeout interval
add al,timhms[bx] ; add current tod digit to interval
adc ah,0
xor dx,dx ; clear high order part thereof
mov cx,60 ; divide by 60
div cx ; compute number of minutes or hours
mov timout,ax ; quotient
mov timhms[bx],dl ; put remainder in timeout tod digit
dec bx ; look at next higher order time field
cmp bx,0 ; done all time fields?
jge inptm6 ; ge = no
cmp timhms[0],24 ; normalize hours
jl inptm7 ; l = not 24 hours
sub timhms[0],24 ; discard part over 24 hours
inptm7: pop si ; return ptr to next source char
jmp inptm11 ; trim trailing whitespace
inptm8: ; decode hh:[mm[:ss]] to timhms
mov si,di ; recall starting source pointer
mov word ptr timhms[0],0 ; clear time out tod
mov word ptr timhms[2],0
mov bx,0 ; three groups possible
inptm9: mov dl,byte ptr[si] ; get a char
cmp dl,':' ; field separator?
je inptm10 ; e = a separator, step fields
sub dl,'0' ; remove ascii bias
cmp dl,9
ja short inptm11 ; a = failure to get expected digit
mov al,timhms[bx] ; get sum to al
mov ah,10
mul ah ; sum times ten
add al,dl ; sum = 10 * previous + current
mov timhms[bx],al ; current sum
cmp timhms[bx],60 ; more than legal?
jae inptm13 ; ae = illegal
cmp bx,0 ; doing hours?
ja inptm9a ; a = no, min or sec
cmp timhms[bx],24 ; more than legal?
jae inptm13 ; ae = illegal
inptm9a:inc si ; next char
jmp short inptm9 ; continue analysis
inptm10:inc bx ; point to next field
inc si ; next char
cmp bx,2 ; last subscript to use (secs)
jbe inptm9 ; be = get more text
inptm11:cmp byte ptr [si],spc ; examine break char, remove spaces
jne inptm12 ; ne = no, stay at this char
inc si ; look at next char
jmp short inptm11 ; continue scanning off white space
inptm12:clc ; carry clear for success
jnc inptm14
inptm13:stc ; carry set for illegal value
inptm14:pop di ; return with si beyond our text
pop dx
pop cx
pop bx
pop ax
ret
inptim endp
; worker: display the char in al on screen
; use caret-char notation for control codes
scdisp proc near
push dx
push ax
mov ah,conout ; our desired function
test flags.remflg,d8bit ; show all 8 bits?
jnz scdisp0 ; nz = yes
and al,7fh ; apply 7 bit display mask
scdisp0:cmp al,0 ; null?
je scdis2 ; e = yes, ignore
cmp al,del ; delete code?
je scdis2 ; e = yes, ignore
cmp al,spc ; control char?
jae scdis1 ; ae = no, display as-is
cmp al,cr ; carriage return?
je scdis1 ; e = yes, display as-is
cmp al,lf ; line feed?
je scdis1
cmp al,tab ; horizontal tab?
je scdis1
cmp al,bell ; bell?
je scdis1
cmp al,bs ; backspace?
je scdis1
cmp al,escape ; escape?
je scdis1
or al,40h ; control code to printable char
push ax
mov dl,5eh ; display caret first
int dos
pop ax
scdis1: mov dl,al ; the char to be displayed
int dos
scdis2: pop ax
pop dx
ret
scdisp endp
; workers
; Circular buffer for data from serial port. Written by Joe R. Doupnik
; Entry points -
; bufread: read serial port for latest char (invokes bufwrite, sets
; status), get a char into al, return carry set if none.
; bufwrite: put a char from al into buf. If this overwrites an unread
; character then: we lose the old char, the read pointer
; is moved to the next oldest unread char, and the
; number of chars in the buffer is decreased by one.
; bufclear: empties the buffer.
; The buffer is prtbuf, of size prtbuflen bytes. Internally, integer bufcnt
; holds the number of buffer locations occupied, pointer bufrdptr is the
; offset of the char to be read, pointer bufwtptr is the offset of the
; place to store the next incoming char.
;
bufclear proc near
mov bufcnt,0 ; clear count of bytes in buffer
mov bufrdptr,offset prtbuf ; move read pointer to start of buf
mov bufwtptr,offset prtbuf ; move write pointer to start of buf
mov cx,prtbuflen
push es ; physically clear the buffer
push di
mov ax,datas
mov es,ax
mov al,0 ; write prtbuflen nulls
mov di,offset prtbuf
cld
rep stosb
pop di
pop es
ret
bufclear endp
bufread proc near
call chkport ; get any oldest char from port
cmp bufcnt,0 ; empty buffer?
jne bufrd1 ; ne = no
stc ; yes, set carry flag (no char)
ret ; and quit (chkport sets status)
bufrd1: push si
mov si,bufrdptr
mov al,byte ptr [si] ; extract a char into al
pop si
inc bufrdptr ; move pointer to next byte
dec bufcnt ; say have extracted a char
cmp bufrdptr,offset prtbuf+prtbuflen ; beyond end?
jb bufrd2 ; b = not yet, just return
mov bufrdptr,offset prtbuf ; reset to start of buf (wrapping)
bufrd2: clc ; clear carry flag (have read a char)
ret ; chkport sets status
bufread endp
; Non-destructive read of serial port circular buffer. Requires external
; initialization of peek read pointer bufpkptr and count remaining bufpkcnt.
; Returns character in register al.
peekbuf proc near
cmp bufpkcnt,0 ; peek counter, empty buffer?
jne peekbu2 ; ne = no, so look in buffer
cmp bufcnt,prtbuflen ; is real buffer full?
jae peekbu1 ; ae = yes, have examined everything
call chkport ; get a char from port
cmp bufcnt,0 ; still nothing from port?
je peekbu1 ; e = no char, report fact
inc bufpkcnt ; got one, increase peek counter
jmp peekbu2 ; go extract it
peekbu1:stc ; return nothing to see
ret
peekbu2:push si
mov si,bufpkptr ; buffer peek pointer
mov al,byte ptr [si] ; extract a char into al
pop si
inc bufpkptr ; move pointer to next byte
dec bufpkcnt ; say have extracted a char
cmp bufpkptr,offset prtbuf+prtbuflen ; beyond end?
jb peekbu3 ; b = not yet, just return
mov bufpkptr,offset prtbuf ; reset to start of buf (wrapping)
peekbu3:clc ; clear carry flag (have read a char)
ret
peekbuf endp
bufwrite proc near
push si
mov si,bufwtptr
mov byte ptr [si],al ; store char held in al
pop si
inc bufwtptr ; move pointer to next byte
cmp bufwtptr,offset prtbuf+prtbuflen ; beyond end?
jb bufwt1 ; b = not yet
mov bufwtptr,offset prtbuf ; reset to start of buf (wrapping)
bufwt1: inc bufcnt ; say have added a char to the buf
cmp bufcnt,prtbuflen ; more than we can hold?
jbe bufwt3 ; be = not overflowing
push bufwtptr ; read ptr can't alias write ptr
pop bufrdptr ; move up read pointer
mov bufcnt,prtbuflen ; limit count to max buffer length
bufwt3: ret
bufwrite endp
; worker: check for timeout, return status=stat_tmo if timeout, else bit
; stat_tmo is cleared.
chktmo: and status,not stat_tmo
mov ah,gettim ; get the time of day
int dos
sub ch,timhms[0] ; hours difference, ch = (now-timeout)
je chktmo2 ; e = same, check mmss.s
jg chktmo1 ; g = past target hour
add ch,24 ; we are early, see by how much
chktmo1:cmp ch,12 ; hours difference, large or small?
jge chktmox ; ge = not that time yet
jl chktmo3 ; l = beyond that time
chktmo2:cmp cl,timhms[1] ; minutes, hours match
jb chktmox ; b = early
ja chktmo3 ; a = late
cmp dh,timhms[2] ; seconds, hhmm match
jb chktmox ; b = early
ja chktmo3 ; a = late
cmp dl,timhms[3] ; fractions, hhmmss match
jb chktmox ; b = early
chktmo3:or status,stat_tmo ; say timeout
stc
ret
chktmox:clc
ret
;
; worker: check keyboard for char. Return status = stat_cc if control-C typed,
; stat_cr if carriage return, or stat_ok if any other char typed. Else return
; with these status bits cleared.
chkkbd: and status,not (stat_ok+stat_cc+stat_cr) ; clear status bits
cmp flags.cxzflg,'C' ; Control-C interrupt seen?
je chkkbd0 ; e = yes
call isdev ; is stdin a device, not disk file?
jnc chkkbd2 ; nc = not device so do not read here
mov ah,dconio ; keyboard char present?
mov dl,0ffH
int dos
je chkkbd1 ; e = none
or status,stat_ok ; have a char, return it in al
cmp al,3 ; control c?
jne chkkbd1 ; ne = not control c
chkkbd0:or status,stat_cc ; say control c
chkkbd1:cmp al,cr ; carriage return? [js]
jne chkkbd2 ; ne = no
or status,stat_cr ; say carriage return [js]
chkkbd2:ret
;
; worker: check serial port for received char. Return status = stat_ok if
; char received, otherwise stat_ok cleared. Can echo char to screen. Will
; write char to local circular buffer.
chkport:and status,not stat_ok ; clear status bit
call prtchr ; char at port (in al)?
jmp chkpor1 ; yes, analyze it
nop ; ensure 3 bytes for rskp of prtchr
ret ; no, return
chkpor1:and al,parmsk ; strip parity, if any
cmp rxtable+256,0 ; is translation turned off?
je chkpor0 ; e = yes, no translation
push bx ; translate incoming character
mov bx,offset rxtable ; the translation table
xlatb
pop bx
chkpor0:test flags.capflg,logses ; capturing active?
jz chkpor3 ; z = no
test flags.remflg,d8bit ; keep 8 bits for displays?
jnz chkpo0a ; nz = yes, 8 bits if possible
cmp flags.debug,0 ; is debug mode active?
jne chkpo0a ; ne = yes, record 8 bits
and al,7fh ; remove high bit
chkpo0a:push ax ; save char
call cptchr ; give it captured character
pop ax ; restore character and keep going
chkpor3:test flags.remflg,d8bit ; keep 8 bits for displays?
jnz chkpo3a ; nz = yes, 8 bits if possible
and al,7fh ; remove high bit
chkpo3a:cmp script.inecho,0 ; input echoing off?
je chkpor4 ; e = yes
call scdisp ; display the char
chkpor4:call bufwrite ; put char in buffer
or status,stat_ok ; say have a char (still in al)
ret
;
; Squit is the script error exit pathway.
;
squit: mov kstatus,2 ; general command status, failure
test status,stat_tmo ; timeout?
jz squit2 ; z = no, another kind of failure
cmp taklev,0 ; in a Take/macro?
jne squit1 ; ne = yes, skip timeout message
push dx
; mov dx,offset tmomsg ; say timed out
mcmsg tmomsg,ctmomsg
mov ah,prstr
int dos ; display it.
pop dx
squit1: cmp script.inactv,0 ; action to do upon timeout
je squit4 ; 0 = proceed, ne = non-zero = quit
call takclos ; close Take file or macro
squit2: call isdev ; stdin is a device (vs file)?
jc squit3 ; c = device, not a file
mov flags.extflg,1 ; set Kermit exit flag
squit3: ret ; return failure
squit4: jmp rskp ; return success, ignore error
;
; Jumping to this location is like retskp. It assumes the instruction
; after the call is a jmp addr.
RSKP PROC NEAR
pop bp
add bp,3
push bp
ret
RSKP ENDP
; Jumping here is the same as a ret.
R PROC NEAR
ret
R ENDP
code ends
end