home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Phoenix CD 2.0
/
Phoenix_CD.cdr
/
01e
/
msk230s1.zip
/
MSSSCP.ASM
< prev
next >
Wrap
Assembly Source File
|
1988-02-12
|
58KB
|
1,105 lines
name mssscp
; File mssscp.asm
; Edit History
; Last edit: 1 Jan 1988
; 6 Jan 1988 Fix pointer for out @con calls. [jrd]
; 1 Jan 1988 version 2.30
; 26 Dec 1987 Use no-echo reading of console for OUTPUT @CON, speedup
; reading of host response for OUTPUT command. [jrd]
; 4 Dec 1987 Update global byte errlev when a Script command Fails
; (timeout or output failure or manual interruption). [jrd]
; 9 Oct 1987 Allow curly braced strings, trim trailing whitespace too. [jrd]
; 4 Oct 1987 Apply Set Display 7/8 bit mask to bytes rcv'd from serial port
; after Set Translation Input filter. Log 8-bit chars in Debug mode. [jrd]
; 26 Sept 1987 Add check for Control-C interrupt to chkkbd and ECHO,
; make Control-C in TRANSMIT command use squit exit. [jrd]
; 18 Aug 1987 Change ESC to escape for MASM 4.5+ [jrd]
; 11 Aug 1987 Add Set Send Pause plus 3 millisec wait before doing OUTPUT.[jrd]
; 31 July 1987 Open port reading to null chars et al. Correct timeofday
; routine, from Jack Bryans. [jrd]
; 22 July 1987 Rewrite time of day material for no ambiguities. [jrd]
; 15 July 1987 Terminate strings read as @filespec on first carriage return.
; Change number parsing to use decimal as default and \bddd for other bases.
; 24 May 1987 Add error recovery for outchr calls. [jrd]
; 10 May 1987 Add translation of input characters, rxtable. [jrd]
; 4 April 1987 Clear Echo's old text line, from Eberhard Lisse. [jrd]
; 18 March 1987 Add requests for command confirmation. [jrd]
; 2 March 1987 Remove test of Set Input Echo from OUTPUT command. [jrd]
; 27 Oct 1986 preserve data char in al around call to outchr in Output [jrd]
; 19 Oct 1986 Add "\b" and "\B" to Output procedure as send-a-Break command
; to serial port comms line. [jrd]
; 1 Oct 1986 Version 2.29a
; 1 Oct 1986 Add 7/8 bit display mask to displayed text. [jrd]
; 12 Sept 1986 Add changes from Frank da Cruz: one second default timeout,
; echo chars if Local Echo is On, Input command without a pattern should
; behave like a Pause command.
;
; MS Kermit Script routines, DEC-20 style.
; Extensively rewritten for MS Kermit 2.29a by Joe R. Doupnik 5 July 86
;;
; Created June, 1986 a.d. By James Sturdevant
; A. C. Nielsen Co. Mpls.
; 8401 Wayzata Blvd.
; Minneapolis, Mn. 55426
; (612)546-0600
;;;;;;;;
; Kermit command level usages and this file's entry points:
; Clear - clears serial port buffers. Procedure scclr.
; Echo text - displays text on local screen. Proc scecho.
; Pause [time] - waits indicated number of seconds (default is Input
; Default-timeout, 1 second typically). Proc scpau.
; Input [time] text - waits up to time seconds while scanning serial port
; input for a match with text. Default value for time is Input
; Default-timeout, 1 second typically). Spaces or tabs are separators
; between the time and text fields. Proc scinp.
; A carriage return typed by the local user simulates a match.
; Output text - sends the text to the serial output port. Proc scout.
; Transmit text [prompt] - raw file transfer to host. Proceeds from source
; line to source line upon receipt of prompt from host or carriage
; return from us. Default prompt is linefeed. A null prompt (\0)
; causes the file to be sent with no pausing or handshaking. Note
; that linefeeds are stripped from outgoing material. Proc scxmit.
; In the above commands "text" may be replaced by "@filespec" to cause the
; one line of that file to be used instead. @CON obtains one line of
; text from the keyboard. Such "indirect command files" may be nested
; to a depth of 100. Control codes are written as decimal numbers
; in the form "\ddd" where d is a digit between 0 and 9. Carriage
; return is \13, linefeed is \10, bell is \7; the special code \255
; is used to match (Input) either cr or lf or both.
; These commands can be given individually by hand or automatically
; in a Kermit Take file; Take files may be nested.
;;;;;;;;
; These routines expect to be invoked by the Kermit command dispatcher
; and can have their default operations controlled by the Kermit Set Input
; command (implemented in file mssset.asm). They parse their own cmd lines.
; Set Input accepts arguments of
; Case Ignore or Observe (default is ignore case when matching strings)
; Default-timeout seconds (default is 5 seconds)
; Echo On or Off controls echoing of Input cmd text (default is Off)
; Timeout-action Quit or Proceed (default is Proceed)
; These conditions are passed via global variables incasv,indfto,inecho,
; inactv, respectively, stored here.
;;;;;;;;;
include mssdef.h
public scout, scinp, scpau, scecho, scclr, scxmit
linelen equ 134 ; length of working buffer line
prtbuflen equ 128 ; serial port local buffer length
maxtry equ 5 ; maximum number of output retries
stat_unk equ 0 ; status return codes.
stat_ok equ 1 ; have a port character
stat_cc equ 2 ; control-C typed
stat_tmo equ 4 ; timeout
stat_cr equ 8 ; carriage return typed
datas segment public 'datas'
public indfto, inactv, incasv, inecho
extrn taklev:byte, takadr:word, portval:word, flags:byte
extrn rxtable:byte, spause:byte, errlev:byte
; global (public) variables
inactv db 0 ; input action value (default proceed)
incasv db 0dfh ; input case (default ignore)
indfto dw 1 ; input and pause timeout (def 1 sec)
inecho db 1 ; echo Input cmd text (0 = no)
; local variables
line db linelen+1 dup (?) ; line of output or input + terminator
prtbuf db prtbuflen dup (?) ; serial port storage buffer
bufcnt dw 0 ; serial port buf byte cnt, must be 0
bufrdptr dw prtbuf ; serial port buf read ptr
bufwtptr dw prtbuf ; serial port buf write ptr
temptr dw ? ; temporary pointer
temptr2 dw ? ; ditto, points to end of INPUT string
tempd dw ? ; temp
tempa db ? ; another temp
retry db 0 ; number of output retries
status dw ? ; general status word
fhandle dw ? ; file handle storage place
parmsk db 7fh ; 7/8 bit parity mask
lecho db ? ; local echo of output (0 = no)
timout dw ? ; work area (seconds before timeout)
timhms db 4 dup (?) ; hhmmss.s tod buffer
crlf db cr,lf,'$'
xfrfnf db cr,lf,'?Transmit file not found$'
xfrrer db cr,lf,'?error reading Transmit file$'
xfrcan db cr,lf,'?transmission canceled$'
indmis db '?Indirect file not found',cr,lf,'$'
inderr db '?error reading indirect file',cr,lf,'$'
tmomsg db cr,lf,'?Timeout$'
outhlp db 'line of text to be sent to remote host$'
inphlp db 'time limit and line of text expected from remote host$'
echhlp db 'line of text to echo to screen$'
ptshlp db 'number of seconds to pause$'
xmthlp db 'File specification with optional path name$'
pmthlp db 'Prompt character expected as an ACK from host (\0 for none)$'
datas ends
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
assume cs:code, ds:datas
; Clear input buffer(s) of serial port
; Clear command
;
SCCLR PROC NEAR
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
call comnd
jmp rskp ; ignore parse error if no text
mov si,offset line ; start of line
mov di,si ; convert to the same place
mov ah,incasv ; save current case state
push ax
mov incasv,0ffh ; say no case conversion
call cnvlin ; convert \numbers to binary
pop ax
mov 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
; Input from port command, match input with text pattern
; Input [timeout] text
;
SCINP PROC NEAR
mov ah,cmtxt ; get a whole line of asciiz text
mov bx,offset line ; place to put text
mov dx,offset inphlp ; help message
call comnd ; get the pattern text
jmp r ; nothing, complain
mov ah,cmcfm ; get a confirm
call comnd
jmp r ; no confirm
nop
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 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
mov status,stat_unk ; clear status flag
call inptim ; get the timeout time, sets si
mov di,offset line ; put text in compare buffer
call cnvlin ; convert \numbers in buf line
jnc input2 ; nc = no error
ret ; else return on error
input2: mov parmsk,0ffh ; parity mask, assume 8 bit data
mov di,portval
cmp [di].parflg,parnon ; parity is none?
je input2a ; e = none
mov parmsk,07fh ; else strip parity (8th) bit
input2a: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
cmp cx,0 ; empty pattern? (cnvlin sets cx=cnt)
jne input4 ; ne = not empty
; 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]
jnz inputx ; nz = yes, return success [js]
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
; 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]
jnz inputx ; nz = yes, return success [js]
call chktmo ; check timeout
test status,stat_tmo
jnz input5 ; nz = timed out, quit
call bufread ; read from serial port buffer into al
jc input4 ; c = nothing there, keep looking
cmp al,'a' ; candidate for case conversion? [js]
jb inpu4a ; b = no [js]
cmp al,'z' ; in lower case set? [js]
ja inpu4a ; a = no [js]
and al,incasv ; apply case conversion mask
inpu4a: 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
jmp squit ; exit failure: timeout or control-c
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
; Pause [seconds]
;
SCPAU PROC NEAR
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
call comnd
nop ; ignore parse errors (no text)
nop ; must be at least 3 bytes
nop
mov ah,cmcfm ; get a confirm
call comnd
jmp r ; no confirm
nop
;
call inptim ; parse pause time (or force default)
cmp taklev,0 ; are we in a Take file
je paus0c ; e = no, print linefeed
cmp flags.takflg,0 ; are commands being echoed
je paus0d ; e = no, skip this
paus0c: cmp inecho,0 ; Input echoing off?
je paus0d ; e = yes
mov al,lf ; next line
call scdisp ; display the char
paus0d: call serini ; initialize the system's serial port
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 pause1 ; e = none
mov parmsk,07fh ; else strip parity (8th) bit
pause1: call chkport ; get and show any new port char
call chkkbd ; check keyboard
test status,stat_cc ; control-c?
jnz pause2 ; nz = yes, quit
call chktmo ; check tod for timeout
test status,stat_tmo ; timeout?
jz pause1 ; z = no, continue to wait
jmp rskp ; timeout, take successful exit
pause2: or errlev,1+2 ; set SEND and RECEIVE error condx.
jmp squit ; take error exit
SCPAU 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 ah,cmtxt ; get a whole line of asciiz text
mov bx,offset line ; store text here
mov dx,offset outhlp ; help message
call comnd
jmp r ; bad parse (no text)
nop
mov ah,cmcfm ; get a confirm
call comnd
jmp r ; no confirm
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 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
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,incasv ; save current case state
push ax
mov incasv,0ffh ; say no case conversion
call cnvlin ; convert \numbers to binary
pop ax
mov 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
jcxz outpu2 ; empty string
outpu2: cmp tempd,0 ; are we done?
jg outpu2a ; g = not done yet
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
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 ;
cmp flags.capflg,0 ; is capturing active?
je outp4b ; e = no
push ax ; save char
call cptchr ; give it captured character
pop ax ; restore character and keep going
outp4b: cmp 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
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
call pcwait
dec cx ; count down retries
jge outpu5b ; ge = keep trying
pop cx ; no more input, recover register
jmp outpu2 ; resume command
outpu6: pop cx ; recover register
or errlev,1 ; set SEND failure condition
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 ah,cmfile ; get a filename, asciiz
mov dx,offset line ; where to store it
mov bx,offset xmthlp ; help message
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 byte ptr line+80,lf ; store default prompt (line feed)
mov byte ptr line+81,0 ; add terminator
mov dx,offset pmthlp ; Help in case user types "?".
call comnd
nop ; ignore parse error if no prompt
nop
nop
mov ah,cmcfm ; get a confirm
call comnd
jmp r ; no confirm
nop
mov si,offset line+80 ; convert possible numeric prompt
cld
call katoi ; convert number to binary, if number
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
mov ah,prstr ; give file not found error message
mov dx,offset xfrfnf
int dos
or errlev,1 ; set SEND failure condition
jmp squit ; exit failure
xmitx: mov ah,prstr ; error during transfer
mov dx,offset xfrrer
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
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
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
jc xmitx ; c = failure
mov cx,ax ; number of bytes read
jcxz xmity ; z = none, end of file
;
mov si,offset line ; buffer for file reads
xmit3: lodsb ; get a byte
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
cmp flags.capflg,0 ; capturing active?
je xmit4a ; e = 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
mov ah,prstr
int dos
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,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
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
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 timeofday for timeout in timhms, and next non-space or
; non-tab source char ptr in si.
;
inptim proc near
push ax
push bx
push cx
push dx
cld
mov si,offset line ; source pointer
mov cx,10 ; multiplier
xor bx,bx ; accumulated sum
xor ax,ax ; source char holder
cmp byte ptr [si],'9' ; start with numeric input?
ja inptm3 ; a = no, use default time
cmp byte ptr [si],'0' ; ditto
jb inptm3
inptm1: lodsb ; get a byte into al
cmp al,'9'
ja inptm4 ; non-numeric, exit loop
cmp al,'0'
jb inptm4 ; b = non=numeric, exit loop
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
sub al,'0' ; convert to binary
add bx,ax ; add to sum
jmp inptm1 ; loop thru all chars
inptm3: mov bx,indfto ; no numbers, use default-timeout
mov si,offset line ; reset pointer to start of line
jmp inptm5
inptm4: dec si ; back up to non-numeric terminator
inptm4a:cmp byte ptr [si],spc ; space?
je inptm4b ; e = yes, skip over it
cmp byte ptr [si],tab ; tab?
je inptm4b ; e = yes, skip over it
jmp inptm5 ; neither
inptm4b:inc si ; look at next char
jmp inptm4a ; continue scanning off white space
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
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 ; convert 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
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
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_unk 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
jl chktmox ; l = we are early
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
chktmox: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
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
;;; mov flags.cxzflg,0 ; clear interrupt flag
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:cmp flags.capflg,0 ; capturing active?
je chkpor3 ; e = 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 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: test status,stat_tmo ; timeout?
jz squit2 ; z = no, another kind of failure
cmp inecho,0 ; Input echo allowed?
je squit1 ; e = no, so skip timeout msg
cmp taklev,0 ; in a Take file?
jne squit1 ; ne = yes, suppress msg
push dx
mov dx,offset tmomsg ; say timed out
mov ah,prstr
int dos ; display it.
pop dx
squit1: cmp inactv,0 ; action to do upon timeout
je squit3 ; 0 = proceed, ne = non-zero = quit
squit2: mov flags.cxzflg,'C' ; simulate Control-C termination
ret ; return failure, pop take level
squit3: 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