knutson@ut-ngp.UUCP (Jim Knutson) (10/05/84)
This and the 6 following messages contain the source code and documentation
for Kermit-MS and code for downloading the program to your micro. The source
will build Kermit for the IBM-PC and any compatibles running DOS 1.x or 2.x,
the NEC APC, DEC Rainbow, HP-150, Zenith Z100, and Wang.
------------------- Cut here -----------------
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting mscmd.asm'
sed 's/^X//' <<'//go.sysin dd *' >mscmd.asm
public comnd, cmcfrm, prserr, repars, cmgtch, drives, comand, fcbcpy
include msdefs.h
datas segment public 'datas'
extrn flags:byte, trans:byte, fcb:byte, buff:byte
extrn taklev:byte, takadr:word, dosnum:byte
comand cmdinfo <>
cmer00 db cr,lf,'?Program error Invalid COMND call$'
cmer01 db cr,lf,'?Ambiguous$'
cmer02 db cr,lf,'?Illegal input file spec$'
cmer03 db cr,lf,'?Invalid command$' ; [19e]
cmer04 db cr,lf,'?Invalid command or operand$' ; [1]
cmer06 db cr,lf,'?Wildcard not allowed$' ; [21a]
cmer07 db cr,lf,'?Invalid drive specificaton$' ; [21a]
cmin00 db ' Confirm with carriage return$'
cmin01 db ' One of the following:',cr,lf,'$'
cmthlp dw 0 ; Text of help message for random input.
drives db 0 ; How many drives we have. [21a]
crlf db cr,lf,'$'
ctcmsg db '^C$'
prsp db ' $' ; Print a space.
hlpmsg dw 0 ; Address of help message.
spchar db 24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH
db 3CH,3EH,7BH,7DH,5FH,5CH,5EH,7EH,7CH,60H
spclen equ $-spchar
spchar2 db 24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH
db 7BH,7DH,5FH,5EH,7EH,60H
spc2len equ $-spchar2
escspc db 10O,' ',10O,'$' ; Clear escape.
clrspc db ' ',10O,'$' ; Clear space.
filbuf db 60H DUP(?) ; Character buffer.
tbuff db 80 DUP(?)
cmdstk dw ?
datas ends
code segment public
extrn dodel:near, ctlu:near, cmblnk:near, locate:near, takrd:near
extrn clearl:near
assume cs:code,ds:datas,es:datas
; This routine parses the specified function in AH. Any additional
; information is in DX and BX.
; Returns +1 on success
; +4 on failure (assumes a JMP follows the call)
CMND PROC NEAR
comnd: mov comand.cmstat,ah ; Save what we are presently parsing.
mov cmdstk,sp ; save stack ptr locally.
call cminbf ; Get chars until an action or a erase char.
mov ah,comand.cmstat ; Restore 'ah' for upcoming checks.
cmp ah,cmcfm ; Parse a confirm?
jz cmcfrm ; Go get one.
cmp ah,cmkey ; Parse a keyword?
jnz cm1
jmp cmkeyw ; Try and get one.
cm1: cmp ah,cmifi ; Parse an input file spec?
jnz cm2
jmp cmifil ; Go get one.
cm2: cmp ah,cmofi ; Output file spec?
jnz cm3
jmp cmofil ; Go get one.
cm3: cmp ah,cmtxt ; Parse arbitrary text. [8]
jnz cm4
jmp cmtext
cm4: mov ah,prstr ; Else give error.
mov dx,offset cmer00 ; "?Unrecognized COMND call"
int dos
ret
; This routine gets a confirm.
cmcfrm: call cmgtch ; Get a char.
cmp ah,0 ; Is it negative (a terminator; a space or
; a tab will not be returned here as they
; will be seen as leading white space.)
js cmcfr0
ret ; If not, return failure.
cmcfr0: and ah,7FH ; Turn off the minus bit.
cmp ah,esc ; Is it an escape?
jne cmcfr2
mov ah,conout
mov dl,bell ; Get a bell.
int dos
mov ah,0
mov comand.cmaflg,ah ; Turn off the action flag.
mov bx,comand.cmcptr ; Move the pointer to before thee scape.
dec bx
mov comand.cmcptr,bx
mov comand.cmdptr,bx
dec comand.cmccnt ; Decremrnt the char count.
jmp cmcfrm ; Try again.
cmcfr2: cmp ah,'?' ; Curious?
jne cmcfr3
mov ah,prstr ; Print something useful.
mov dx,offset cmin00
int dos
mov ah,prstr
mov dx,offset crlf ; Print a crlf.
int dos
mov ah,prstr
mov dx,comand.cmprmp ; Reprint the prompt.
int dos
mov bx,comand.cmdptr ; Get the pointer into the buffer.
mov ah,'$' ; Put a $ there for printing.
mov [bx],ah
mov bx,comand.cmcptr
dec bx ; Decrement & save the buffer pointer.
mov comand.cmcptr,bx
mov ah,prstr
mov dx,offset comand.cmdbuf
int dos
mov ah,0 ; Turn off the action flag.
mov comand.cmaflg,ah
jmp repars ; Reparse everything.
cmcfr3: cmp ah,ff ; Is it a form feed?
jne cmcfr4
call cmblnk ; If so blank the screen.
cmcfr4: jmp rskp
; This routine parses a keyword from the table pointed
; to in DX. The format of the table is as follows:
;
; addr: db n ; Where n is the # of entries in the table.
; db m ; M is the size of the keyword.
; db 'string$' ; Where string is the keyword.
; dw ab ; Where ab is data to be returned.
;
; The keywords must be in alphabetical order.
cmkeyw: mov comand.cmhlp,bx ; Save the help.
mov comand.cmptab,dx ; Save the beginning of keyword table.
mov bx,dx
mov ch,[bx] ; Get number of entries in table.
inc bx
mov dx,comand.cmdptr ; Save command pointer.
mov comand.cmsptr,dx ; Save pointer's here.
cmky1: cmp ch,0 ; Any commands left to check?
jne cmky2
jmp cmky41 ; no, go complain
cmky2: dec ch
mov cl,0 ; Keep track of how many chars read in so far.
call cmgtch ; Get a char.
cmp ah,0 ; Do we have a terminator?
jns cmky2x
jmp cmky4 ; Negative number means we do.
cmky2x: inc bx ; Point to first letter of keyword.
inc cl ; Read in another char.
mov al,[bx]
cmp ah,'a' ; Less than a?
jl cmky21 ; If so, don't capitalize.
cmp ah,'z'+1 ; More than z?
jns cmky21
and ah,137O ; Capitalize the letter.
cmky21: cmp ah,al
je cmky3
jg cmky2y
jmp cmky41 ; Fail if ah preceeds al alphabetically.
cmky2y: jmp cmky6 ; Not this keyword - try the next.
cmky3: inc bx ; We match here, how 'bout next char?
mov al,[bx]
cmp al,'$' ; End of keyword?
jne cmky3x
jmp cmky7 ; Succeed.
cmky3x: mov dl,al ; Save al's char here.
call cmgtch
inc cl ; Read in another char.
mov al,dl
cmp ah,'a'
jl cmky31
cmp ah,'z'+1
jns cmky31
and ah,137O
cmky31: cmp ah,esc+80H ; Escape Recognition (escape w/minus bit on)?
je cmky3y
cmp ah,'?'+80H ; A question mark? [3]
je cmky3y
cmp ah,' '+80H ; A space?
je cmky3y
cmp ah,cr+80H ; Carriage return?
je cmky3y
jmp cmky38
cmky3y: mov comand.cmkptr,bx ; Save bx here.
mov comand.cmsiz,cx ; Save size info.
mov comand.cmchr,ah ; Save char for latter.
call cmambg ; See if input is ambiguous or not.
jmp cmky32 ; Succeeded (not ambiguous).
mov ah,comand.cmchr
cmp ah,esc+80H ; Escape?
je cmky3z
cmp ah,'?'+80H ; maybe question mark?
je cmkyj1 ; yes, go handle
jmp cmky41 ; Else fail.
cmky3z: mov ah,conout ; Ring a bell.
mov dl,bell
int dos
mov bx,comand.cmcptr ; Move pointer to before the escape.
dec bx
mov comand.cmcptr,bx
mov comand.cmdptr,bx
dec comand.cmccnt ; Decrement char count.
mov bx,comand.cmkptr ; Failed - pretend user never typed ....
mov cx,comand.cmsiz ; ... in a char.
dec cl ; Don't count the escape.
dec bx
mov comand.cmaflg,0 ; Reset the action flag.
jmp cmky3 ; Keep checking.
; ambiguous. Print out all the keywords that match
cmkyj1: mov dx,offset cmin01
mov ah,prstr
int dos
mov bx,comand.cmkptr ; this is current keyword
mov cx,comand.cmsiz ; we are cl chars into it
mov ch,0
sub bx,cx ; back up to beginning
inc bx ; not counting ?
mov comand.cmkptr,bx ; save beginning of kw
cmkyj2: mov dl,tab ; put a tab before each keyword
mov ah,conout
int dos
mov dx,comand.cmkptr ; get current keyword
mov ah,prstr
int dos ; print it
mov bx,comand.cmkptr ; get keyword back
dec bx
mov al,[bx] ; get length
mov ah,0
add ax,5 ; skip length, $, value, next length
add bx,ax ; this is next keyword
mov si,bx
mov di,comand.cmkptr ; compare with last keyword
mov comand.cmkptr,bx ; update this
mov cx,comand.cmsiz
dec ch ; are we at end of table?
jl cmkyj3 ; yes, don't go on
mov comand.cmsiz,cx ; else update count
mov ch,0
dec cl ; this includes ?
jcxz cmkyj2 ; empty, just print it
repe cmpsb ; compare to previous string
je cmkyj2 ; same, go print this one
cmkyj3: jmp cmky50 ; else go finish up
cmky32: mov cx,comand.cmsiz ; Restore info.
mov bx,comand.cmkptr ; Our place in the keyword table.
cmp comand.cmchr,0A0H ; Space?
je cmky35
cmp comand.cmchr,0BFH ; Question mark? [3]
je cmky35
cmp comand.cmchr,8DH ; Carriage return?
je cmky35
dec comand.cmcptr ; Pointer into buffer of input.
mov dx,comand.cmcptr
cmky33: mov ah,[bx] ; Get next char in keyword.
cmp ah,'$' ; Are we done yet?
jz cmky34
mov di,dx
mov [di],ah
inc bx
inc dx
inc comand.cmccnt
jmp cmky33
cmky34: mov ah,' '
mov di,dx
mov [di],ah ; Put a blank in the buffer.
inc dx
mov cx,comand.cmcptr ; Remember where we were.
mov comand.cmcptr,dx ; Update our pointers.
mov comand.cmdptr,dx
mov ah,'$'
mov di,dx
mov [di],ah ; Add '$' for printing.
mov ah,prstr
mov dx,cx ; Point to beginning of filled in data.
int dos
inc bx ; Point to address we'll need.
mov bx,[bx]
mov comand.cmaflg,0 ; Turn off action flag.
jmp rskp
cmky35: inc bx
mov ah,[bx] ; Find end of keyword.
cmp ah,'$'
jne cmky35
inc bx
mov bx,[bx] ; Address of next routine to call.
; mov comand.cmaflg,0 ; Zero the action flag.
jmp rskp
cmky38: cmp ah,al
je cmky39
jmp cmky6 ; Go to end of keyword and try next.
cmky39: jmp cmky3 ; Check next letter.
cmky4: and ah,7FH ; Turn off minus bit.
cmp ah,'?' ; Need help?
je cmky5
cmp ah,' ' ; Just a space - no error.
je cmky51
cmp ah,cr
je cmky51
cmp ah,tab
je cmky51
cmp ah,esc ; Ignore escape?
je cmky43
cmky41: mov ah,prstr
mov dx,offset cmer03
int dos
jmp prserr ; Parse error - give up.
cmky43: mov ah,conout ; Ring a bell.
mov dl,bell
int dos
dec comand.cmcptr ;[ESC] don't trash BX here.
dec comand.cmdptr ;[ESC] ditto
dec comand.cmccnt ; Don't count the escape.
mov comand.cmaflg,0 ; Reset action flag.
inc ch ; Account for a previous 'dec'.
jmp cmky1 ; Start over.
cmky5: inc bx ; point to actual keyword
mov comand.cmkptr,bx ; remember current kw
mov cl,1 ; code above expects to count ?
mov comand.cmsiz,cx ; and size
mov dx,comand.cmhlp
or dx,dx ; was any help given?
jnz cmky5a ; yes, use it
jmp cmkyj1 ; else make our own message
cmky5a: mov ah,prstr
int dos
cmky50: mov ah,prstr
mov dx,offset crlf
int dos
mov dx,comand.cmprmp ; Address of prompt.
int dos
mov bx,comand.cmdptr ; Get pointer into buffer.
mov al,'$'
mov [bx],al ; Add dollar sign for printing.
mov dx,offset comand.cmdbuf
int dos
dec comand.cmcptr ; Don't keep it in the buffer.
dec comand.cmccnt ; Don't conut it.
mov comand.cmaflg,0 ; Turn off the action flag.
jmp repars
cmky51: cmp comand.cmcr,1 ; Are bare CR's allowed?
je cmky52 ; Yes.
mov ah,prstr
mov dx,offset cmer04 ; Complain.
int dos
cmky52: jmp prserr
cmky6: inc bx ; Find end of keyword.
mov al,[bx]
cmp al,'$'
jne cmky6
inc bx ; Beginning of next command.
inc bx
inc bx
mov dx,comand.cmsptr ; Get old cmdptr.
mov comand.cmdptr,dx ; Restore.
mov comand.cmsflg,0FFH
jmp cmky1 ; Keep trying.
cmky7: call cmgtch ; Get char.
cmp ah,0
js cmky71 ; Ok if a terminator.
dec bx
jmp cmky6 ; No match - try next keyword.
cmky71: inc bx ; Get necessary data.
mov bx,[bx]
cmp ah,9BH ; An escape?
jne cmky72
mov ah,prstr
mov dx,offset prsp ; Print a space.
int dos
mov di,comand.cmcptr
dec di
mov ah,20H
mov [di],ah ; Replace escape char with space.
mov comand.cmaflg,0
mov comand.cmsflg,0FFH ; Pretend they typed a space.
cmky72: jmp rskp
; See if keyword is unambiguous or not from what the user has typed in.
cmambg: cmp ch,0 ; Any keywords left to check?
jne cmamb0
ret ; If not then not ambiguous.
cmamb0: inc bx ; Go to end of keyword ...
mov al,[bx] ; So we can check the next one.
cmp al,'$'
jne cmamb0
add bx,4 ; Point to start of next keyword.
dec cl ; Don't count escape.
mov dx,comand.cmsptr ; Buffer with input typed by user.
cmamb1: mov ah,[bx] ; Keyword char.
mov di,dx
mov al,[di] ; Input char.
cmp al,'a' ; Do capitalizing.
jl cmam11
cmp al,'z'+1
jns cmam11
and al,137O
cmam11: cmp ah,al ; Keyword bigger than input (alphabetically)?
jle cmamb2 ; No - keep checking.
ret ; Yes - not ambiguous.
cmamb2: inc bx ; Advance one char.
inc dx
dec cl
jnz cmamb1
jmp rskp ; Fail - it's ambiguous.
cmifil: mov hlpmsg,bx ; Address of help message.
mov bx,dx ; Get the fcb address in bx.
mov comand.cmfcb,bx ; Save it.
mov ch,0 ; Initialize char count.
mov ah,0
mov [bx],ah ; Set the drive to default to current.
inc bx
mov comand.cmfcb2,bx
mov cl,' '
cmifi0: mov [bx],cl ; Blank the FCB.
inc bx
inc ah
cmp ah,0BH ; Twelve?
jl cmifi0
cmifi1: call cmgtch ; Get another char.
cmp ah,0 ; Is it an action character.
js cmif1x ; Jump out of range. [21a]
jmp cmifi2 ; Ditto. [21a]
cmif1x: and ah,7FH ; Turn off the action bit. [21a]
cmp ah,'?' ; A question mark?
jne cmif12
mov al,0
mov comand.cmaflg,al ; Blank the action flag.
dec comand.cmcptr ; Decrement the buffer pointer.
dec comand.cmccnt ; Decrement count.
mov ah,prstr
mov dx,hlpmsg ; Help message.
int dos
mov dx,offset crlf
int dos
mov dx,comand.cmprmp
int dos
mov bx,comand.cmdptr
mov al,'$'
mov [bx],al ; Put in dollar sign for printing.
mov dx,offset comand.cmdbuf
int dos
jmp repars
cmif12: cmp ah,esc ; An escape?
je cm12x
jmp cmif13
cm12x: mov comand.cmaflg,0 ; Turn off the action flag.
dec comand.cmcptr ; Move pointers to before the escape.
dec comand.cmdptr
dec comand.cmccnt ; Decrement char count.
mov comand.cmchr,ch ; Save current character count.
cmp ch,9 ; Past '.'?
jl cmf120 ; No.
dec ch ; Yes, don't count point.
cmf120: mov di,comand.cmfcb2 ; Fill the rest with CP/M wildcards.
mov ah,'?'
cmf121: cmp ch,11 ; Done?
jge cmf122 ; Yes.
mov [di],ah
inc di
inc ch
jmp cmf121
cmf122: mov ah,sfirst ; Find first matching file?
mov dx,comand.cmfcb ;[jd] use pointer to PASSED fcb
int dos
cmp al,0FFH ; Any found?
jne cmf123 ; Yes.
jmp cmf12b ; No, lose.
cmf123: mov di,offset filbuf ; Copy first file spec from DTA to buffer.
mov bx,offset buff+1
mov cl,11
call fcbcpy
mov di,offset filbuf+10H ; Get another copy (if not ambiguous).
mov bx,offset buff+1
mov cl,11
call fcbcpy
mov ah,snext ; More matching specs?
mov dx,comand.cmfcb ;[jd] use PASSED fcb...
int dos
cmp al,0FFH
je cmf124 ; Only one.
mov di,offset filbuf+10H ; Copy second file spec.
mov bx,offset buff+1
mov cl,11
call fcbcpy
cmf124: mov si,offset filbuf ; Start comparing file names.
mov bx,offset filbuf+10H
mov di,comand.cmcptr ; Command buffer pointer
mov cl,comand.cmchr ; Bypass characters typed.
cmp cl,9 ; Past '.'?
jl cmf125 ; No.
dec cl ; Yes, don't count point.
cmf125: mov ch,0 ; Adjust pointers.
add si,cx
add bx,cx
mov ch,cl ; Update character count
cmf126: cmp ch,11 ; All done?
jne cmf127 ; No.
jmp cmf12a ; Yes.
cmf127: cmp ch,8 ; End of file name?
jne cmf128 ; No.
cmp comand.cmchr,9 ; Exactly at point?
je cmf128 ; Yes, don't output a second point.
mov ah,'.' ; Output separator.
mov [di],ah
inc di
inc comand.cmccnt
cmf128: mov ah,[si] ; Get a character from first file spec.
inc si
mov al,[bx] ; Get another from second spec.
inc bx
cmp ah,al ; Compare.
jne cmf12a ; Ambiguous.
inc ch ; Same, count.
cmp ah,' ' ; Blank?
je cmf129 ; Yes, don't output.
mov [di],ah
inc di
inc comand.cmccnt
cmf129: jmp cmf126 ; Repeat.
cmf12a: mov comand.cmchr,ch ; Save count of characters processed.
mov ah,'$' ; Put terminator into buffer.
mov [di],ah
mov comand.cmcptr,di ; Save pointer for recognized characters.
mov ah,prstr
mov dx,comand.cmdptr
int dos
mov ch,comand.cmchr ; Characters processed.
cmp ch,11 ; Complete file name.
je cmf12c ; Yes, don't beep.
cmf12b: mov ah,conout ; Beep, if not recognized.
mov dl,bell
int dos ; Ring the bell.
cmf12c: jmp repars
cmif13: mov ah,ch ; It must be a terminator.
cmp ah,0 ; Test the length of the file name.
jnz cmf3x
cmp comand.cmcr,1 ; Is zero length OK? [21a]
je cmf3z ; Return successfully. [21a]
jmp cmifi9 ; If zero complain.
cmf3x: cmp ah,0DH
js cmf3y
jmp cmifi9 ; If too long complain.
cmf3y: jmp rskp ; Otherwise we have succeeded.
cmf3z: push es
mov ax,ds
mov es,ax
mov di,comand.cmfcb
inc di
mov cx,11
mov al,'?'
repne stosb
pop es
mov flags.wldflg,0FFH ; Remember we had a wildcard.
jmp rskp
cmifi2: cmp ah,'.'
jne cmifi3
inc ch
mov ah,ch
cmp ah,1H ; Any chars yet?
jnz cmf2x
jmp cmifi9 ; No, give error.
cmf2x: cmp ah,0AH ; Tenth char?
js cmf2y
jmp cmifi9 ; Past it, give an error.
cmf2y: mov dl,9H
mov dh,0
mov bx,comand.cmfcb
add bx,dx ; Point to file type field.
mov comand.cmfcb2,bx
mov ch,9H ; Say we've gotten nine.
jmp cmifi1 ; Get the next char.
cmifi3: cmp ah,':'
jne cmifi4
inc ch
cmp ch,2H ; Is it in right place for a drive?
je cmif3x
jmp cmifi9 ; If not, complain.
cmif3x: mov ch,0 ; Reset char count.
mov flags.droflg,1 ; Override default drive. [21a]
mov flags.nmoflg,0 ; Not so fast. [21a]
mov bx,comand.cmfcb2
mov al,':' ; Use for parsing drive name.
mov [bx],al
dec bx ; Point to drive spec.
mov si,bx
push es
mov ax,ds
mov es,ax
mov di,offset tbuff ; Borrow this buffer.
mov ah,prsfcb
int dos
pop es
cmp al,0 ; OK return code?
je cmif3y ; Yes, keep going.
; mov ah,[bx] ; Get the drive name.
; sub ah,'@' ; Get the drive number.
; cmp ah,drives ; Did user specify a non-existant drive? [21a]
; jle cmif3y ; Nope, so continue. [21a]
mov dx,offset cmer07 ; Fail with this error message. [21a]
jmp cmif9x ; [21a]
cmif3y: mov comand.cmfcb2,bx ; Put rest of filename starting here. [21a]
mov ah,[bx] ; Pick up drive specified.
sub ah,'@' ; Get real value.
mov bx,comand.cmfcb
mov [bx],ah ; Put it in the fcb.
push bx
mov al,' ' ; Overwrite the drive and ":".
inc bx
mov [bx],al
inc bx
mov [bx],al
pop bx
jmp cmifi1
cmifi4: cmp ah,'*'
jne cmifi7
cmp comand.cmrflg,1 ; In receive mode? [21a]
jne cmif4x ; Jump out of range. [21a]
mov dx,offset cmer06 ; Set the error message. [21a]
jmp cmif9x ; Fail - no wildcard allowed. [21a]
cmif4x: mov ah,ch ; [21a]
cmp ah,8H ; Is this in the name or type field?
jns cmifi5 ; Type.
mov cl,8H ; Say we have eight chars.
js cmifi6 ; Name field.
jmp cmifi9 ; If its where the dot should be give up.
cmifi5: mov cl,0CH ; Three chars.
cmifi6: mov flags.wldflg,0FFH ; Remember we had a wildcard.
mov bx,comand.cmfcb2 ; Get a pointer into the FCB.
mov ah,'?'
mov [bx],ah ; Put a question mark in.
inc bx
mov comand.cmfcb2,bx
inc ch
mov ah,ch
cmp ah,cl
jl cmifi6 ; Go fill in another.
jmp cmifi1 ; Get the next char.
cmifi7: cmp ah,03DH ; Equals sign (wildcard)?
jne cmif7x
cmp comand.cmrflg,1 ; In receive mode? [21a]
jne cmif7y ; No, so it's ok. [21a]
mov dx,offset cmer06 ; Set the error message. [21a]
jmp cmif9x ; Fail - no wildcard allowed. [21a]
cmif7y: mov ah,'?' ; New label. [21a]
mov flags.wldflg,0FFH ; Say we have a wildcard.
jmp cmifi8 ; Put into FCB.
cmif7x: cmp ah,'0'
jl cmif8x
cmp ah,'z'+1
jns cmif8x
cmp ah,'A' ; Don't capitalize non-alphabetics.
jl cmifi8
and ah,137O ; Capitalize.
cmifi8: mov bx,comand.cmfcb2 ; Get the pointer into the FCB.
mov [bx],ah ; Put the char there.
inc bx
mov comand.cmfcb2,bx
mov flags.nmoflg,1 ; Overriding name from host. [21a]
inc ch
jmp cmifi1
cmif8x: push es
mov cx,ds
mov es,cx ; Scan uses ES register.
mov di,offset spchar ; Special chars.
mov cx,spclen ; How many of them.
cmp dosnum,0 ; Under version 2.0
je cmif8y
mov di,offset spchar2
mov cx,spc2len
cmif8y: mov al,ah ; Char is in al.
repnz scasb ; Search string for input char.
cmp cx,0 ; Was it there?
pop es
jnz cmifi8
cmifi9: mov dx,offset cmer02
cmif9x: mov ah,prstr
int dos
mov flags.droflg,0 ; Not overriding drive. [21a]
mov flags.nmoflg,0 ; Or name to save file under. [21a]
mov comand.cmrflg,0 ; Reset this flag too. [21a]
ret
cmofil: jmp cmifil ; For now, the same as CMIFI.
; Parse arbitrary text up to a CR. Put chars into data buffer sent to
; the host (pointed to by BX). Called with text of help message in DX.
; Return updated pointer in BX and input size in AH.
cmtext: mov comand.cmptab,bx ; Save pointer to data buffer. [8 start]
mov cmthlp,dx ; Save the help message.
mov cl,0 ; Init the char count.
cmtxt1: mov comand.cmsflg,0 ; Get all spaces. [25]
call cmgtch ; Get a char.
test ah,80H ; is high-order bit on?
jz cmtxt5 ; Nope, put into the buffer.
and ah,07FH
cmp ah,' '
je cmtxt5
cmp ah,esc ; An escape?
jne cmtxt2
mov ah,conout
mov dl,bell ; Ring a bell.
int dos
mov comand.cmaflg,0 ; Reset action flag.
dec comand.cmcptr ; Move pointer to before the escape.
dec comand.cmdptr
dec comand.cmccnt ; Decrement count.
jmp cmtxt1 ; Try again.
cmtxt2: cmp ah,'?' ; Asking a question?
jz cmtx30
cmp ah,ff ; Formfeed?
jne cmtx2x
call cmblnk
cmtx2x: mov ah,cl ; Return count in AH.
mov bx,comand.cmptab ; Return updated pointer.
jmp rskp
cmtx30: mov comand.cmaflg,0 ; Reset action flag to zero.
inc comand.cmdptr ; count the ?
cmp cl,0 ; Is "?" first char?
jne cmtxt5 ; No, just add to buffer.
dec comand.cmcptr ;[ESC] (moved 3 lines) Don't keep in buffer.
dec comand.cmccnt ;[ESC] Don't conut it.
dec comand.cmdptr ;[ESC] don't count if printing help.
mov ah,prstr ; Else, give some help.
mov dx,cmthlp ; Address of help message.
int dos
mov ah,prstr
mov dx,offset crlf ; Print a crlf.
int dos
mov ah,prstr
mov dx,comand.cmprmp ; Reprint the prompt.
int dos
mov bx,comand.cmdptr ; Get the pointer into the buffer.
mov byte ptr [bx],'$'
mov ah,prstr
mov dx,offset comand.cmdbuf
int dos
jmp cmtxt1 ; And keep going.
cmtxt5: inc cl ; Increment the count.
mov bx,comand.cmptab ; Pointer into destination array.
mov [bx],ah ; Put char into the buffer.
inc bx
mov comand.cmptab,bx
jmp cmtxt1 ; [8 end]
cmgetc: cmp taklev,0
jne cmget1
jmp cmge10 ; no take file, get from keyboard
cmget1: push bx
push si
mov bx,takadr
mov ax,[bx].takcnt
or ax,[bx].takcnt+2
jnz cmget5
cmget2: mov al,byte ptr [bx].takfcb ; get first byte of fcb
cmp al,0ffh ; is it really a macro?
je cmget4 ; yes, better not try to close it
cmp al,0feh ; or maybe a file handle?
je cmget3 ; yes, close w/2.0 call
mov ah,closf
lea dx,[bx].takfcb
int dos
jmp short cmget4 ; skip over alternate close
cmget3: mov bx,word ptr [bx].takfcb+1 ; this is where file handle is stored
mov ah,close2 ; use 2.0 close
int dos
cmget4: dec taklev
sub takadr,size takinfo
pop si
pop bx
mov al,cr ; end with carriage return...
ret
cmget5: cmp [bx].takchl,0 ; Any chars left in buffer?
jne cmget6
call takrd
cmget6: dec [bx].takchl
sub [bx].takcnt,1 ; DEC doesn't set carry!!
sbb [bx].takcnt+2,0
mov si,[bx].takptr
lodsb
mov [bx].takptr,si
cmp al,ctlz ; maybe control-z?
je cmget2 ; yes, close take file (has to be before pops)
pop si
pop bx
cmp al,lf ; linefeed?
jne cmget7
cmp flags.takflg,0
je cmgetc ; yes, ignore it
cmget7: cmp al,';' ; maybe a semicolon?
je cmget9
cmp flags.takflg,0 ; Echo contents of take file?
je cmget8
push dx
mov dl,al
mov ah,conout
int dos
pop dx
cmget8: ret ; else just return...
; semicolon seen, ignore chars until cr
cmget9: call cmgetc ; get a character?
cmp al,cr ; carriage return?
jne cmget9 ; no, keep reading
ret ; else return it
cmge10: mov ah,coninq ; Get a char.
cmp flags.debug,0 ; in debug mode?
je cmge11 ; yes, go on
mov ah,8 ; else use read that recognizes ^C
cmge11: int dos
push ax ; save the char
cmp al,bs ; backspace?
je cmge13 ; yes, skip echo
cmp al,' ' ; printable?
jae cmge12 ; yes, no translation needed
cmp al,cr ; this is printable
je cmge12
cmp al,lf
je cmge12
cmp al,tab
je cmge12
mov al,' ' ; else echo a space
cmge12: mov dl,al ; put char here
mov ah,conout
int dos ; echo it ourselves...
cmge13: pop ax ; and return it
cmp al,'C'-40H ; control-C?
je cmge15 ; yes, go handle
cmp al,';' ; semicolon?
je cmget9 ; yes, ignore rest of line...
cmp al,tab
jne cmge14
mov al,' '
cmge14: ret
cmge15: mov dx,offset ctcmsg
mov ah,prstr
int dos
mov flags.cxzflg,'C' ; remember ^C'd
mov sp,cmdstk ; restore command stack ptr
ret ; and fail
; Come here is user types ^W when during input.
cntrlw: mov ah,prstr
mov dx,offset escspc
int dos
dec comand.cmccnt ; Don't include it in the count.
dec comand.cmcptr ; Back up past the ^W.
mov cl,comand.cmccnt
mov ch,0
jcxz ctlw2
pushf
push es
std ; Scan backwards.
mov ax,ds
mov es,ax ; Point to the data area.
mov di,comand.cmcptr ; Looking from here.
dec di
mov al,' '
repe scasb ; Look for non-space.
je ctlw1 ; All spaces, nothing else 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
mov comand.cmccnt,cl ; update count
mov cx,comand.cmcptr ; remember old ptr
mov comand.cmcptr,di ; update pointer
sub cx,di ; this is characters moved
mov al,bs ; backspace
cld
mov di,offset tbuff ; temporary buffer
rep stosb ; put enough spaces in
mov byte ptr [di],'$' ; end buffer
mov dx,offset tbuff
mov ah,prstr
int dos ; back up cursor
call clearl ; clear line
pop es
popf
ret ; and return
ctlw2: mov ah,conout
mov dl,bell
int dos
ret
cminbf: push dx
push bx
mov cx,dx ; Save value here too.
mov ah,comand.cmaflg ; Is the action char flag set?
cmp ah,0
je cminb1
jmp cminb9 ; If so get no more chars.
cminb1: inc comand.cmccnt ; Increment the char count.
call cmgetc
mov ah,al ; Keep char in 'ah'.
mov bx,comand.cmcptr ; Get the pointer into the buffer.
mov [bx],ah ; Put it in the buffer.
inc bx
mov comand.cmcptr,bx
cmp ah,'W'-64 ; Is it a ^W?
jne cmnb11
call cntrlw ; Kill the previous word.
jmp repars
cmnb11: cmp ah,25O ; Is it a ^U?
jne cminb2
cmnb12: call ctlu ; Clear out the line.
mov ah,prstr
mov dx,comand.cmprmp ; Print the prompt.
int dos
mov bx,offset comand.cmdbuf
mov comand.cmcptr,bx ; Reset the point to the start.
mov comand.cmccnt,0 ; Zero the count.
mov dx,cx ; Preserve original value of dx.
jmp repars ; Go start over.
cminb2: cmp ah,bs ; Or backspace?
jz cminb3
cmp ah,del ; Delete?
jne cminb4
cminb3: call dodel ; Delete a character.
mov ah,comand.cmccnt ; Decrement the char count by two.
dec ah
dec ah
cmp ah,0 ; Have we gone too far?
jns cmnb32 ; If not proceed.
mov ah,conout ; Ring the bell.
mov dl,bell
int dos
jmp cmnb12 ; Go reprint prompt and reparse.
cmnb32: mov comand.cmccnt,ah ; Save the new char count.
mov ah,prstr ; Erase the character.
mov dx,offset clrspc
int dos
mov bx,comand.cmcptr ; Get the pointer into the buffer.
dec bx ; Back up in the buffer.
dec bx
mov comand.cmcptr,bx
jmp repars ; Go reparse everything.
cminb4: cmp ah,'?' ; Is it a question mark.
jz cminb6
cmp ah,esc ; Is it an escape?
jz cminb8
cmp ah,cr ; Is it a carriage return?
jz cminb5
cmp ah,lf ; Is it a line feed?
jz cminb5
cmp ah,ff ; Is it a formfeed?
jne cminb7
call cmblnk
call locate
cminb5: mov ah,comand.cmccnt ; Have we parsed any chars yet?
cmp ah,1
jnz cminb6
jmp prserr ; If not, just start over.
cminb6: mov ah,0FFH ; Set the action flag.
mov comand.cmaflg,ah
jmp cminb9
cminb7: jmp cminb1 ; Get another char.
cminb8: mov ah,prstr ; Don't print the escape char.
mov dx,offset escspc
int dos
jmp cminb6
cminb9: pop bx
pop dx
ret
cmgtch: push cx
push bx
push dx
cmgtc1: mov ah,comand.cmaflg
cmp ah,0 ; Is it set.
jne cmgt10
call cminbf ; If the action char flag is not set get more.
cmgt10: mov bx,comand.cmdptr ; Get a pointer into the buffer.
mov ah,[bx] ; Get the next char.
inc bx
mov comand.cmdptr,bx
cmp ah,' ' ; Is it a space?
jz cmgtc2
cmp ah,tab ; Or a tab?
jne cmgtc3
cmgtc2: mov ah,comand.cmsflg ; Get the space flag.
cmp ah,0 ; Was the last char a space?
jne cmgtc1 ; Yes, get another char.
mov ah,0FFH ; Set the space flag.
mov comand.cmsflg,ah
mov ah,' '
pop dx
pop bx
jmp cmgtc5
cmgtc3: mov al,0
mov comand.cmsflg,al ; Zero the space flag.
pop dx
pop bx
cmp ah,esc
jz cmgtc5
cmp ah,'?' ; Is the user curious?
jz cmgtc4
cmp ah,cr
jz cmgtc4
cmp ah,lf
jz cmgtc4
cmp ah,ff
je cmgtc4
pop cx
ret ; Not an action char, just return.
cmgtc4: dec comand.cmdptr
cmgtc5: or ah,80H ; Make the char negative to indicate
pop cx
ret ; it is a terminator.
CMND ENDP
; This address is jumped to on reparse.
PARSE PROC NEAR
repars: mov sp,comand.cmostp ; new sp <-- old sp
mov bx,offset comand.cmdbuf
mov comand.cmdptr,bx
mov ah,0FFH
mov comand.cmsflg,ah
jmp comand.cmrprs ; go back to reparse address
; This address can be jumped to on a parsing error.
prserr: mov sp,comand.cmostp ; Set new sp to old one.
mov bx,offset comand.cmdbuf
mov comand.cmcptr,bx ; Initialize the command pointer.
mov comand.cmdptr,bx
mov ah,0
mov comand.cmaflg,ah ; Zero the flags.
mov comand.cmccnt,ah
mov comand.cmsflg,0FFH
cmp taklev,0 ; in take cmd?
jne prser1 ; yes, don't print prompt
mov ah,prstr
mov dx,offset crlf
int dos
mov ah,prstr ; Print the prompt.
mov dx,comand.cmprmp ; Get the prompt.
int dos
; Instead return to before the prompt call.
prser1: jmp comand.cmrprs
PARSE ENDP
; FCB must be remembered if found "*" in filename. [7 start]
; Copy from place addressed by BX to place addressed by DI.
; Also use to get the filename to the FCB from the DTA.
FCBCPY PROC NEAR
push es
push si
mov ax,ds
mov es,ax ; make sure destination segment is correct
mov ch,0 ; high-order part of length
jcxz fcbcp1 ; zero argument (is this necessary???)
mov si,bx ; this is source
rep movsb ; copy the whole thing
fcbcp1: pop si
pop es
ret ; and return
FCBCPY ENDP
; 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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 mscmd.asm
/bin/echo -n ' '; /bin/ls -ld mscmd.asm
fi
/bin/echo 'Extracting mscomm.asm'
sed 's/^X//' <<'//go.sysin dd *' >mscomm.asm
public data, spack, rpack, rpack5, portval, port1, port2, hierr
include msdefs.h
gettim equ 2CH ; Get the time of day.
maxlp equ 100 ; Use as number of times to loop (in inchr).
true equ 1
false equ 0
mntrgl equ bufsiz/4 ; Low point = 1/4 of the way full.
maxpack equ 60H ; largest packet we can handle
datas segment public 'datas'
extrn flags:byte, trans:byte, pack:byte, count:word, xofsnt:byte
port1 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon>
port2 prtinfo <0FFFH,0,defpar,1,0,defhand,floxon>
portval dw port1 ; Default is to use port 1.
hierr db 0 ; Non-ascii char (non-zero if yes).
spmes db 'Spack: $'
rpmes db 'Rpack: $'
crlf db cr,lf,'$'
infms0 db 'Waiting .....$'
hibit db 'Warning - Non Ascii char$'
cemsg db 'User intervention$'
temp dw 0
tmp db ?,'$'
pktptr dw ? ; Position in receive packet.
incnt dw ? ; Number of chars read in from port.
loopct db ? ; Loop counter.
time dw ? ; When we should timeout.
dw ? ; Want a double word.
packet db ?,?,?,? ; Packet (data is part of it).
data db 5AH DUP(?) ; Data and checksum field of packet.
recpkt db maxpack DUP(?) ; Receive packet storage (use the following).
crctab dw 00000H
dw 01081H
dw 02102H
dw 03183H
dw 04204H
dw 05285H
dw 06306H
dw 07387H
dw 08408H
dw 09489H
dw 0A50AH
dw 0B58BH
dw 0C60CH
dw 0D68DH
dw 0E70EH
dw 0F78FH
crctb2 dw 00000H
dw 01189H
dw 02312H
dw 0329BH
dw 04624H
dw 057ADH
dw 06536H
dw 074BFH
dw 08C48H
dw 09DC1H
dw 0AF5AH
dw 0BED3H
dw 0CA6CH
dw 0DBE5H
dw 0E97EH
dw 0F8F7H
datas ends
code segment public
extrn prtchr:near, clrbuf:near, outchr:near
extrn sppos:near, stpos:near, biterr:near, intmsg:near
extrn clearl:near, rppos:near, errpack:near
assume cs:code, ds:datas
; Packet routines
; Send_Packet
; This routine assembles a packet from the arguments given and sends it
; to the host.
;
; Expects the following:
; AH - Type of packet (D,Y,N,S,R,E,F,Z,T)
; ARGBLK - Packet sequence number
; ARGBK1 - Number of data characters
; Returns: +1 always
SPKT PROC NEAR
spack: push ax ; Save the packet type.
call clrbuf ; Clear the input buffer. [20e]
mov bx,offset packet ; Get address of the send packet.
mov ah,trans.ssoh ; Get the start of header char.
mov [bx],ah ; Put in the packet.
inc bx ; Point to next char.
mov ax,pack.argbk1 ; Get the number of data chars.
xchg ah,al
mov al,trans.chklen ; Length of checksum.
dec al ; Extra length of checksum.
add ah,' '+3 ; Real packet character count made printable.
add ah,al ; Account for checksum length in count.
mov [bx],ah ; Put in the packet.
inc bx ; Point to next char.
mov ch,0 ; For the 16 bit checksum.
mov cl,ah ; Start the checksum.
mov ax,pack.argblk ; Get the packet number.
add al,' ' ; Add a space so the number is printable.
mov [bx],al ; Put in the packet.
inc bx ; Point to next char.
add cx,ax ; Add the packet number to the checksum.
pop ax ; Get the packet type.
mov [bx],ah ; Put in the packet.
inc bx ; Point to next char.
mov al,0
xchg ah,al
add cx,ax ; Add the type to the checksum.
mov dx,pack.argbk1 ; Get the packet size.
spack2: cmp dx,0 ; Are there any chars of data?
jz spack3 ; No, finish up.
dec dx ; Decrement the char count.
mov al,[bx] ; Get the next char.
inc bx ; Point to next char.
mov ah,0
add cx,ax ; Add the char to the checksum.
cmp al,0
jns spack2
cmp hierr,0ffH ; Printed message already?
je spack2 ; Yes, then that's it.
push bx
push cx
push dx
call biterr
pop dx
pop cx
pop bx
mov hierr,0FFH ; set err flag.
jmp spack2 ; Go try again.
spack3: cmp trans.chklen,2 ; What kind of checksum are we using.
je spackx ; 2 characters.
jg spacky ; 3 characters.
mov ah,cl ; 1 char: get the character total.
mov ch,cl ; Save here too (need 'cl' for shift).
and ah,0C0H ; Turn off all but the two high order bits.
mov cl,6
shr ah,cl ; Shift them into the low order position.
mov cl,ch
add ah,cl ; Add it to the old bits.
and ah,3FH ; Turn off the two high order bits. (MOD 64)
add ah,' ' ; Add a space so the number is printable.
mov [bx],ah ; Put in the packet.
inc bx ; Point to next char.
jmp spackz ; Add EOL char.
spacky: mov al,0 ; Get a null.
mov [bx],al ; To determine end of buffer.
push bx ; Don't lose our place.
mov bx,offset packet+1 ; First checksummed character.
call crcclc ; Calculate the CRC.
pop bx
push cx
mov ax,cx ; Manipulate it here.
and ax,0F000H ; Get 4 highest bits.
mov cl,4
shr ah,cl ; Shift them over 4 bits.
add ah,' ' ; Make printable.
mov [bx],ah ; Add to buffer.
inc bx
pop cx ; Get back checksum value.
spackx: push cx ; Save it for now.
and cx,0FC0H ; Get bits 6-11.
mov ax,cx
mov cl,6
shr ax,cl ; Shift them bits over.
add al,' ' ; Make printable.
mov [bx],al ; Add to buffer.
inc bx
pop cx ; Get back the original.
and cx,003FH ; Get bits 0-5.
add cl,' ' ; Make printable.
mov [bx],cl ; Add to buffer.
inc bx
spackz: mov ah,trans.seol ; Get the EOL the other host wants.
mov [bx],ah ; Put in the packet.
inc bx ; Point to next char.
mov ah,0 ; Get a null.
mov [bx],ah ; Put in the packet.
cmp flags.debug,0 ; debug mode.
je spack4
inc bx
mov ah,'$'
mov [bx],ah
call sppos
call clearl ; Clear to end of line.
mov dx,offset crlf
mov ah,prstr
int dos
call clearl ; Next line too.
call sppos ; Reposition cursor.
mov ah,prstr
mov dx,offset spmes
int dos
mov dx,offset packet
mov ah,prstr
int dos ; debug end.
spack4: call outpkt ; Call the system dependent routine.
jmp r
jmp rskp
SPKT ENDP
; Write out a packet.
OUTPKT PROC NEAR
mov dh,trans.spad ; Get the number of padding chars.
outpk2: dec dh
cmp dh,0
jl outpk3 ; If none left proceed.
mov ah,trans.spadch ; Get the padding char.
call outchr ; Output it.
jmp r ; Say we failed. [25]
jmp outpk2
outpk3: mov bx,offset packet ; Point to the packet.
outlup: mov ah,[bx] ; Get the next character.
cmp ah,0 ; Is it a null?
jnz outlp2
jmp rskp
outlp2: call outchr ; Output the character.
jmp r
inc bx ; Increment the char pointer.
jmp outlup
OUTPKT ENDP
; Calculate the CRC. Returns the CRC in CX. Destroys: BX, AX.
crcclc: push dx
push si
mov dx,0 ; Initial CRC value is 0.
crc0: mov al,[bx] ; Get the first char of the string.
cmp al,0 ; If null, then we're done.
je crc1
inc bx
xor al,dl ; Xor input with lo order byte of CRC.
mov ah,al ; Get a copy.
and ah,0F0H ; Get hi 4 bits.
mov cl,4
shr ah,cl ; Right justify.
and al,0FH ; Get lo 4 bits.
push bx
mov si,offset crctb2 ; Low portion of CRC factor.
mov bh,0
mov bl,al
add bl,al ; Get word index.
mov cx,[si+bx] ; Low portion.
mov si,offset crctab ; High portion of CRC factor.
mov bh,0
mov bl,ah
add bl,ah ; Get word index.
mov bx,[si+bx]
xor bx,cx ; Add the two.
mov cl,8
shr dx,cl ; Shift CRC 8 bits to the right.
xor dx,bx ; XOR table value and CRC.
pop bx ; Retrieve index.
jmp crc0
crc1: mov cx,dx ; Return it in CX.
pop si
pop dx
ret
; Receive_Packet
; This routine waits for a packet arrive from the host. It reads
; chars until it finds a SOH.
RPACK PROC NEAR
rpack5: call inpkt ; Read up to a carriage return.
jmp r ; Return bad.
rpack0: call getchr ; Get a character.
jmp r ; Hit the carriage return, return bad.
cmp al,trans.rsoh ; Is the char the start of header char?
jne rpack0 ; No, go until it is.
rpack1: call getchr ; Get a character.
jmp r ; Hit the carriage return, return bad.
cmp al,trans.rsoh ; Is the char the start of header char?
jz rpack1 ; Yes, then go start over.
mov ch,0 ; For 16-bit checksum.
mov cl,al ; Start the checksum.
mov ah,0
mov pack.argbk1,ax ; Save the data count.
call getchr ; Get a character.
jmp r ; Hit the carriage return, return bad.
cmp al,trans.rsoh ; Is the char the start of header char?
jz rpack1 ; Yes, then go start over.
mov ah,0
add cx,ax ; Add it to the checksum.
sub al,' ' ; Get the real packet number.
mov ah,0
mov pack.argblk,ax ; Save the packet number.
call getchr ; Get a character.
jmp r ; Hit the carriage return, return bad.
cmp al,trans.rsoh ; Is the char the start of header char?
jz rpack1 ; Yes, then go start over.
mov ah,0
mov temp,ax ; Save the message type. [11]
add cx,ax ; Add it to the checksum.
; Start of change.
; Now determine block check type for this packet. Here we violate the layered
; nature of the protocol by inspecting the packet type in order to detect when
; the two sides get out of sync. Two heuristics allow us to resync here:
; a. An S packet always has a type 1 checksum.
; b. A NAK never contains data, so its block check type is LEN-2.
push cx
mov cl,al
mov ax,pack.argbk1 ; Get back the size.
sub al,34 ; unchar(len) - 2, for SEQ & TYPE fields.
mov ah,trans.chklen ; Checksum length we expect.
cmp cl,'S' ; Is this an "S" packet?
jne rpk0 ; Nope.
mov ah,1 ; Yes, use 1 char checksum.
rpk0: cmp cl,'N' ; Is this a NAK?
jne rpk1 ; Nope.
mov ah,al ; So, len - 2 is checksum type.
rpk1: mov trans.chklen,ah ; Then, this is the chksum length.
sub al,ah ; Real size of data.
mov dh,al ; Need it here.
mov ah,0
mov pack.argbk1,ax ; And here.
pop cx
; End of change.
mov bx,offset data ; Point to the data buffer.
rpack2: dec dh ; Any data characters?
js rpack3 ; If not go get the checksum.
call getchr ; Get a character.
jmp r ; Hit the carriage return, return bad.
cmp al,trans.rsoh ; Is the char the start of header char?
jz rpack1 ; Yes, then go start over.
mov [bx],al ; Put the char into the packet.
inc bx ; Point to the next character.
mov ah,0
add cx,ax ; Add it to the checksum.
jmp rpack2 ; Go get another.
rpack3: call getchr ; Get a character.
jmp r ; Hit the carriage return, return bad.
cmp al,trans.rsoh ; Is the char the start of header char?
jnz rpk3x
jmp rpack1 ; Yes, then go start over.
rpk3x: sub al,' ' ; Turn the char back into a number.
cmp trans.chklen,2 ; What checksum length is in use.
je rpackx ; Two character checksum.
jg rpacky ; Three character CRC.
mov dh,cl ; 1 char - get the character total.
and dh,0C0H ; Turn off all but the two high order bits.
mov ch,cl
mov cl,6
shr dh,cl ; Shift them into the low order position.
mov cl,ch
add dh,cl ; Add it to the old bits.
and dh,3FH ; Turn off the two high order bits. (MOD 64)
cmp dh,al ; Are they equal?
jz rpack4 ; If so finish up.
jmp rpack6 ; No, we fail.
rpacky: mov tmp,al ; Save value from packet here.
mov ah,0 ; Three character CRC.
push bx
mov bx,pktptr ; Where we are in the packet.
dec bx
mov [bx],ah ; Add null to signify end of buffer.
mov bx,offset recpkt+1 ; Where data for CRC is.
call crcclc ; Calculate the CRC and put into CX.
pop bx
push cx
mov ax,cx ; Manipulate it here.
and ax,0F000H ; Get 4 highest bits.
mov cl,4
shr ah,cl ; Shift them over 4 bits.
pop cx ; Get back checksum value.
cmp ah,tmp ; Is what we got == what we calculated?
jne rpack6
call getchr ; Get next character of checsum.
jmp r ; Failed.
cmp al,trans.rsoh ; Restarting?
jz rpack7
sub al,' ' ; Get back real value.
rpackx: mov tmp,al ; Save here for now.
push cx ; Two character checksum.
and cx,0FC0H ; Get bits 6-11.
mov ax,cx
mov cl,6
shr ax,cl ; Shift them bits over.
pop cx ; Get back the original.
cmp al,tmp ; Are they equal?
jne rpack6 ; No, we fail.
call getchr ; Get last character of checsum.
jmp r ; Failed.
cmp al,trans.rsoh ; Restarting?
jz rpack7
sub al,' ' ; Get back real value.
and cx,003FH ; Get bits 0-5.
cmp al,cl ; Do the last chars match?
jne rpack6
rpack4: mov ah,0
mov [bx],ah ; Put a null at the end of the data.
mov ax,temp ; Get the type. [11]
xchg al,ah ; Packet type should be in AH.
jmp rskp
rpack6: ret
rpack7: jmp rpack1 ; For the jump out of range.
RPACK ENDP
INPKT PROC NEAR
mov bl,flags.cxzflg ; Remember original value. [20b]
mov tmp,bl ; Store it here. [20b]
inpkt1: mov bx,offset recpkt ; Point to the beginning of the packet.
mov incnt,0
inpkt2: call inchr ; Get a character.
jmp inpkt8 ; Return failure. [20b]
nop ; Make it three bytes long. [20b]
mov [bx],ah ; Put the char in the packet.
inc bx
inc incnt
cmp ah,trans.reol ; Is it the EOL char?
je inpkt3 ; ended by eol, keep going
cmp incnt,maxpack ; is it too big?
jbe inpkt2 ; no, keep going
jmp inpkt1 ; else just start over
inpkt3: cmp incnt,1 ; Ignore bare CR. [2 start]
je inpkt1
mov bp,portval
cmp ds:[bp].hndflg,0 ; Waiting for handshake?
jz inpkt5 ; If not then proceed.
inpkt4: call inchr ; Wait for the turn around char.
jmp inpkt8 ; Return failure. [20b]
nop ; Make it three bytes long. [20b]
mov bp,portval
cmp ah,ds:[bp].hands ; Is it the IBM turn around character?
jne inpkt4 ; If not, go until it is.
inpkt5: cmp flags.debug,0 ; In debug mode?
je inpkt6
mov ah,'$'
mov [bx],ah
call rppos
call clearl ; Clear to end of line.
mov dx,offset crlf
mov ah,prstr
int dos
call clearl ; Next line too.
call rppos ; Reposition cursor.
mov ah,prstr
mov dx,offset rpmes
int dos
mov dx,offset recpkt
mov ah,prstr
int dos ; debug end.
inpkt6: mov bx,offset recpkt
mov pktptr,bx ; Save the packet pointer.
mov bl,tmp ; Get the original value. [20b]
cmp bl,flags.cxzflg ; Did ^X/^Z flag change? [20b]
je inpkt7 ; If not, just return. [20b]
cmp flags.cxzflg,'E' ; Error packet?
je inpkt9
call intmsg ; Else, say we saw the interrupt. [20b]
inpkt7: jmp rskp ; If so we are done.
inpkt8: cmp flags.cxzflg,'C' ; Did the user type a ^C? [25]
jne inpkt9
mov pack.state,'A'
ret
inpkt9: cmp flags.cxzflg,'E' ; How about ^E?
jne inpk10 ; No just go on.
mov bx,offset cemsg ; Null message for error packet.
call errpack
mov pack.state,'A'
ret
inpk10: mov bl,tmp ; Get the original value. [20b]
cmp bl,flags.cxzflg ; Did ^X/^Z flag change? [20b]
je inpk11 ; If not, just return failure. [20b]
call intmsg ; Else, say we saw the interrupt. [20b]
inpk11: jmp r
INPKT ENDP
inchr: cmp flags.timflg,0 ; Are timeouts turned off.
je inchr1 ; Yes, so skip this stuff.
cmp trans.stime,0 ; Don't time out?
je inchr1 ; Yes, so skip this stuff.
mov loopct,0 ; Use to check for timeout.
mov ah,gettim ; Get the time.
int dos
mov time,cx
mov time+2,dx
mov ah,0
mov al,trans.stime ; Timeout when getting data.
mov cl,8
shl ax,cl ; Move timeout to seconds field.
add time+2,ax ; If get to this time, then timeout.
jnc inchr1
inc time
inchr1: call prtchr ; Is there a character to read?
jmp inchr6 ; Got one.
mov dl,0FFH ; To read in a char.
mov ah,dconio ; Is a char on the console?
int dos
jz inchr2 ; If not go look for another char.
mov ah,al
cmp ah,cr ; Is it a carriage return?
je inchr5 ; If yes, then leave.
cmp ah,'Z'-100O ; Control-Z? [20b]
je inchr4 ; Yes - flag it. [20b]
cmp ah,'X'-100O ; Control-X? [20b]
je inchr4 ; Yes - flag it. [20b]
cmp ah,'E'-100O ; Control-E?
je inchr4 ; Flag it and get rest of packet.
cmp ah,'C'-100O ; Control-C? [25]
jne inchr2 ; No, then wait for input. [25]
add ah,100O ; Make it printable. [25]
mov flags.cxzflg,ah ; Save it. [25]
ret ; Return right away. [25]
inchr2: cmp flags.timflg,0 ; Are timeouts turned off?
je inchr1 ; Yes, just check for more input.
cmp trans.stime,0 ; Doing time outs?
je inchr1 ; No, just go check for more input.
inc loopct
cmp loopct,maxlp ; Times to go without checking time.
jne inchr1 ; Don't check yet.
mov ah,gettim ; Get the current time.
int dos
mov ax,time
sub ax,cx ; Check hours and minutes.
jl inchr5 ; Over the limit so fail.
jg inchr3 ; Under the limit, keep going.
mov ax,time+2
sub ax,dx ; Else, check seconds and hundreds of seconds.
jle inchr5 ; Return failure.
inchr3: mov loopct,0 ; Reset counter.
jmp inchr1
inchr4: add ah,100O ; Make it printable. [20b]
mov flags.cxzflg,ah ; Remember what we saw. [20b]
jmp inchr2 ; Continue getting input. [20b]
inchr5: ret
inchr6: mov ah,al
mov bp,portval ; Point to current port structure.
cmp ds:[bp].parflg,parnon ; Is the parity none? [10]
je inchr7 ; We're done. [10]
and ah,7FH ; Turn off the parity bit.
inchr7: cmp ds:[bp].floflg,0 ; Doing any flow control?
jne inchr8 ; Yes, check it out.
jmp rskp ; No, just return the data.
inchr8: cmp xofsnt,true ; Have we sent flow char (XOFF)?
je inchr9 ; Yes.
jmp rskp ; No, just return.
inchr9: cmp count,mntrgl ; Under the low trigger point?
jb inchra ; Yes.
jmp rskp ; No, just return.
inchra: push ax
mov bp,portval
mov ax,ds:[bp].flowc ; Get flow control char (AH = XON, AL = XOFF).
call outchr ; Send it (XON).
mov xofsnt,false ; Turn off the flag.
pop ax
jmp rskp ; Return the character.
; Return next character in AL.
GETCHR PROC NEAR
push bx
mov bx,pktptr ; Get the packet pointer.
mov al,[bx] ; Get the char.
inc bx
mov pktptr,bx
pop bx ; Restore BX.
cmp al,trans.reol ; Is it the EOL char?
jne getcr2 ; If not return retskp.
ret ; If so return failure.
getcr2: jmp rskp
GETCHR ENDP
; 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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 mscomm.asm
/bin/echo -n ' '; /bin/ls -ld mscomm.asm
fi
/bin/echo 'Extracting msdefs.h'
sed 's/^X//' <<'//go.sysin dd *' >msdefs.h
verdef macro
db ' Kermit-MS V2.26'
endm
BELL EQU 07Q
TAB EQU 11Q
LF EQU 12Q
FF EQU 14Q
CR EQU 15Q
XXON EQU 21Q
XXOFF EQU 23Q
ESC EQU 33Q
DEL EQU 177Q
BS EQU 08H
CTLZ EQU 1AH
SOH EQU 01H ; Start of header char.
DOS EQU 21H
CONIN EQU 01H
CONOUT EQU 02H
RDRIN EQU 03H
PUNOUT EQU 04H
LSTOUT EQU 05H
DCONIO EQU 06H
CONINQ EQU 07H ; quiet console input
PRSTR EQU 09H
CONSTAT EQU 0BH
SELDSK EQU 0EH ; Select disk. [21a]
OPENF EQU 0FH
CLOSF EQU 10H
SFIRST EQU 11H
SNEXT EQU 12H
DELF EQU 13H
READF EQU 14H ; Read from the file.
WRITEF EQU 15H
MAKEF EQU 16H
GCURDSK EQU 19H ; Current disk. [21a]
SETDMA EQU 1AH
PRSFCB equ 29H ; parse an fcb.
DOSVER equ 30H ; dos version #
OPEN2 EQU 3DH ; 2.0 open
CLOSE2 EQU 3EH ; 2.0 close
READF2 EQU 3FH ; 2.0 read.
LSEEK EQU 42H ; 2.0 lseek
IOCTL EQU 44H
WRITEF2 EQU 40H ; 2.0 write
GCD equ 47H ; 2.0 get current directory.
PAREVN EQU 00H ; Even parity. [10 start]
PARMRK EQU 01H ; Mark parity.
PARNON EQU 02H ; No parity.
PARODD EQU 03H ; Odd parity.
PARSPC EQU 04H ; Space parity.
CMKEY EQU 01H ; Parse a keyword.
CMIFI EQU 02H ; Parse an input file spec (can be wild).
CMOFI EQU 03H ; Parse an output file spec.
CMCFM EQU 04H ; Parse a confirm.
CMTXT EQU 05H ; Parse arbitrary text up to CR. [8]
FLOXON EQU 1113H ; Use XON/XOFF for flow control.
FLONON EQU 0 ; Don't do flow control.
DEFHAND EQU XON ; Use XON as default handshake.
DMASIZ EQU 80H ; Size of DMA.
FCBSIZ EQU 25H
MAXTAK EQU 05H ; Max number of TAKE's allowed. [25t]
MAXTRY EQU 05Q ; Default number of retries on a packet.
IMXTRY EQU 20Q ; Default number of retries send initiate.
DEFESC EQU ']'-100Q ; The default escape character.
DRPSIZ EQU 5EH ; Default receive packet size.
DSPSIZ EQU 50H ; Default send packet size.
DSTIME EQU 08H ; Default send time out interval.
DRTIME EQU 0DH ; Default receive time out interval.
DSRVTM EQU 30 ; Default server timeout.
DSPAD EQU 00H ; Default send padding.
DRPAD EQU 00H ; Default receive padding.
DSPADC EQU 00H ; Default send padding char.
DRPADC EQU 00H ; Default receive padding char.
DSEOL EQU CR ; Default send EOL char.
DREOL EQU CR ; Default receive EOL char.
DSSOH EQU SOH ; Default send start-of-packet char.
DRSOH EQU SOH ; Default receive start-of-packet char.
DSQUOT EQU '#' ; Default send quote char.
DRQUOT EQU '#' ; Default receive quote char.
DQBIN EQU '&' ; Default 8-bit prefix. [21b]
DRPT EQU '~' ; Default repeat prefix.
DCHKLEN EQU 1 ; Default checksum length.
DEFPAR EQU PARNON ; Default parity (none.)
IBMPAR EQU PARMRK ; IBM's parity (mark.) [10 end]
bufsiz equ 2048 ; size of serial input buffer
; baud rate definitions
B00455 EQU 0 ; 45.5 baud
B0050 EQU 1 ; 50 baud
B0075 EQU 2 ; 75 baud
B0110 EQU 3 ; 110 baud
B01345 EQU 4 ; 134.5 baud
B0150 EQU 5 ; 150 baud
B0300 EQU 6 ; 300 baud
B0600 EQU 7 ; 600 baud
B1200 EQU 8 ; 1200 baud
B1800 EQU 9 ; 1800 baud
B2000 EQU 10 ; 2000 baud
B2400 EQU 11 ; 2400 baud
B4800 EQU 12 ; 4800 baud
B9600 EQU 13 ; 9600 baud
B19200 EQU 14 ; 19200 baud
B38400 EQU 15 ; 38400 baud
BAUDSIZ EQU 16 ; Number of options for baud rate.
; Structure definitions.
; Modem information.
mdminfo struc
mddat dw 0 ; Default to port 1. [19b start]
mdstat dw 0 ; Ditto.
mdcom dw 0 ; Here too.
mden db 0
mddis db 0
mdmeoi db 0
mdintv dw 0 ; [19b end]
mdminfo ends
; Command information.
cmdinfo struc
cmstat db 0 ; What is presently being parsed.
cmaflg db 0 ; Non-zero when an action char has been found.
cmccnt db 0 ; Non-zero if a significant char is found.
cmsflg db 0 ; Non-zero when the last char was a space.
cmostp dw 0 ; Old stack pointer for reparse.
cmrprs dw 0 ; Address to go to on reparse.
cmprmp dw 0 ; Address of prompt.
cmptab dw 0 ; Address of present keyword table.
cmhlp dw 0 ; Address of present help.
cmdbuf db 80H DUP(0) ; Buffer for command parsing.
cmfcb dw 0 ; Pointer to FCB.
cmfcb2 dw 0 ; Pointer to position in FCB.
cmcptr dw 0 ; Pointer for next char input.
cmdptr dw 0 ; Pointer into the command buffer.
cmsiz dw 0 ; Size info of user input.
cmkptr dw 0 ; Pointer to keyword.
cmsptr dw 0 ; Place to save a pointer.
cmchr db 0 ; Save char when checking ambiguity.
cmrflg db 0 ; Assume parsing filename for send. [21a]
cmcr db 0 ; Say whether bare CR is allowed.
cmdinfo ends
; Flags information.
flginfo struc
belflg db 1 ; Use bell [17a -- DT]
comflg db 1 ; Use COM1 by default. [19b]
abfflg db 1 ; Discard incoming file if abort. [20d]
debug db 0 ; Debugging mode (default off).
flwflg db 1 ; File warning flag (default on). [19c]
ibmflg db 0 ; IBM flag (default off).
extflg db 0 ; Exit flag (default off).
vtflg db 1 ; H-19 emulation.
droflg db 0 ; Override default disk drive. [21a]
nmoflg db 0 ; Override name from the F packet. [21a]
wldflg db 0 ; Assume no "*" in fn. [7]
cxzflg db 0 ; ^X/^Z to interrupt file x-fer. [20b]
xflg db 0 ; Seen "X" packet. [21c]
filflg db 0 ; Non-zero when nothing in DMA buffer.
eoflag db 0 ; EOF flag; non-zero on EOF.
getflg db 0 ; Assume normal RECEIVE (not GET). [21a]
capflg db 0 ; On if capturing data. [25]
takflg db 0 ; On if echo commands of TAKE file.
timflg db 0 ; Say if are timing out or not.
destflg db 1 ; Incoming files destination: disk or printer.
eofcz db 0 ; ^Z signals eof if non-zero.
remflg db 0 ; non-zero if in remote mode.
flginfo ends
; Transmission parameters
trinfo struc
maxdat db 0 ; Max packet size for send.
chklen db 1 ; Number of characters in checksum.
seol db dseol ; Send EOL char.
reol db dreol ; Receive EOL char.
ssoh db dssoh ; Send start-of-packet character.
rsoh db drsoh ; Receive start-of-packet character.
squote db dsquot ; Send quote character.
rquote db drquot ; Receive quote character.
spsiz db dspsiz ; Send packet size.
rpsiz db drpsiz ; Receive packet size.
stime db dstime ; Send timeout. (Don't timeout).
rtime db drtime ; Receive timeout.
spad db dspad ; Send padding.
rpad db drpad ; Receive padding.
spadch db dspadc ; Send padding char.
rpadch db drpadc ; Receive padding char.
ebquot db 'Y' ; Send 8-bit quote character.
escchr db defesc ; Escape character.
trinfo ends
pktinfo struc
pktnum dw 0 ; Packet number.
numpkt dw 0 ; Total number of packets sent.
numrtr dw 0 ; Total number of retries.
numtry db 0 ; Number of tries on this packet.
oldtry db 0 ; Number of tries on previous packet.
state db 0 ; Present state of the automaton.
argblk dw 0 ; For subroutine arguments.
argbk1 dw 0
argbk2 dw 0
argbk3 dw 0
pktinfo ends
takinfo struc
takfcb db fcbsiz dup(0)
takbuf db dmasiz dup(0)
takptr dw 0
takchl db 0
takcnt dw 0,0
takinfo ends
; Port Information.
prtinfo struc
baud dw 0 ; Default baud rate.
ecoflg db 0 ; Local echo flag (default off).
parflg db 0 ; Parity flag (default none.) [10]
floflg db 0 ; If need flow control during file x-fer.
hndflg db 0 ; If need handshake during file x-fer.
hands db 0 ; Default handshake.
flowc dw 0 ; Do flow control with XON/XOFF.
prtinfo ends
mkeyw macro key,val
local junk,oldval
oldval equ $
db junk,key,'$'
junk equ $-oldval-2
dw val
endm
; definitions for terminal handler:
termarg struc
flgs db ? ; flags
prt db ? ; port to use (0,1)
cols db ? ; # columns on screen
rows db ? ; # rows on screen
captr dw ? ; routine to call with captured data
belld dw ? ; bell divisor
klen dw ? ; length of key redefinition table
ktab dw ? ; address of key redefinition table
krpl dw ? ; address of key replacement table
escc db ? ; escape character
baudb db ? ; baud rate bits.
parity db ? ; parity
termarg ends
; bits for flag byte
scrsam equ 80h ; on if shouldn't redraw screen
capt equ 40h ; capture output
emheath equ 20h ; emulate heath
havtt equ 10h ; have translate table
trnctl equ 08h ; translate control chars
modoff equ 04h ; mode line off
lclecho equ 01h ; local echo
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msdefs.h
/bin/echo -n ' '; /bin/ls -ld msdefs.h
fi
/bin/echo 'Extracting msfile.asm'
sed 's/^X//' <<'//go.sysin dd *' >msfile.asm
public bufpnt, buff, fcb, cpfcb, chrcnt, fixfcb, init, init1,
public gofil, outbuf, ptchr, gtchr, gtnfil, getfil, filbuf,
public encode, decode, nulref, nulr, decbuf, errpack, rptq,
public origr, rptct, rptval, clrfln, cxmsg, biterr, intmsg,
public rtpos, erpos,rppos, stpos,nppos,rprpos,nrtpos,sppos,
public kbpos,perpos,frpos, prtscr
include msdefs.h
rptmin equ 3 ; At least 3 of same char in a row.
; equates for screen positioning
scrfln equ 0316H ; Place for file name.
scrkb equ 0416H ; Place for percent transferred.
scrper equ 0516H ; Place for Kbytes transferred.
scrst equ 0616H ; Place for status.
scrnp equ 0816H ; Place for number of packets.
scrnrt equ 0916H ; Place for number of retries.
screrr equ 0A16H ; Place for error msgs.
scrhi equ 0B16H ; Err when 8th bit is on.
scrfr equ 0B16H ; Rename file.
scrint equ 0B16H ; Acknowledge interrupt. [20b]
scrsp equ 0C00H ; Place for send packet.
scrrp equ 0E00H ; Place for receive packet.
scrrpr equ 1100H ; Prompt when Kermit ends.
datas segment public 'datas'
extrn data:byte, flags:byte, trans:byte, pack:byte, hierr:byte
extrn dosnum:byte
outlin db cr,lf,cr,lf
db cr,lf,' File name:'
db cr,lf,' KBytes transferred:'
db cr,lf
db cr,lf
db cr,lf
db cr,lf,' Number of packets:'
db cr,lf,' Number of retries:'
db cr,lf,' Last error: None'
db cr,lf,' Last warning: None'
db '$'
ermes4 db 'Unable to rename file$'
erms10 db '?Unable to receive data$'
erms11 db '?Disk full$'
erms12 db '?Unable to create file$'
erms17 db 'Record length exceeds size of buffer$'
infms5 db 'Renaming file to $'
infms7 db 'File interrupt$'
infms8 db 'File group interrupt$'
hibit db 'Warning - Non Ascii char$'
crlf db cr,lf,'$'
printer db 0,'LPT1 '
spchar db 24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH
db 3CH,3EH,7BH,7DH,5FH,5CH,5EH,7EH,7CH,60H
spclen equ $-spchar ; Number of special chars.
spchar2 db 24H,26H,23H,40H,21H,25H,27H,28H,29H,2DH
db 7BH,7DH,5FH,5EH,7EH,60H
spc2len equ $-spchar2
next db 0FFH ; No next character just yet.
rptval db 0 ; Repeated character.
rptct db 1 ; Number of times it's repeated.
rptq db drpt ; Repeat prefix.
origr db drpt ; Original repeat prefix.
temp1 dw ? ; Temporary storage.
temp2 dw ?
oloc dw 0 ; Original buffer location. [21c]
osiz dw 0 ; Original buffer size. [21c]
chrcnt dw ? ; Number of chars in the file buffer.
outpnt dw ? ; Position in packet.
bufpnt dw ? ; Position in file buffer.
fdtpnt dw ? ; Pointer to within our file.
fcbptr dw ? ; Position in FCB.
cbfptr dw ? ; Position in character buffer.
filsiz dw 0 ; Double word for filesize (in bytes.)
dw 0
ofilsz dw 0 ; Original file size percent adjusted (/100).
tfilsz dw 0 ; Bytes transferred.
dw 0
oldper dw ? ; old percentage
oldkbt dw ? ; old KB transferred.
wrpmsg db ? ; non-zero if we wrote percent message
percnt dw 100 ; Number to divide by for a percent.
bufhex dw 80H
permsg db cr,' Percent transferred:$'
cxzhlp db '^X cancels file, ^Z cancels batch'
db ', ^E aborts protocol'
db ', ^C aborts at once'
db '$'
asmsg db ' AS '
asmln equ $-asmsg
filbuf db 60H DUP(?) ; Character buffer.
buff db dmasiz DUP(?) ; Use as our DTA.
fcb db fcbsiz DUP(?) ; Use as our FCB.
cpfcb db fcbsiz DUP(?) ; Save FCB in case of "*". [7]
decbuf db dmasiz DUP(?) ; For decoding incoming data.
datas ends
code segment public
extrn spack:near, cmblnk:near, locate:near, nout:near
extrn putmod:near, poscur:near, clearl:near, fcbcpy:near
assume cs:code,ds:datas
; Position cursor for an error message.
ERPOS PROC NEAR
cmp flags.xflg,1 ; Packet header seen? [21c start]
jne erp0 ; No, do as normal.
mov dx,offset crlf
mov ah,prstr
int dos
ret
erp0: mov dx,screrr
jmp poscur
ERPOS ENDP
; Position cursor for number of retries message.
RTPOS PROC NEAR
cmp flags.xflg,1 ; Packet header seen? [21c]
jne rtp0 ; No, do as normal.
ret
rtp0: mov dx,scrnrt
jmp poscur
RTPOS ENDP
; Reassure user that we acknowledge his ^X/^Z.
INTMSG PROC NEAR
cmp flags.xflg,0 ; Writing to screen?
jne int1 ; Yes. Don't do anything.
mov dx,scrint
call poscur
call clearl
mov dx,offset infms7 ; File interrupted?
cmp flags.cxzflg,'X' ; Yes.
je int0
mov dx,offset infms8 ; File group interrupted.
int0: mov ah,prstr
int dos
int1: ret
INTMSG ENDP
; Print err message that found a non-standard-Ascii char in the file.
BITERR PROC NEAR
cmp flags.remflg,0 ; remote mode?
jne biter1 ; yes, no printing.
push bx
mov dx,scrhi
call poscur
call clearl
mov ah,prstr
mov dx,offset hibit
int dos
pop bx
biter1: ret
BITERR ENDP
; Clear out message about interrupted file.
CXMSG PROC NEAR
cmp flags.xflg,0 ; Writing to screen?
jne cxm0 ; Yes. Don't do anything.
mov dx,scrint
call poscur
call clearl
cxm0: ret
CXMSG ENDP
; Clear out the old filename on the screen.
CLRFLN PROC NEAR
mov dx,scrfln
call poscur
call clearl ; Clear to end of line. [19a]
ret
CLRFLN ENDP
; some random screen positioning functions
kbpos: mov dx,scrkb ; KBytes transferred.
jmp poscur
perpos: mov dx,scrper ; Percent transferred.
call poscur
jmp clearl
frpos: mov dx,scrfr ; Say renamed file.
call poscur
jmp clearl
stpos: mov dx,scrst ; Print status of file transfer.
call poscur
jmp clearl
nppos: mov dx,scrnp ; Number of packets sent.
jmp poscur
rprpos: mov dx,scrrpr ; Reprompt position.
jmp poscur
nrtpos: mov dx,scrnrt ; Number of retries.
jmp poscur
sppos: mov dx,scrsp ; Send packet location.
jmp poscur
rppos: mov dx,scrrp ; Receive packet location.
jmp poscur
; Initialize buffers and clear line.
INIT PROC NEAR
call cmblnk
call locate
mov ah,prstr ; Put statistics headers on the screen.
mov dx,offset outlin
int dos
mov dx,offset cxzhlp
call putmod ; write mode line
mov wrpmsg,0 ; haven't printed the messsage yet.
call init1
ret
INIT ENDP
INIT1 PROC NEAR
mov chrcnt,dmasiz ; Number of chars left.
mov bufpnt,offset buff ; Addr for beginning.
mov hierr,0
ret
INIT1 ENDP
; Output the chars in a packet.
; Called with AX = size of the data, BX = address of source.
FILEIO PROC NEAR
ptchr: mov cx,ax
lea ax,outbuf ; Where to put data when buffer gets full.
jmp decode
; CX = Size of data, BX = Address of data, AX = Routine to call to
; dump data.
decode: push si
push di
push es
push dx
push ax
mov ax,ds
mov es,ax
pop ax
mov si,bx ; Source of data.
mov bx,ax ; Coroutine to call.
mov di,bufpnt ; Destination of data.
mov dh,0 ; assume no quote char
cmp trans.ebquot,'N' ; no quoting?
je decod1 ; yes, keep going
cmp trans.ebquot,'Y' ; or not doing it?
je decod1 ; yes, keep going
mov dh,trans.ebquot ; otherwise use quote char
decod1: mov rptct,0 ; Reset.
mov rptval,0 ; Ditto.
dec cx
jge dcod11 ; More data.
jmp decod6 ; Else, we're through.
dcod11: dec chrcnt ; Decrement number of chars in dta.
jns decod2 ; Continue if space left.
push cx
push dx
push bx
call bx ; Output it if full.
jmp decod5 ; Error return if disk is full.
nop
pop bx
pop dx
pop cx
mov di,bufpnt
decod2: cmp rptct,0 ; Doing a repeat?
je dcod20 ; No, so go get a character.
mov ah,0
mov al,rptval ; Get the character we're repeating.
jmp decod4 ; And write it out to the file.
dcod20: lodsb ; Pick up a char.
cmp rptq,0 ; Doing repeat quoting?
je dcod21 ; Nope, skip this part.
cmp al,rptq ; Did we pick up the repeat quote char?
jne dcod21 ; No, continue processing it.
lodsb ; Get the size.
dec cx ; Modify buffer count.
sub al,20H ; Was made printable.
mov rptct,al ; Remember how many repetitions.
lodsb ; Get the char to repeat.
dec cx ; Modify buffer count.
dcod21: mov ah,00H ; Assume no 8-bit quote char. [21b start]
cmp al,dh ; This the 8-bit quot char?
jne decod3
lodsb ; Get the real character.
dec cx ; Decrement # chars in packet
mov ah,80H ; Turn on 8-bit quot char flag. [21b end]
decod3: cmp al,trans.squote ; Is it the quote char? [21b] [21c]
jne decod4 ; If not proceed.
lodsb ; Get the quoted character
dec cx ; Decrement # of chars in packet.
or ah,al ; save parity (combine with prefix)
and ah,80h ; only parity
and al,7FH ; Turn off the parity bit.
cmp al,trans.squote ; Is it the quote char? [21c]
je decod4 ; If so just go write it out.
cmp al,dh ; This the 8-bit quot char?
je decod4 ; If so, just go write it out
cmp al,rptq ; Is is the repeat quote character?
je decod4 ; If so, just write it out.
add al,40H ; Make it a control char again.
and al,7FH ; Modulo 128.
decod4: or al,ah ; or in parity
stosb ; store the character
dec rptct ; Repeat counter.
cmp rptct,0 ; Write out char again?
jg dcod41
jmp decod1 ; No, get next char.
dcod41: mov rptval,al ; Save the char.
jmp dcod11 ; and loop to next char.
decod5: pop bx
pop dx ; dx is pushed twice (really)
pop cx
pop dx
pop es
pop di
pop si
ret
decod6: mov bufpnt,di
pop dx
pop es
pop di
pop si
jmp rskp ; Return successfully if done.
; output the buffer, reset bufpnt and chrcnt
outbuf: cmp flags.xflg,1 ; Writing to screen? [21c]
je outbf2 ; Yes, handle specially. [21c]
push bx
mov ah,writef ; The write code.
mov dx,offset fcb
int dos ; Write the record.
pop bx
cmp al,0 ; Successful.
jz outbf1
push ax ; Remember the return code. [20d]
call abfil ; Fix things up before aborting. [20d]
pop ax ; Retrive return code. [20d]
cmp al,01
jz outbf0
call erpos
mov ah,prstr
mov dx,offset erms17 ; Record length exceeds dta.
int dos
ret
outbf0: call erpos
mov ah,prstr ; Tell about it.
mov dx,offset erms11 ; Disk full error.
int dos
ret
outbf1: add tfilsz+2,80H ; Say 128 more characters received.
adc tfilsz,0
call kbpr ; Print the kilobytes received.
call perpr ; Print the percent ('?' for now).
outb11: mov bufpnt,offset buff ; Addr for beginning.
mov chrcnt,dmasiz-1 ; Buffer size.
jmp rskp
outbf2: mov cx,dmasiz-1 ; Number of chars to write. [21c]
sub cx,chrcnt ; minus # of unused in buffer
mov di,offset buff ; Where they are. [21c]
call prtscr ; Output buffer to screen. [21c]
jmp outb11 ; Reset counter & pointer. [21c]
; Tidy up before aborting. [20d]
ABFIL PROC NEAR
mov ah,closf ; Close the file.
mov dx,offset fcb
int dos
cmp flags.abfflg,1 ; Delete what got across or keep it?
jne abfil0 ; Nope, keep it.
mov ah,delf ; Delete it.
mov dx,offset fcb
int dos
abfil0: mov bx,offset erms10 ; Text of message to send.
call errpack ; Send an error packet.
ret
ABFIL ENDP
; General routine for sending an error packet. Register BX should
; point to the text of the message being sent in the packet. [20f]
ERRPACK PROC NEAR
mov di,offset data ; Where to put the message.
mov al,0
errp1: mov ah,[bx]
cmp ah,'$' ; At end of message?
je errp2
inc al ; Remember number of chars in msg.
mov [di],ah
inc bx
inc di
jmp errp1
errp2: mov ah,0
mov pack.argbk1,ax
mov ah,'E' ; And send an error packet.
call spack
ret ; Return if succeed or fail.
nop
nop
ret
ERRPACK ENDP
; Get the chars from the file.
gtchr: cmp flags.filflg,0 ; Is there anything in the DMA?
jz gtchr0 ; Yup, proceed.
mov ah,rptq
mov origr,ah ; Save repeat prefix here.
mov rptct,1 ; Number of times char is repeated.
mov rptval,0 ; Value of repeated char.
call inbuf
jmp gtchr1 ; No more chars, go return EOF.
nop ; Make three bytes long.
gtchr0: lea bx,inbuf
jmp encode
gtchr1: mov ax,0ffffh
ret
; encode - writes data portion of kermit packet into filbuf.
; expects BX to contain the address of a routine to refill the buffer,
; chrcnt to be the # of chars in the buffer, trans.maxdat to contain
; the maximum size of the data packet, bufpnt to contain a pointer to
; the source of the characters.
; Returns: AX/ the number of characters actually written to the buffer.
encode: mov cl,trans.maxdat ; Maximum packet size. [21b]
mov ch,0
mov di,offset filbuf ; Where to put the data.
mov si,bufpnt ; pointer into source buffer
mov dl,trans.rquote ; send quote char
mov dh,0 ; assume no 8-bit quoting
cmp trans.ebquot,'N' ; not doing 8-bit quoting
je encod1
cmp trans.ebquot,'Y' ; or can but won't?
je encod1
mov dh,0ffh ; remember we have to do it
encod1: dec cx ; Decrement output buffer counter.
jge encod2 ; Go on if there is more than one left.
sub di,offset filbuf
mov ax,di
mov bufpnt,si ; update pointer into DMA.
jmp rskp
encod2: dec chrcnt ; any data in buffer?
jge encod3 ; yes, skip over buffer refill.
call bx ; Get another buffer full.
jmp encod8
mov si,bufpnt ; update position in DMA.
cmp chrcnt,0 ; no characters returned?
jne encod3 ; Got some, keep going.
jmp encod8 ; none, assume eof.
encod3: lodsb
cmp rptq,0 ; Are we doing repeat prefixing?
je encd3x ; Nope, skip next part.
cmp chrcnt,0 ; Are we on the last character?
jle encd31 ; Yes, so there's no next character.
cmp rptct,94 ; Max number that we can put in a byte.
je encd31 ; Then that's it.
mov ah,[si] ; Get the next character.
cmp al,ah ; Is current char == next char?
jne encd31
inc rptct ; Number of times char appears.
mov rptval,al ; Remember the character.
inc cx ; Repeats don't take up so much buffer space.
jmp encod1 ; Keep checking for more.
encd31: cmp rptct,1 ; Were previous characters repeats?
je encd3x ; No, so just add this char.
cmp rptct,rptmin ; Are we within bounds for repeat prefixing?
jge encd32 ; Yes, use repeat prefixing.
mov al,rptct
mov ah,0
sub si,ax ; Not enough characters to warrant it.
mov rptval,0 ; Clear out this value.
inc cx ; Adjust output buffer pointer.
mov al,rptq
mov origr,al ; Save original repeat prefix.
mov rptq,0 ; Pretend we're not doing the prefixing.
mov al,rptct
mov ah,0
add chrcnt,ax ; Adjust input buffer pointer.
jmp encod1 ; Reprocess those characters.
encd32: push ax ; Do repeat prefixing - save data.
mov al,rptq ; Add repeat prefix char.
stosb
dec cx ; Account for it in buffer size.
mov al,rptct ; Get the repeat count.
add al,20H ; Make it printable.
stosb ; Add to buffer.
dec cx
pop ax ; Get back the actual character.
mov rptct,1 ; Reset repeat count.
mov rptval,0 ; And this.
encd3x: cmp dh,0 ; are we doing 8-bit quoting?
je encod4 ; no, forget this.
test al,80h ; parity on?
je encod4 ; no, don't bother with this
and al,7fh ; turn off parity
push ax ; save original char for a bit
dec cx ; decrement # of chars left
mov al,trans.ebquot ; get quote char
stosb ; save in buffer
pop ax ; restore character
encod4: mov ah,al ; save character
and ah,80h ; only parity
and al,7fh ; turn off parity in character
cmp al,' ' ; Compare to a space.
jl encod5 ; If less then its a control char.
cmp al,del ; Is the char a delete?
jz encod5 ; Go quote it.
cmp al,dl ; Is it the quote char?
je encod6 ; Yes - go add it. [21b start]
cmp dh,0 ; are we doing 8-bit quoting?
je encd41 ; no, don't translate it
cmp al,trans.ebquot ; Is it the 8-bit quote char?
je encod6 ; Yes, just output with quote
encd41: cmp origr,0 ; Doing repeat prefixing?
je encod7 ; No, don't check for quote char.
cmp al,origr ; Is this the repeat quote character.
je encod6 ; Yes, then quote it.
jmp short encod7 ; else don't quote it.
encod5: add al,40h ; control char, uncontrollify
and al,7fh
encod6: push ax ; save the char
dec cx
mov al,dl
stosb
pop ax
encod7: or al,ah ; put parity back
stosb
cmp rptct,1 ; One occurence of this char?
jne encd7x
mov al,origr
mov rptq,al ; Restore repeat quote char.
jmp encod1 ; Yes, so loop around for some more.
encd7x: dec rptct ; Add another entry of this char.
jmp encod1 ; With quoting and all.
encod8: sub di,offset filbuf
or di,di
je encod9 ; Nope.
mov ax,di
jmp rskp
encod9: mov ax,0FFFFH ; Get a minus one.
ret
inbuf: mov ah,flags.eoflag ; Have we reached the end?
cmp ah,0
jz inbuf0
ret ; Return if set.
inbuf0: push si
push di
push dx
push bx
push cx
mov bx,offset buff ; Set the r/w buffer pointer.
mov bufpnt,bx
mov ah,readf ; Read a record.
mov dx,offset fcb
int dos
mov cx,filsiz
cmp cx,0 ; Check for 128 chars or less left.
jne inbuf1 ; Still have data left.
mov ax,ds
mov es,ax
mov si,offset filsiz+2
mov di,offset bufhex
cmps filsiz+2,es:bufhex
ja inbuf1 ; More than 128 chars.
mov flags.eoflag,0FFH ; Set End-of-file.
mov cx,filsiz+2
cmp flags.filflg,0 ; Ever used DMA? [25]
jnz inbf01
dec cx ; Account for DEC in caller routine.
inbf01: mov chrcnt,cx ; Return proper number of chars.
mov flags.filflg,0 ; Buffer not empty.
pop cx
pop bx
pop dx
pop di
pop si
jmp rskp
inbuf1: sub filsiz+2,80H ; Sent another 128 chars.
sbb filsiz,0 ; Account for the doubleword.
add tfilsz+2,80H ; Book keeping for the same.
adc tfilsz,0
push ax
call kbpr ; Print the kilobytes sent.
call perpr ; Print the percent sent.
pop ax
mov al,80H ; Use as counter for number of chars read.
pop cx
pop bx
pop dx
pop di
pop si
cmp flags.filflg,0 ; Ever used DMA?
jnz inbf21 ; Nope, then don't change count.
dec al ; Fix boundary error.
inbf21: mov ah,0 ; Zero the flag (buffer not empty).
mov chrcnt,ax ; Number of chars read from file.
mov flags.filflg,0 ; Buffer not empty.
jmp rskp
nulref: mov chrcnt,0 ; No data to return.
jmp rskp
nulr: ret
; Print the number of Kilobytes transferred.
kbpr: cmp flags.remflg,0 ; remote mode?
jne kbpr1 ; yes, no printing.
mov ax,tfilsz+2
mov bx,tfilsz
mov cl,10
shr ax,cl ; divide by 1024
mov cl,6 ; high order moves 16-10 = 6 bits
shl bx,cl
or ax,bx
cmp ax,oldkbt ; is it the same?
je kbpr1 ; yes, skip printing
mov oldkbt,ax ; save new # of kb
push ax
call kbpos ; Postion the cursor.
pop ax
call nout ; Print the number of KBytes transferred.
kbpr1: ret
; Print the percent transferred.
perpr: cmp flags.remflg,0 ; remote mode?
jne perpr5 ; yes, no printing.
mov ax,tfilsz
or ax,tfilsz+2
cmp ax,oldper ; same as it was before?
je perpr5 ; yes, don't bother printing.
mov oldper,ax ; remember this for next time
cmp ofilsz,0 ; No divide by zeroes.
je perpr5 ; If not proceed.
cmp wrpmsg,0 ; did we write the percentage message?
jne perpr1 ; yes, skip this part
call perpos ; position cursor
mov dx,offset permsg
mov ah,prstr
int dos ; write out message
mov wrpmsg,1 ; init flag so we don't do it again
perpr1: call perpos ; Position the cursor.
perpr2: mov dx,tfilsz ; Get the high order word.
mov ax,tfilsz+2 ; Get the low order word.
div ofilsz ; Div by percent adjusted original file size.
cmp ax,100 ; > 100% ?
jle perpr3 ; no, accept it
mov ax,100 ; else just use 100
perpr3: call nout
mov dl,'%' ; Load a percent sign.
perpr4: mov ah,conout ; Print the character.
int dos
perpr5: ret
getfil: mov ah,0FFH
mov flags.filflg,ah ; Nothing in the DMA.
mov ax,0
mov flags.eoflag,ah ; Not the end of file.
mov bx,offset fcb+0CH
mov [bx],ax ; Zero the current block number.
mov bx,offset fcb+0EH
mov [bx],ax ; Ditto for Lrecl.
mov bx,offset fcb+20H
mov [bx],ah ; Zero the current record (of block).
inc bx
mov [bx],ax ; Same for record (of file).
mov bx,offset fcb+23H
mov [bx],ax
mov ah,openf ; Open the file.
mov dx,offset fcb
int dos
mov dx,word ptr fcb+18 ; get file size (hi order word)
mov filsiz,dx
mov ax,word ptr fcb+16 ; lo order word
mov filsiz+2,ax
div percnt ; Divide by 100.
mov ofilsz,ax
mov tfilsz,0 ; Set bytes sent to zero.
mov tfilsz+2,0
mov oldkbt,-1
mov oldper,-1
cmp filsiz,0 ; Null file?
jne getfl0 ; Nope.
cmp filsiz+2,0 ; Null file?
jne getfl0 ; Nope.
mov flags.eoflag,0FFH ; Set EOF.
getfl0: jmp rskp
gtnfil: cmp flags.cxzflg,'Z' ; Did we have a ^Z? [20b]
je gtn5 ; If yes, we're done sending files. [20b]
cmp flags.wldflg,0 ; Was there a "*"? [7 start]
je gtn5 ; Nope.
mov bx,offset cpfcb ; Get FCB from last check for file.
mov di,offset fcb ; Copy to FCB.
mov cl,37 ; Size of FCB.
call fcbcpy
gtn2: mov ah,snext
mov dx,offset fcb ; More files?
int dos
cmp al,0FFH
je gtn5
mov bx,offset fcb
mov di,offset cpfcb
mov cl,37
call fcbcpy ; Copy from FCB.
mov di,offset fcb+1 ; Get name of next file to send.
mov bx,offset buff+1
mov cl,11
call fcbcpy
call getfil ; Initialize
jmp r
jmp rskp
gtn5: mov flags.wldflg,0 ; Reset wild card flag.
ret ; [7 end]
; Get the file name (including host to micro translation)
gofil: cmp flags.xflg,1 ; Remote command? [21c]
jne goflx ; No.... [21c]
jmp gofla ; Yes so skip this stuff. [21c]
goflx: cmp flags.nmoflg,1 ; Overriding name from other side? [21a]
jne gofil0 ; No - get the filename. [21a]
jmp gofil7 ; Yes, so ignore packet contents. [21a]
gofil0: mov bx,offset data ; Get the address of the file name. [21a]
mov fdtpnt,bx ; Store the address.
mov bx,offset fcb+1 ; Address of the FCB.
mov fcbptr,bx ; Save it.
mov ax,0
mov temp1,ax ; Initialize the char count.
mov temp2,ax
cmp flags.droflg,1 ; Default drive? [21a]
je gofil1 ; No - don't blank out value in FCB. [21a]
mov si,offset fcb
mov [si],ah ; Set the drive to default to current.
gofil1: mov ch,' ' ; Moved the label. [21a]
mov [bx],ch ; Blank the FCB.
inc bx
inc ah
cmp ah,0BH ; Twelve?
jl gofil1
gofil2: mov bx,fdtpnt ; Get the NAME field.
mov ah,[bx]
inc bx
mov fdtpnt,bx
cmp ah,'.' ; Seperator?
jne gofil3
mov bx,offset fcb+9H
mov fcbptr,bx
mov ax,temp1
mov temp2,ax
mov temp1,9H
jmp gofil6
gofil3: cmp ah,0 ; Trailing null?
jz gofil7 ; Then we're done.
call verlet ; Verify that the char is legal.
mov bx,fcbptr
mov [bx],ah
inc bx
mov fcbptr,bx
mov ax,temp1 ; Get the char count.
inc ax
mov temp1,ax
cmp ax,8H ; Are we finished with this field?
jl gofil2
gofil4: mov temp2,ax
mov bx,fdtpnt
mov ah,[bx]
inc bx
mov fdtpnt,bx
cmp ah,0
jz gofil7
cmp ah,'.' ; Is this the terminator?
jne gofil4 ; Go until we find it.
gofil6: mov bx,fdtpnt ; Get the TYPE field.
mov ah,[bx]
inc bx
mov fdtpnt,bx
cmp ah,0 ; Trailing null?
jz gofil7 ; Then we're done.
call verlet ; Verify that the char is legal.
mov bx,fcbptr
mov [bx],ah
inc bx
mov fcbptr,bx
inc temp1 ; Increment char count.
cmp temp1,0CH ; Are we finished with this field?
jl gofil6
gofil7: cmp flags.remflg,0 ; remote mode?
jne gofil7a ; yes, don't print it.
call prtfn ; Print the file name. [21a]
gofil7a:cmp flags.destflg,0 ; Writing to the printer?
jne gf7y
push es
mov ax,ds
mov es,ax ; Set this up.
mov cx,11
mov si,offset printer
mov di,offset fcb
repne movsb ; Change name in FCB to be printer.
pop es
jmp gofil9
gf7y: mov ah,flags.flwflg ; Is file warning on?
cmp ah,0
jnz gf7x
jmp gofil9 ; If not, just proceed.
gf7x: mov ah,openf ; See if the file exists.
mov dx,offset fcb
int dos
cmp al,0FFH ; Does it exist?
jnz gf8x
jmp gofil9 ; If not create it.
gf8x: cmp flags.remflg,0 ; remote mode?
jne gf8xa ; yes, skip printing
call frpos ; Position cursor.
mov ah,prstr ; Inform the user we are renaming the file.
mov dx,offset infms5
int dos
gf8xa: mov ax,temp2 ; Get the number of chars in the file name.
cmp ax,0
jne gofil8
mov ax,temp1
mov temp2,ax
gofil8: mov ch,0
mov cl,al
mov al,0 ; Says if first field is full.
cmp cl,9H ; Is the first field full?
jne gofl81
mov al,0FFH ; Set a flag saying so.
dec cl
gofl81: mov bx,offset fcb ; Get the FCB.
add bx,cx ; Add in the character number.
mov ah,'&'
mov [bx],ah ; Replace the char with an ampersand.
push ax
push bx
mov ah,openf ; See if the file exists.
mov dx,offset fcb
int dos
pop bx
cmp al,0FFH ; Does it exist?
pop ax
jz gofl89 ; If not create it.
cmp al,0 ; Get the flag.
jz gofl83
dec cl ; Decrement the number of chars.
cmp cl,0
jz gofl88 ; If no more, die.
jmp gofl81
gofl83: inc cl ; Increment the number of chars.
cmp cl,9H ; Are we to the end?
jl gofl81 ; If not try again ; else fail.
gofl88: cmp flags.remflg,0 ; remote mode?
jne gofl88a ; yes, no printing
call erpos ; Position cursor.
mov ah,prstr ; Tell the user that we can't rename it.
mov dx,offset ermes4
int dos
gofl88a:mov bx,dx ; Tell host can't rename. [20f]
call errpack ; Send error packet before abort. [20f]
ret
gofl89: cmp flags.remflg,0 ; remote mode
jne gofil9 ; yes, don't have to print it
mov bx,offset fcb+0CH ; Point past the end of the file name.
mov dh,[bx] ; Save the present contents.
mov ah,'$'
mov [bx],ah ; Put in a dollar sign.
push dx
mov ah,prstr ; Print the file name.
mov dx,offset fcb+1
int dos
pop dx
mov bx,offset fcb+0CH ; Restore over the dollar sign.
mov [bx],dh
gofil9: mov ah,delf ; Delete the file if it exists.
mov dx,offset fcb
int dos
mov ax,0
mov si,offset fcb+0CH
mov [si],ax ; Zero current block.
mov si,offset fcb+0EH
mov [si],ax ; Same for Lrecl.
mov si,offset fcb+20H
mov [si],ah ; Zero the current record (within block).
inc si
mov [si],ax ; Zero record (within file).
mov si,offset fcb+23H
mov [si],ax
mov ofilsz,0 ; File size unknown.
mov tfilsz,0 ; Set bytes received to zero.
mov tfilsz+2,0
mov oldkbt,-1
mov oldper,-1
mov ah,makef ; Now create it.
mov dx,offset fcb
int dos
cmp al,0FFH ; Is the disk full?
je gf9x
jmp rskp
gf9x: cmp flags.remflg,0 ; remote mode?
jne gf9xa ; yes, don't try printing
call erpos ; Position cursor.
mov ah,prstr ; If so tell the user.
mov dx,offset erms12
int dos
mov bx,dx
gf9xa: call errpack ; Send an error packet.
ret
gofla: cmp pack.argbk1,0 ; Any data in "X" packet? [21c start]
je gofla1 ; Nothing to print.
mov ah,prstr
mov dx,offset crlf
int dos
mov di,offset data ; Where data is.
mov cx,pack.argbk1 ; How much data we have.
call prtscr ; Print it on the screen.
gofla1: mov ah,prstr
mov dx,offset crlf
int dos
jmp rskp ; And done. [21c end]
FILEIO ENDP
; Passed char of incoming filename in AH. Verify that it is legal
; and if not change it to an "X".
verlet: cmp ah,'0'
jl ver2 ; See if it's a legal weird char.
cmp ah,'z'+1
jns ver2
cmp ah,'9'
jle ver1 ; It's between 0-9 so it's OK.
cmp ah,'A'
jl ver2 ; Coud be a weird char.
cmp ah,'Z'
jle ver1 ; It's A-Z so it's OK.
cmp ah,'a'
jl ver2
and ah,137O ; It's a-z, capitalize.
ver1: ret
ver2: push es
mov cx,ds
mov es,cx ; Scan uses ES register.
mov di,offset spchar ; Special chars.
mov cx,spclen ; How many of them.
cmp dosnum,0 ; Under version 2.0
je ver3
mov di,offset spchar2
mov cx,spc2len
ver3: mov al,ah ; Char is in al.
repnz scasb ; Search string for input char.
pop es
mov ah,al ; Return it in AH.
cmp cx,0 ; Was it there?
jnz ver1 ; Yes, return it.
mov ah,'X' ; If illegal, replace with "X".
mov flags.nmoflg,1
ret
; Print incoming filename(s). [21a]
PRTFN PROC NEAR
call clrfln ; Position cursor & blank out the line.
mov di,offset data ; Where to put the name.
mov bx,offset fcb ; Where it is now.
cmp flags.droflg,0 ; Drive specified?
je prtfn1
mov dl,[bx] ; Which one did they say?
add dl,'@' ; Make it readable.
mov ah,dconio ; Print the drive name.
int dos
mov dl,':'
int dos
prtfn1: inc bx ; Point to start of filename.
cmp flags.nmoflg,0 ; Is filename in packet?
je prtfn2 ; no, keep going
add di,pack.argbk1 ; bump by length of remote name
mov si,offset asmsg ; something to put after it
mov cx,asmln ; length of it
rep movsb ; add this to the buffer
prtfn2: mov cx,8 ; At most 8 letters in file name.
mov si,bx ; this is source now
prtfn3: lodsb ; get a letter
cmp al,' ' ; Done with name?
je prtfn4 ; yes, continue
stosb ; else store
loop prtfn3 ; and loop thru rest
prtfn4: mov si,offset fcb+9 ; Point to file type.
cmp byte ptr [si],' ' ; is there a type?
je prtfn5 ; Nope so we're done.
mov al,'.' ; Add the dot.
stosb
mov cx,3 ; At most 3 letters in file type.
rep movsb ; copy type (incl trailing spaces)
prtfn5: mov byte ptr [di],'$' ; end the string
mov ah,prstr ; Print the file name.
mov dx,offset data
int dos
mov flags.droflg,0 ; Reset flag once have the full name.
mov flags.nmoflg,0
ret
PRTFN ENDP
; Print data onto the screen. If text has no "$" in it, just print
; it. Else, do special output for the "$".
; Routine expects: DI = Start of buffer we are to print.
; CX = Number of characters to print. [21c]
PRTSCR PROC NEAR
mov al,'$' ; This is what we're looking for.
mov oloc,di ; Remember original buffer address.
mov osiz,cx ; And original size.
push es
mov bx,ds
mov es,bx ; Have ES point to data area.
prts0: repnz scasb ; Search for "$" in the buffer.
cmp cx,0 ; Found one?
je prts1 ; No, do a regular DOS call.
mov ah,prstr
mov dx,oloc ; Print up to the "$".
int dos
mov ah,dconio
mov dl,'$'
int dos ; Print the "$"
mov oloc,di ; New starting location.
mov osiz,cx ; New size.
jmp prts0
prts1: mov bx,oloc ; The buffer location.
add bx,osiz ; Point past the data.
mov [bx],al ; Add "$" for printing.
mov ah,prstr
mov dx,oloc
int dos
pop es
ret
PRTSCR ENDP
FIXFCB PROC NEAR
push ax ; Don't forget this. [22]
mov bx,offset fcb+18
mov di,offset filsiz
mov ax,[bx]
mov [di],ax
mov bx,offset fcb+16
mov ax,[bx]
mov 2[di],ax
pop ax ; Get number of chars in last buffer full. [22]
sub filsiz+2,ax ; Get real file size.
sbb filsiz,0
mov bx,offset fcb+18
mov di,offset filsiz
mov ax,[di]
mov [bx],ax
mov bx,offset fcb+16
mov ax,2[di]
mov [bx],ax
ret
FIXFCB ENDP
; 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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msfile.asm
/bin/echo -n ' '; /bin/ls -ld msfile.asm
fiknutson@ut-ngp.UUCP (Jim Knutson) (10/05/84)
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting mskerm.asm'
sed 's/^X//' <<'//go.sysin dd *' >mskerm.asm
public prompt, dosnum, curdsk, swchar
include msdefs.h
;******************** Version 2.26 **********************************
; KERMIT, Celtic for "free"
;
; The name "Kermit" is a registered trade mark of Henson Associates, Inc.,
; used by permission.
;
; Kermit-MS Program Version 2.26, July 26, 1984
;
; Based on the Columbia University KERMIT Protocol.
;
; Copyright (C) 1982,1983,1984 Trustees of Columbia University
;
; Daphne Tzoar, Jeff Damens
; Columbia University Center for Computing Activities
; 612 West 115th Street
; New York, NY 10025
;
; Special thanks to Frank da Cruz, Bill Catchings, Steve Jensen, Herm Fischer,
; Vace Kundakci, and Bernie Eiben for their help and contributions.
makseg equ 26H
deffcb equ 5cH
setblk equ 4AH
exec equ 4BH
env equ 2CH ; environment address in psp
terma equ 10 ; termination address in psp
cline equ 80H ; offset in psp of command line
namsiz equ 20 ; Bytes for file name and size.
maxnam equ 10
chmod equ 43H ; chmod call (used to test for file existence)
STACK SEGMENT PARA STACK 'STACK'
DW 100 DUP(0) ; Initialize stack to all zeros.
STK EQU THIS WORD
STACK ENDS
datas segment public 'datas'
extrn buff:byte, comand:byte, flags:byte, pack:byte, trans:byte
extrn fcb:byte, cpfcb:byte, prmptr:word, inichk:byte
extrn machnam:byte
public takadr,taklev
versio label byte
verdef
db cr,lf
db 'Type ? for help',cr,lf
db '$'
tmp db ?,'$'
crlf db cr,lf,'$'
ermes1 db cr,lf,'?Unrecognized command$'
ermes3 db cr,lf,'?Not confirmed$'
erms30 db cr,lf,'Passed maximum nesting level for TAKE command$'
erms31 db cr,lf,'Take file not found$'
erms32 db cr,lf,'File(s) not found$'
erms33 db cr,lf,'CHKDSK program not found on current disk$'
erms34 db cr,lf,'This command works only for DOS 2.0 and above$'
erms35 db cr,lf,'Must specify program name$'
erms36 db cr,lf,'Could not free memory$'
erms37 db cr,lf,'Unable to execute program$'
infms1 db 'Really erase *.*? $'
infms8 db cr,lf,'File(s) erased$'
tmsg5 db cr,lf,'[closing log file]',cr,lf,'$' ; [jd]
filhlp1 db ' Command file specification $'
filhlp2 db ' File specification (possibly wild) $'
filhlp3 db ' File spec (possibly wild) or confirm with carriage return$'
filmsg db ' File specification with optional path name $'
filwmsg db ' File specification (possibly wild) with optional path name $'
chkfil db 0,'CHKDSK COM'
chkflen equ $-chkfil
tophlp db cr,lf
db 'BYE',tab,tab
db 'CLOSE',tab,tab
db 'CONNECT',tab,tab
db 'DEFINE',tab,tab
db cr,lf
db 'DELETE',tab,tab
db 'DIRECTORY',tab
db 'DO',tab,tab
db 'EXIT',tab,tab
db cr,lf
db 'FINISH',tab,tab
db 'GET',tab,tab
db 'HELP',tab,tab
db 'LOCAL',tab,tab
db cr,lf
db 'LOG',tab,tab
db 'LOGOUT',tab,tab
db 'PUSH',tab,tab
db 'QUIT',tab,tab
db cr,lf
db 'RECEIVE',tab,tab
db 'REMOTE',tab,tab
db 'RUN',tab,tab
db 'SEND',tab,tab
db cr,lf
db 'SERVER',tab,tab
db 'SET',tab,tab
db 'SHOW',tab,tab
db 'SPACE',tab,tab
db cr,lf
db 'STATUS',tab,tab
db 'TAKE'
db '$'
lochlp db cr,lf,'DELETE file'
db cr,lf,'DIRECTORY [filespec]'
db cr,lf,'SPACE remaining on current disk'
db cr,lf,'RUN program'
db cr,lf,'PUSH to command interpreter'
db '$'
; COMND tables
yestab db 2
mkeyw 'NO',0
mkeyw 'YES',1
comtab db 27
mkeyw 'BYE',bye
mkeyw 'C',telnet
mkeyw 'CLOSE',clscpt
mkeyw 'CONNECT',telnet
mkeyw 'DEFINE',dodef
mkeyw 'DELETE',delete
mkeyw 'DIRECTORY',direct
mkeyw 'DO',docom
mkeyw 'EXIT',exit
mkeyw 'FINISH',finish
mkeyw 'GET',get
mkeyw 'HELP',help
mkeyw 'LOCAL',lclcmd
mkeyw 'LOG',setcpt
mkeyw 'LOGOUT',logout
mkeyw 'PUSH',dopush
mkeyw 'QUIT',exit
mkeyw 'RECEIVE',read
mkeyw 'REMOTE',remote
mkeyw 'RUN',run
mkeyw 'SEND',send
mkeyw 'SERVER',server
mkeyw 'SET',setcom
mkeyw 'SHOW',showcmd
mkeyw 'SPACE',chkdsk
mkeyw 'STATUS',status
mkeyw 'TAKE',take
loctab db 5
mkeyw 'DELETE',delete
mkeyw 'DIRECTORY',direct
mkeyw 'PUSH',dopush
mkeyw 'RUN',run
mkeyw 'SPACE',chkdsk
shotab db 2
mkeyw 'KEY',shokey
mkeyw 'MACRO',shomac
; Program storage.
oldstk dw ? ; Storage for system stack.
oldsts dw ? ; System stack segment.
ssave dw ? ; Original SS when doing CHKDSK.
siz dw ? ; Memory size.
in3ad dd 0 ; Original break interrupt addresses. [25]
curdsk db 0 ; Current disk.
origd db 0 ; Original disk.
fildat db 0 ; Manipulate file data/time creation.
db 0
taklev db 0 ; Take levels. [25t]
takadr dw takstr-(size takinfo) ; Pointer into structure. [25t]
temp dw 0
temp1 dw ? ; Temporary storage.
temp2 dw ?
temp3 dw ?
temp4 dw ?
psp dw ?
divst dw 0
takstr db (size takinfo) * maxtak dup(?)
ininam db 0,'MSKERMITINI' ; init file name, on default disk, 12 chars
ininm2 db 'MSKERMIT.INI',0 ; init file name for 2.0
nambuf db maxnam * namsiz dup (?)
cmdnam db namsiz dup (?)
exefcb db fcbsiz dup (?)
exefcb2 db fcbsiz dup (?)
exearg dw ? ; segment addr of environment (filled in below)
dd 0 ; ptr to cmd line (filled in below)
dd exefcb ; default fcb
dd exefcb2 ; second default fcb
dircmd db ' /c dir '
dirclen equ $-dircmd
dirnam db 50h dup (?)
chkdcmd db 'chkdsk.com'
chkdlen equ $-chkdcmd
dosnum db ? ; dos version number
pthnam db 'PATH='
pthlen equ $-pthnam
pthbuf db 100 dup (?) ; buffer for path definition.
defpth db '\', 70 dup (?) ; buffer for default path
cmspnam db 'COMSPEC='
cmsplen equ $-cmspnam
cmspbuf db '\command.com',0 ; default name
db 30 dup (?) ; some additional space
tfile db 100 dup (?) ; temp space for file names.
eexit db cr,'exit',cr
leexit equ $-eexit
swchar db '\' ; default switch character.
datas ends ; End data segment
code segment public
public takrd
start proc far
extrn cmblnk:near, locate:near, logout:near
extrn bye:near, telnet:near, finish:near, comnd:near
extrn read:near, remote:near, send:near, status:near, get:near
extrn dodisk:near, serrst:near, setcom:near
extrn clscpi:near, clscpt:near, getbaud:near
extrn dodef:near, setcpt:near, docom:near
extrn server:near, lclini:near, shokey:near, shomac:near
assume cs:code,ds:datas,ss:stack,es:nothing
push ds ; Save system data area.
sub ax,ax ; Get a zero.
push ax ; Put zero return addr on stack.
mov ax,datas ; Initialize DS.
mov ds,ax
sub ax,ax
mov oldstk,sp ; Save old stack pointer.
mov ax,es:[2] ; In program segment prefix
mov siz,ax ; Pick up memory size
mov psp,es
mov ah,prstr
mov dx,offset machnam ; print machine name
int dos
mov ah,prstr ; Print the version header.
mov dx,offset versio
int dos
mov ah,setdma ; Set disk transfer address.
mov dx,offset buff
int dos
call getbaud ; Get the baud rate. [25]
call dodisk ; See how many disk drives we have. [21a]
call setint
mov ah,gcurdsk ; Get current disk.
int dos
inc al ; We want 1 == A (not zero).
mov curdsk,al
mov origd,al ; Remember original disk we started on.
mov ah,dosver
int dos
mov dosnum,al ; remember dos version
cmp al,0
je start1 ; 1.1, keep going
mov es,psp
mov ax,es:[env] ; pick up environment address
push ax
call getpath ; get the path from the environment
pop ax ; get environment back
call getcsp ; get comspec from environment as well
start1: call lclini ; do local initialization
call gcmdlin ; read command line
call rdinit ; read kermit init file
call packlen ; Packet length in case do server comand.
; This is the main KERMIT loop. It prompts for and gets the users commands.
kermit: mov ax,ds
mov es,ax ; make sure this addresses data segment
mov dx,prmptr ; get prompt
call prompt ; Prompt the user.
mov pack.state,0 ; Clear the state.
mov flags.cxzflg,0 ; Reset each itme.
mov ah,inichk ; Original or set checksum length.
mov trans.chklen,ah ; Reset just in case.
mov dx,offset comtab
mov bx,offset tophlp
mov comand.cmcr,1 ; Allow bare CR's.
mov ah,cmkey
call comnd
jmp kermt2
mov comand.cmcr,0 ; Not anymore.
call bx ; Call the routine returned.
jmp kermt3
cmp flags.extflg,0 ; Check if the exit flag is set.
jne krmend ; If so jump to KRMEND.
jmp kermit ; Do it again.
kermt2: mov dx,offset ermes1 ; Give an error.
jmp short kermt4
kermt3: mov dx,offset ermes3 ; Give an error.
kermt4: cmp flags.cxzflg,'C' ; some sort of abort?
je kermit ; yes, don't print error message.
mov ah,prstr
int dos
mov flags.droflg,0 ; Reset drive override flag.
mov flags.nmoflg,0 ; Reset filename override flag.
mov flags.getflg,0 ; May as well do this one.
mov flags.cmrflg,0 ; This one too.
jmp kermit
krmend: call serrst ; Just in case the port wasn't reset. [21c]
mov dl,origd ; Original disk drive.
dec dl ; Want A == 0.
mov ah,seldsk ; Reset original disk just in case.
int dos
mov sp,oldstk
ret
START ENDP
; This is the 'exit' command. It leaves KERMIT and returns to DOS.
EXIT PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r
test flags.capflg,0FFH ; capturing?
jz exit1 ; no, keep going
mov dx,offset tmsg5
mov ah,prstr
int dos
call clscpi
nop ; this skip returns...
nop
nop
exit1:
mov flags.extflg,1 ; Set the exit flag.
jmp rskp ; Then return to system.
EXIT ENDP
; This is the 'help' command. It gives a list of the commands.
HELP PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r
mov ah,prstr ; Print a string to the console.
mov dx,offset tophlp ; The address of the help message.
int dos
jmp rskp
HELP ENDP
lclcmd proc near
mov ah,cmkey
mov dx,offset loctab
mov bx,offset lochlp
call comnd
jmp r
call bx
nop
nop
nop
jmp rskp
lclcmd endp
; Don't ignore ^C when in debug mode.
SETINT PROC NEAR
push ds ; Don't forget this. [25]
mov ax,ds
mov es,ax ; So can access our data area.
mov ax,0
mov ds,ax ; Access low core.
mov ax,ds:[23H * 4] ; Address for interrupt 23H.
mov cx,ds:[23H * 4 +2] ; CS value for it.
mov word ptr es:in3ad,ax ; Remember original values.
mov word ptr es:in3ad+2,cx
mov ax,cs
mov ds,ax ; Access code are.
mov dx,offset intbrk
mov al,23H ; On ^C, goto above address.
mov ah,25H
int dos
pop ds
ret
SETINT ENDP
; take commands from a file, but allow a path name
PTAKE PROC NEAR
cmp taklev,maxtak ; Hit our limit?
jl ptake1 ; Continue if still OK.
mov ah,prstr
mov dx,offset erms30 ; Complain.
int dos
ret
ptake1: mov di,takadr
add di,size takinfo
push di
mov ah,cmtxt
lea bx,[di].takbuf ; convenient place to parse name into
mov dx,offset filmsg ; Help in case user types "?".
call comnd
pop di
ret
nop
pop di ; restore frame address
push di ; keep it on stack.
lea si,[di].takbuf ; get buffer back
mov bl,ah ; length of thing parsed
mov bh,0
mov byte ptr [bx+si],0 ; make it asciz
mov ax,si ; point to name again
call spath ; is it around?
pop di ; need this back
jc ptake2 ; no, go complain
mov dx,ax ; point to name from spath
mov ah,open2 ; 2.0 open call
mov al,0 ; open for reading
int dos
jnc ptake3 ; open ok, keep going
ptake2: mov ah,prstr
mov dx,offset erms31
int dos
ret
ptake3: inc taklev
mov takadr,di
mov word ptr [di].takfcb+1,ax ; save file descriptor
mov byte ptr [di].takfcb,0feh ; mark as 2.0 file descriptor
mov bx,ax ; need descriptor here
mov ah,lseek
mov al,2
mov cx,0
mov dx,cx ; seek 0 bytes from end
int dos
mov [di].takcnt,ax
mov [di].takcnt+2,dx ; store length
mov ah,lseek
mov al,0
mov cx,0
mov dx,cx ; now seek back to beginning
int dos
cmp flags.takflg,0
je ptake4
mov ah,prstr
mov dx,offset crlf
int dos
ptake4: call takrd ; Get a buffer full of data.
jmp rskp
PTAKE ENDP
; TAKE commands from a file. [25t]
TAKE PROC NEAR
cmp dosnum,0
je take1
jmp ptake ; use this for 2.0
take1: cmp taklev,maxtak ; Hit our limit?
jl take2 ; Continue if still OK.
mov ah,prstr
mov dx,offset erms30 ; Complain.
int dos
ret
take2: mov bx,takadr
add bx,size takinfo
push bx
lea dx,[bx].takfcb
mov comand.cmcr,0 ; Filename must be specified.
mov ah,cmifi
mov bx,offset filhlp1
call comnd
pop bx
ret ; Make sure this is three bytes long.
nop
pop bx
mov byte ptr [bx].takfcb+32,0 ; have to clear current record in fcb
mov ah,openf
lea dx,[bx].takfcb
int dos
cmp al,0FFH ; File not found?
jne take3
mov ah,prstr
mov dx,offset erms31
int dos
take3: inc taklev
mov takadr,bx
mov ax,word ptr [bx+16].takfcb
mov [bx].takcnt,ax
mov ax,word ptr [bx+18].takfcb
mov [bx].takcnt+2,ax ; copy size into takinfo
cmp flags.takflg,0
je take4
mov ah,prstr
mov dx,offset crlf
int dos
take4: call takrd ; Get a buffer full of data.
jmp rskp
TAKE ENDP
TAKRD PROC NEAR
push bx
push cx
push dx
mov bx,takadr
cmp byte ptr [bx].takfcb,0feh ; is it a 2.0 file handle?
jne takrd1 ; no, handle differently
push bx ; save frame address
lea dx,[bx].takbuf ; buffer to read into
mov cx,dmasiz ; # of bytes to read
mov ah,readf2 ; 2.0 read call
mov bx,word ptr [bx].takfcb+1 ; file handle is stored here
int dos
pop bx ; restore frame address
jmp takrd2 ; rejoin common exit
takrd1: mov ah,setdma
lea dx,[bx].takbuf
int dos
mov ah,readf
lea dx,[bx].takfcb
int dos
mov ah,setdma
lea dx,buff
int dos
takrd2: mov [bx].takchl,dmasiz
lea ax,[bx].takbuf
mov [bx].takptr,ax
pop dx
pop cx
pop bx
ret
TAKRD ENDP
; copy the path into pthbuf
; enter with ax/ environment segment address
; works in 2.0 only.
getpath proc near
push es
mov bx,ds
mov es,bx ; address data segment
mov bx,offset pthnam ; thing to find
mov cx,pthlen ; length of it
mov dx,offset pthbuf ; place to put it
mov byte ptr pthbuf,0 ; initialize to null...
call getenv ; get environment value
pop es
ret ; and return
getpath endp
; copy the comspec into cmspbuf
; enter with ax/ environment segment address
; works in 2.0 only.
getcsp proc near
push es
mov bx,ds
mov es,bx ; address data segment
mov bx,offset cmspnam ; thing to find
mov cx,cmsplen ; length of it
mov dx,offset cmspbuf ; place to put it
call getenv ; get environment value
pop es
ret ; and return
getcsp endp
; find a path variable. Enter with ax/ environment segment,
; bx/ variable to find (incl =), cx/ length of variable name,
; dx/ address to store value at.
; The buffer given in dx is unchanged if the variable isn't found
getenv proc near
push ds
push es
mov es,ax ; address segment
mov di,0 ; offset in segment
geten1: cmp es:byte ptr [di],0 ; end?
je geten4 ; yes, forget it
push cx ; save counter
push di ; and offset
mov si,bx
repe cmpsb ; is it the one?
pop di
pop cx ; restore these
je geten2 ; found it, break loop
push cx ; preserve again
mov cx,0ffffh ; bogus length
mov al,0 ; marker to look for
repne scasb ; search for it
pop cx ; restore length
jmp geten1 ; loop thru rest of environment
geten2: add di,cx ; skip to definition
mov si,di ; this is source
mov di,dx ; destination as given
mov ax,ds
mov bx,es
mov ds,bx
mov es,ax ; exchange segment regs for copy
geten3: lodsb ; get a byte
stosb ; drop it off
cmp al,0 ; end of string
jne geten3 ; no, go on
geten4: pop es
pop ds ; restore registers
ret ; and return
getenv endp
; put kermit.ini onto take stack if it exists. Just like
; the take command, except it doesn't read a filename.
rdinit proc near ; read kermit init file...
mov al,dosnum ; get dos version
or al,al
jne rdini4 ; post 2.0, use file handle instead...
mov bx,takadr
add bx,size takinfo ; bump take ptr, point to current take frame
lea di,[bx].takfcb ; destination is fcb
mov ax,ds
mov es,ax ; destination segment = source segment
mov si,offset ininam ; name of init file
mov cx,12 ; 8 char name + 3 char ext + 1 char drive...
rep movsb ; copy it in
mov byte ptr [bx].takfcb+32,0 ; have to clear current record in fcb
mov ah,openf
lea dx,[bx].takfcb
int dos
cmp al,0FFH ; File not found?
jne rdini1 ; no, keep going
ret ; else just return, no init file
rdini1: inc taklev ; bump take level
mov takadr,bx ; save current take frame ptr
mov ax,word ptr [bx+16].takfcb
mov [bx].takcnt,ax
mov ax,word ptr [bx+18].takfcb
mov [bx].takcnt+2,ax ; copy size into takinfo
rdini2: cmp flags.takflg,0
je rdini3
mov ah,prstr
mov dx,offset crlf
int dos
rdini3: call takrd ; Get a buffer full of data.
ret
rdini4: mov ax,offset ininm2 ; name to try
push bx
call spath ; can we find it?
pop di
jc rdini6 ; no, forget it, go use it
mov dx,ax ; point to name
mov ah,open2 ; 2.0 open function
mov al,0 ; for reading...
int dos
jc rdini6 ; can't open, forget it
rdini5: inc taklev ; bump take level
add takadr,size takinfo
mov di,takadr ; get current frame ptr
mov word ptr [di].takfcb+1,ax ; save file handle
mov byte ptr [di].takfcb,0feh ; mark as a handle
mov bx,ax ; move file ptr
mov ah,lseek
mov al,2
mov cx,0
mov dx,0 ; seek to end of file
int dos
mov [di].takcnt,ax ; copy file size
mov [di].takcnt+2,dx ; into structure
mov al,0
mov ah,lseek
mov cx,0
mov dx,0
int dos ; seek back to beginning
jmp rdini2 ; go rejoin common exit
rdini6: ret ; no init file, just return
rdinit endp
; get command line into a macro buffer.
gcmdlin proc near
push ds
push es
cld
mov es,psp ; address psp
mov ch,0
mov cl,es:[cline] ; length of cmd line
mov di,cline+1 ; point to actual line
mov al,' '
jcxz gcmdl3 ; no command line, forget it.
repe scasb ; skip over spaces
je gcmdl3 ; all spaces, forget it
mov si,di ; this is first non-space
dec si ; pre-incremented...
inc cx
inc taklev ; bump take level
add takadr,size takinfo ; address new take frame
mov bx,takadr
mov byte ptr [bx].takfcb,0ffh ; mark as a macro
push cx ; save length
push ds ; and segment
lea di,[bx].takbuf ; into take buffer
mov ax,ds
mov ds,psp
mov es,ax ; switch segments for copy
gcmdl1: lodsb ; get a byte
cmp al,',' ; comma?
jne gcmdl2 ; no, keep going
mov al,cr ; convert to cr
gcmdl2: stosb ; deposit it
loop gcmdl1 ; copy whole cmd
pop ds ; restore segment
mov si,offset eexit ; something to tack onto end
mov cx,leexit ; length of it
rep movsb ; copy it in
pop cx ; restore len
add cx,leexit ; count wnat we added
lea ax,[bx].takbuf
mov [bx].takptr,ax ; init buffer ptr
mov [bx].takchl,cl ; chars remaining
mov [bx].takcnt,cx ; and all chars
mov [bx].takcnt+2,0 ; clear high order
gcmdl3: pop es
pop ds
ret
gcmdlin endp
; This routine prints the prompt and specifies the reparse address.
PROMPT PROC NEAR
mov comand.cmprmp,dx ; save the prompt
pop bx ; Get the return address.
mov comand.cmrprs,bx ; Save as addr to go to on reparse.
mov comand.cmostp,sp ; Save for later restoral.
push bx ; Put it on the stack again.
mov bx,offset comand.cmdbuf
mov comand.cmcptr,bx ; Initialize the command pointer.
mov comand.cmdptr,bx
mov ah,0
mov comand.cmaflg,ah ; Zero the flags.
mov comand.cmccnt,ah
mov comand.cmsflg,0FFH
cmp flags.takflg,0 ; look at take flag
jne promp1 ; supposed to echo, skip this check...
cmp taklev,0 ; inside a take file?
je promp1 ; no, keep going
ret ; yes, return
promp1: mov ah,prstr
mov dx,offset crlf
int dos
mov ah,prstr ; Print the prompt.
mov dx,comand.cmprmp
int dos
ret
PROMPT ENDP
; Erase specified file(s).
DELETE PROC NEAR
mov comand.cmcr,0 ; Filename must be specified.
mov ah,cmifi ; Parse an input filespec.
mov dx,offset fcb
mov bx,offset filhlp2 ; Text of help message.
call comnd
jmp r ; Bad filename.
mov ah,cmcfm ; Parse a confirm.
call comnd
jmp r
cld
mov di,offset fcb+1
mov al,'?'
mov cx,11 ; # of chars in a name
repe scasb ; are they all ?'s?
jne del1 ; no, skip message
mov dx,offset infms1
call prompt
mov ah,cmkey
mov dx,offset yestab
mov bx,0
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd
pop bx
ret
nop
pop bx
cmp bx,0
jne del1
jmp rskp
del1: mov dx,offset fcb
mov ah,sfirst ; See if any files match this specification.
int dos
cmp al,0FFH ; No matches?
jne del2
mov ah,prstr
mov dx,offset erms32
int dos
jmp rskp
del2: mov dx,offset fcb
mov ah,delf ; Erase the file(s).
int dos
mov dx,offset infms8
mov ah,prstr ; Say we did so.
int dos
jmp rskp
DELETE ENDP
CHKDSK PROC NEAR
mov ah,cmcfm
call comnd
jmp r
cmp dosnum,0
je chkds1 ; yes, have to do it the hard way
mov si,offset chkdcmd ; point to cmd
mov cx,chkdlen ; and length
jmp crun ; and go execute it nicely
chkds1: push es
mov ax,ds
mov es,ax
mov di,offset fcb
mov si,offset chkfil
mov cx,chkflen
rep movsb
mov dx,offset stk + 15 ; End of stack plus roundoff.
mov cl,4
shr dx,cl ; Divide to get segment.
add dx,seg stack ; Get past the stack.
mov es,dx ; remember where segment is.
mov ah,makseg ; Create new PSP.
int dos
mov ax,siz ; Update machine size.
mov es:2,ax
mov es: byte ptr [deffcb],0 ; Blank default fcb.
mov di,deffcb+1
mov al,' ' ; Blank out fcb.
mov cx,fcbsiz
rep stosb
mov word ptr es:[terma],offset term ; Termination address.
mov es:[terma+2],cs
mov ah,openf
mov dx,offset fcb
int dos
inc al
jnz chkok
mov dx,offset erms33
mov ah,prstr
int dos
jmp chkend
chkok: mov byte ptr fcb+32,0 ; set current record field
mov di,100h ; offset to copy into
lp: mov dx,offset fcb
mov ah,readf
int dos
push ax ; save status
mov si,offset buff
mov cx,dmasiz/2 ; Word size of DMA
rep movsw ; copy into new segment...
pop ax
cmp al,1 ; End of file
je dun
cmp al,3 ; Done here too
jne lp
dun: mov ssave,sp ; Save stack pointer.
mov ax,es
mov word ptr cs:[doit+2],ax ; Set segment for CHKDSK.
mov ds,ax
mov ss,ax
mov ax,0
jmp cs: dword ptr [doit] ; Call CHKDSK.
term: mov ax,seg datas ; Reset data area.
mov ds,ax
mov sp,ssave
mov ax,seg stack
mov ss,ax
mov ah,setdma
mov dx,offset buff
int dos ; restore dma address!!
chkend: pop es
jmp rskp
doit dd 100h
CHKDSK ENDP
; Get directory listing.
DIRECT PROC NEAR
mov ah,dosver ; See what level of DOS we're at.
int dos
cmp al,0 ; Level 2.0 or above?
jne dir4 ; Yes - get directory the easy way.
mov comand.cmcr,1 ; Allow plain CR (so DIR == DIR *.*).
mov ah,cmifi ; Get input file spec.
mov dx,offset fcb ; Give the address for the FCB.
mov bx,offset filhlp3
call comnd
jmp r
mov ah,cmcfm ; Parse a confirm.
call comnd
jmp r
mov comand.cmcr,0 ; Reset this.
push es
mov ax,ds
mov es,ax
mov temp1,0FFH
mov di,offset nambuf
dir0: call getfn ; Get a matching file name.
cmp al,0FFH ; Retcode -- are we done?
je dir1 ; Yes, just leave.
call dumpit ; Print it or dump to buffer.
jmp dir0
dir1: pop es
jmp rskp
dir4: mov si,offset cmspbuf ; command processor
mov di,offset dirnam
dir5: lodsb ; get a byte
or al,al
jz dir6 ; stop on the null
stosb ; otherwise copy it in
jmp dir5 ; and keep going
dir6: mov si,offset dircmd ; add directory command to it
mov cx,dirclen
rep movsb
mov ah,cmtxt ; parse with cmtxt so we can have paths...
mov bx,di ; next available byte
mov dx,offset filwmsg ; In case user wants help.
call comnd
jmp r
mov cl,ah
mov ch,0 ; length of name
sub di,offset dirnam ; compute # of bytes used
add cx,di
mov si,offset dirnam ; dir cmd
jmp crun ; join run cmd from there.
DIRECT ENDP
getfn: cmp temp1,0FFH
jne gtfn1
mov ah,sfirst ; Any matches?
mov dx,offset fcb
int dos
cmp al,0FFH ; Means no matches.
je gtfn5
call savfcb
mov temp1,0
jmp gtfn4
gtfn1: cmp flags.wldflg,0FFH ; Wilcard seen?
je gtfn2 ; Yes, get next file.
mov al,0FFH ; No, set retcode.
ret
gtfn2: call rstfcb
mov ah,snext
mov dx,offset fcb
int dos
cmp al,0 ; Any more matches?
je gtfn3 ; Yes keep going.
mov al,0FFH ; OK return code.
ret
gtfn3: call savfcb
gtfn4: push di
mov si,offset buff ; Data is here.
mov di,offset fcb ; Copy to here.
mov cx,37
repne movsb
pop di
call nicnam ; Make name nice for printing.
mov al,0
ret
gtfn5: mov ah,prstr ; Don't print if a server.
mov dx,offset erms32 ; Say no matches.
int dos
mov al,0FFH ; Failure return code.
ret
savfcb: push di
mov si,offset fcb ; Data is here.
mov di,offset cpfcb ; Copy to here.
mov cx,37
repne movsb
pop di
ret
rstfcb: push di
mov si,offset cpfcb ; Data is here.
mov di,offset fcb ; Copy to here.
mov cx,37
repne movsb
pop di
ret
nicnam: mov al,CR ; Add CRLF before print names
stosb
mov al,LF
stosb
mov cx,8
mov si,offset fcb+1
repne movsb ; Get the file name.
mov al,' '
stosb
mov cx,3
repne movsb
mov al,tab
stosb
mov al,' '
stosb
mov ah,openf
mov dx,offset fcb
int dos
mov bx,offset fcb+18 ; Get hi order word of file size.
mov ax,[bx]
mov dx,ax
mov bx,offset fcb+16 ; Get lo order word.
mov ax,[bx]
call nout2x ; Get it in decimal.
mov al,tab
stosb
mov al,' '
stosb
mov ah,0
mov si,offset fcb+20
lodsb
mov fildat+1,al
lodsb
mov fildat,al ; Date field of fcb.
mov cl,5
shr fildat+1,cl
and fildat,1
mov cl,3
shl fildat,cl
mov al,fildat
or al,fildat+1 ; Get the month field.
cmp al,9
jg nic0
push ax
mov al,' '
stosb
pop ax
nic0: call nout2 ; Make it decimal.
mov al,'-'
stosb
mov si,offset fcb+20 ; Get date field.
lodsb
and al,1FH
cmp al,10 ; Only one digit?
jge nic0x
push ax
mov al,'0' ; Make it two digits.
stosb
pop ax
nic0x: call nout2 ; Make it decimal.
mov al,'-'
stosb
mov si,offset fcb+21 ; Get the year field.
lodsb
shr al,1
add al,80
cmp al,100 ; At the year 2000 or above?
js nic0y ; No, just go on.
sub al,100 ; Go back to two digits.
nic0y: cmp al,10 ; Only one digit?
jge nic0z
push ax
mov al,'0' ; Make it two digits.
stosb
pop ax
nic0z: call nout2 ; Make it decimal.
mov al,tab
stosb
mov si,offset fcb+23 ; Get time field of fcb.
lodsb
mov cl,3 ; Get the hour field.
shr al,cl
mov tmp,'a' ; For AM.
cmp al,12 ; Before noon?
jl nic1
mov tmp,'p' ; It's PM.
je nic1 ; Don't change "12" to "0".
sub al,12 ; Use a 12 hr. clock.
nic1: cmp al,0 ; Just after midnight?
jne nic1x
add al,12 ; Make it "12" instead of "0".
nic1x: cmp al,10 ; Pad with a space?
jge nic2
push ax
mov al,' '
stosb
pop ax
nic2: call nout2 ; Make it decimal.
mov al,':' ; Separate hours and minutes.
stosb
mov si,offset fcb+23 ; Get the minutes field.
lodsb
and al,07
mov cl,3
shl al,cl
mov ah,al
mov si,offset fcb+22
lodsb
mov cl,5
shr al,cl
or al,ah
mov ah,0
cmp al,10 ; Would there be a leading zero.
jge nic3
push ax
mov al,'0'
stosb
pop ax
nic3: call nout2 ; Make it decimal.
mov al,tmp ; Add 'a' (AM) or 'p' (PM).
stosb
mov ah,closf
mov dx,offset fcb
int dos
ret
; For now, just print it.
dumpit: mov al,'$'
stosb
mov ah,prstr
mov dx,offset nambuf
int dos
mov di,offset nambuf
ret
; push to an inferior command parser
dopush proc near
cmp dosnum,0 ; < 2.0 ?
jne dopus1 ; no, go on
mov dx,offset erms34
mov ah,prstr
int dos
jmp rskp
dopus1: mov ah,cmcfm
call comnd
jmp r
mov si,offset cmspbuf ; name of parser
push si ; save beginning
sub cx,cx ; initial length
dopus2: lodsb
inc cx ; count this
or al,al ; at end?
jnz dopus2 ; no, keep going
pop si ; restore cmd
dec cx ; this is incremented one over
jmp short crun ; go run it
dopush endp
; crun - run an arbitrary program. Enter with si/address of whole
; cmd, cx/length of cmd.
CRUN proc near
push cx ; save length of cmd
mov ax,ds
mov es,ax ; address dest segment
mov di,offset nambuf
rep movsb ; copy command so we can mess with it
pop cx
mov si,offset nambuf ; point to command
jmp short run3 ; and join run code
CRUN ENDP
RUN PROC NEAR
cmp dosnum,0
jne run1
mov ah,prstr
mov dx,offset erms34 ; Complain.
int dos
jmp rskp
run1: mov ah,cmtxt ; Get program name.
mov bx,offset nambuf ; Convenient buffer.
mov dx,offset filmsg ; In case user wants help.
call comnd
nop
nop
nop
cmp ah,0
jne run2
mov ah,prstr
mov dx,offset erms35
int dos
jmp rskp
run2: mov cl,ah
mov ch,0
mov si,offset nambuf
; alternate entry if cmd is already known. Source cmd ptr in si
; is trashed.
run3: mov bx,cx
mov byte ptr [si+bx],cr ; end string with a cr for dos.
mov di,offset cmdnam
mov ax,ds
mov es,ax
run4: lodsb
cmp al,' '
jne run5
dec si ; back up over space
jmp short run6 ; and exit loop
run5: stosb
loop run4
run6: mov byte ptr [di],0 ; terminate string
dec si ; point back a byte into argument
mov [si],cl ; put length of argument here
mov exearg+2,si ; pointer to argument string
mov exearg+4,ds ; segment of same
inc si ; pass length over
mov al,1 ; scan leading separators
mov di,offset exefcb ; parse into this fcb
mov ah,prsfcb
int dos ; go parse the fcb
mov al,1 ; scan leading separators
mov di,offset exefcb2 ; second fcb to fill
mov ah,prsfcb
int dos ; parse the fcb
mov es,psp ; point to psp again
mov ax,es:[env] ; get environment ptr
mov exearg,ax ; put into argument block
mov bx,offset stk + 15 ; end of pgm
mov cl,4
shr bx,cl ; compute # of paragraphs in last segment
mov ax,seg stack ; end of kermit
sub ax,psp ; minus beginning...
add bx,ax ; # of paragraphs occupied
mov ah,setblk
int dos
jc run7 ; nope...
mov ax,ds
mov es,ax ; put es segment back
mov ax,offset cmdnam ; point to cmd name again
call spath ; look for it
jc run8 ; not found, go complain
mov dx,ax ; point to command name
mov al,0 ; load and execute...
mov ah,exec
mov bx,offset exearg ; and to arguments
mov ssave,sp ; save stack ptr
int dos ; go run the program
mov ax,seg datas
mov ds,ax ; reset data segment
mov ax,seg stack
mov ss,ax ; and stack segment
mov sp,ssave ; restore stack ptr
mov ah,setdma
mov dx,offset buff
pushf ; save flags
int dos ; restore dma address!!
popf ; recover flags
jc run8 ; error, handle.
jmp rskp ; ok, return
run7: mov ah,prstr
mov dx,offset erms36
int dos
jmp rskp
run8: mov ah,prstr
mov dx,offset erms37
int dos
jmp rskp
RUN ENDP
; the show command
showcmd proc near
mov ah,cmkey
mov dx,offset shotab
xor bx,bx ; no canned help
call comnd
jmp r
call bx ; call the handler
jmp r
jmp rskp ; and return
showcmd endp
intbrk: cmp flags.debug,1 ; Debug mode?
je intb1 ; Yes, then don't ignore the ^C.
push ax
push ds
mov ax,seg datas
mov ds,ax
mov flags.cxzflg,'C' ; Say we saw a ^C.
mov pack.state,'A' ; Set the state to abort.
pop ds
pop ax
iret
intb1: jmp in3ad ; Original break interrupt address.
; Set the maximum data packet size. [21b]
PACKLEN PROC NEAR
mov ah,trans.spsiz ; Maximum send packet size.
sub ah,4 ; Size minus control info.
sub ah,trans.chklen ; And minus checksum chars.
sub ah,2 ; Leave room at end: 2 for possible #X.
cmp trans.ebquot,'N' ; Doing 8-bit quoting?
je pack0 ; Nope so we've got our size.
cmp trans.ebquot,'Y'
je pack0 ; Not doing it in this case either.
sub ah,1 ; Another 1 for 8th-bit quoting.
pack0: mov trans.maxdat,ah ; Save max length for data field.
ret
PACKLEN ENDP
NOUT2 PROC NEAR
push ax
push dx
mov temp,10 ; Divide quotient by 10.
cwd ; Convert word to doubleword.
div temp ; AX <-- Quo, DX <-- Rem.
cmp ax,0 ; Are we done?
jz nout0 ; Yes.
call nout2 ; If not, then recurse.
nout0: add dl,'0' ; Make it printable.
mov temp,ax
mov al,dl
stosb
mov ax,temp
pop dx
pop ax
ret ; We're done. [21c]
NOUT2 ENDP
NOUT2X PROC NEAR
push ax
push dx
push cx
mov temp,10 ; Divide quotient by 10.
div temp ; AX <-- Quo, DX <-- Rem.
mov cx,dx ; Remember the remainder.
cmp ax,0 ; Are we done?
jz nout0x ; Yes.
mov dx,0
call nout2 ; If not, then recurse.
nout0x: add cl,'0' ; Make it printable.
mov temp,ax
mov al,cl
stosb
mov ax,temp
pop cx
pop dx
pop ax
ret ; We're done. [21c]
NOUT2X ENDP
SPATH proc near
; enter with ax/ ptr to file name. Searches path for given file,
; returns with ax/ ptr to whole name, or carry on if file isn't
; to be found.
push es
mov bx,ds
mov es,bx ; address data segment
mov bx,ax ; convenient place to keep this
mov si,ax
mov di,offset tfile ; place to copy to
mov dl,0 ; no '\' seen yet
mov ah,swchar ; get switch character
spath1: lodsb
stosb
cmp al,ah ; contain path characters?
jne spath2 ; no, keep going
mov dl,1 ; remember we've seen them
spath2: or al,al
jnz spath1 ; copy name in
or dl,dl ; look at flag
jz spath3 ; no path embedded, keep going
pop es
mov ax,offset tfile ; else...
call isfile
mov ax,offset tfile ; point to right thing...
ret ; let isfile decide and return
; no path, keep going
spath3: mov si,offset pthbuf ; path definition
cmp byte ptr [si],0 ; empty path?
jne spath4 ; no, keep going
mov ah,gcd ; get current dir
mov dl,0 ; for default drive
mov si,offset defpth+1 ; place to put it
int dos
mov si,offset defpth ; point to the path
spath4: cmp byte ptr [si],0 ; null, exit loop
je spath9
mov di,offset tfile ; place to put name
spath5: lodsb ; get a byte
cmp al,';' ; end of this part?
je spath7 ; yes, break loop
cmp al,0 ; maybe end of string?
jne spath6 ; no, keep going
dec si ; back up over it
jmp short spath7 ; and break loop
spath6: stosb ; else stick in dest string
jmp spath5 ; and continue
spath7: push si ; save this ptr
mov si,bx ; this is user's file name
mov al,swchar ; get switch character.
cmp byte ptr [di-1],al ; does it end with switch char?
je spath8 ; yes, don't put one in
stosb ; else add one
spath8: lodsb
stosb
or al,al
jnz spath8 ; copy rest of name
pop si ; restore pos in path def
mov ax,offset tfile
call isfile ; is it a file?
jc spath4 ; no, keep looking
mov ax,offset tfile
pop es
ret ; return success (carry off)
spath9: pop es ; restore this
mov ax,bx ; not found yet, get original path
call isfile ; does it exist?
ret ; return whatever isfile says.
spath endp
isfile proc near
; returns carry off if the file pointed to by ax exists
mov dx,ax ; copy ptr
mov al,0 ; don't change anything
mov ah,chmod
int dos
ret ; dos sets carry
isfile endp
; 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 of code section.
end start
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 mskerm.asm
/bin/echo -n ' '; /bin/ls -ld mskerm.asm
fi
/bin/echo 'Extracting mskermit.ini'
sed 's/^X//' <<'//go.sysin dd *' >mskermit.ini
; Make shift-comma send a left angle bracket
set key scan 556
<
; Shift-period sends a right angle bracket
set key scan 558
>
; Accent grave is where ESC is supposed to be
set key scan 96
\33
; Put accent grave on the ESC function key
set key scan 27
`
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 mskermit.ini
/bin/echo -n ' '; /bin/ls -ld mskermit.ini
fi
/bin/echo 'Extracting mskermit.msg'
sed 's/^X//' <<'//go.sysin dd *' >mskermit.msg
This issue of the Info-Kermit Digest is devoted to the long-heralded (and
overdue) announcement of version 2 of Kermit for MS-DOS systems (Kermit
is Columbia University's file transfer protocol for use over
telecommunication lines, and it runs on a wide variety of systems). We
announced our intention to provide this new release back in January, and
have been working on it ever since. The previous release was 1.20, 28
November 1983.
The new version is called "Kermit-MS" rather than "Kermit-86" and the
version number is 2.26. It is available for several systems:
System DOS Versions
------ ------------
IBM PC, PPC, and XT 1.1, 2.0 & above
DEC Rainbow 100 and 100+ 2.05 & above
HP-150 2.0
Wang PC 2.01
Others (Generic DOS) 1.1, 2.0 & above
Versions for the IBM PCjr and Heath/Zenith 100 are soon to be added
(version 1.20 already run on these machines). If your MS-DOS system is
not on this list, you are invited to add support for it by supplying the
appropriate system- and device-dependent modules (described below).
The IBM version has been tested on IBM PCs with the old and new
motherboards and ROMs, as well as on the XT and Portable PC, on hard
disks, floppy disks, and RAM disks, and on color and monochrome monitors.
It has NOT been tested on the Compaq, Columbia, or other "PC compatible"
product; there is some chance that it might not work on the compatibles
even when the previous release (1.20) did, because of greater dependence
on the display hardware.
Version 2 of MS-DOS Kermit has been tested successfully up to 9600 baud on
the IBM, DEC, HP, and Wang micros, in communication with full duplex
systems like the DEC-20 and VAX, and half duplex systems like IBM
mainframes. Kermit-MS requires about 80K RAM, and certain functions like
PUSH and RUN will need additional memory. Thus, for DOS plus Kermit, you
will need a machine with at least 128K. Version 1.20 can run on a 64K
machine.
Version 1.20 will remain available indefinitely because it has proven
quite stable, runs on a variety of PC-compatible systems, and is
considerably smaller than version 2.
Here is a summary of the changes:
* Program organization:
The program has been broken up into separate source files, assembled
separately, and linked together. The modules are:
System/Device Independent:
MSKERM.ASM - Main program
MSSEND.ASM - File sender
MSRECV.ASM - File receiver
MSSERV.ASM - Server operation
MSFILE.ASM - File i/o
MSCMD.ASM - Command parser
MSTERM.ASM - CONNECT command
MSCOMM.ASM - Communications port buffering & flow control
MSSET.ASM - SET, SHOW, and STATUS commands
MSDEFS.H - Data structure definitions and equates
System/Device Dependent:
MSXxxx.ASM - System-dependent code for system xxx
MSYxxx.ASM - System-dependent screen and keyboard code
MSZxxx.ASM - Modem control (modem-dependent)
MSXSYS.DOC - Description of system-dependent modules
The modular organization allows easier modification of the program,
quicker transfer of modified portions from system to system. The modules
are designed to be well-defined and self-contained, such that they can
be easily replaced. For instance, someone who prefers windows and mice
to typing commands could replace the command parsing module without having
to worry about the effect on the other modules.
* Kermit Protocol Improvements:
Kermit-MS now supports:
X. 8th-bit prefixing for passing binary data through 7-bit communication links
X. 12-bit checksums and 16-bit CRCs as alternate block check types
X. Compression of repeated bytes
X. Server operation
X. Advanced commands for servers, including:
REMOTE DELETE
REMOTE DIRECTORY
REMOTE HELP
REMOTE HOST
REMOTE SPACE
REMOTE TYPE
These advanced protocol features can be used in conjunction with other
advanced Kermit implementations, including itself, as well as the current
Kermits for the DECsystem-10, DECSYSTEM-20, VAX/VMS, PDP-11 (RSX, RSTS, RT),
DEC Pro-350, and others, and soon to include IBM VM/CMS and UNIX.
* Local command execution:
The following new commands provide access to DOS functions from within the
Kermit-MS program:
DELETE
DIRECTORY
SET DEFAULT DISK
PUSH (to DOS)
SET DESTINATION (device - disk or printer)
SPACE (runs CHKDSK)
RUN (a program)
* Command parsing:
The command parser has been improved in many areas. For instance, "?" now
works much better than before (though still not perfectly). ESC now
provides completion not only in keywords, but also in filenames. CTRL-W
deletes the previous "word" on the command line. CTRL-C always returns to
the Kermit-MS> prompt.
There is a command macro facility; DEFINE lets you build macros by
combining Kermit-MS commands, DO executes them, SHOW displays them.
DOS command line arguments are accepted, and may be strung together
separated by commas, e.g. "kermit set baud 9600, set timer on, connect"
Kermit-MS now reads an initialization file, MSKERMIT.INI, and can process
(nested) command files with a TAKE command.
* Terminal emulation:
On IBM micros, the speed of Heath-19 terminal emulation has been improved
by using direct screen memory access. Functions like insert and delete
character now execute very rapidly. Heath-19 emulation functions, such as
reverse index, missing from earlier releases are now supplied. H19
emulation may be disabled to allow the use of other console drivers, like
ANSI.SYS, in conjunction with Kermit-MS.
On systems with 25 lines, the 25th line is an inverse video mode line,
displaying current settings, which may be kept or turned off. On the IBM
and DEC systems, there are pop-up help and status screens, and the screen
is saved and restored between remote/local context switches.
The terminal session can be logged to disk to provide unguarded capture of
remote files or session typescripts.
On the IBM, DEC, and HP systems, the screen can be rolled back several
pages, on a per-line or per-screen basis.
On most of the systems, print-screen (screen dump) and CTRL-print-screen
(toggle printing on/off) work as they do in DOS.
On the IBM and DEC systems, a key redefinition facility is available to
allow the layout of the keyboard to be altered to suit individual tastes,
to set up keypads or function keys for specific applications, or to
construct "keystroke macros". On IBM micros, the ALT key can be set up
for use as a META key for use with EMACS-like editors.
All versions of Kermit-MS except the generic DOS version are capable of
transmitting the BREAK signal.
The functions that are missing from the Wang and/or HP micros -- key
redefinition, pop-up menus, screen rollback, screen print -- were omitted
due to lack of information about how to get at the scan codes, screen
memory, printer interrupts, etc, and may be added at a later time.
Meanwhile, anyone out there who has the information and feels inclined to
add missing features is invited to do so.
* Communication options:
The port characteristics are left alone when Kermit-MS starts (in the
previous release, Kermit-MS always set the baud rate). The program allows
settings for speed, duplex, flow control, handshake, and parity on a
per-port basis, to allow convenient switching between ports.
* File Transfer:
You can now supply new names for files in SEND and GET commands.
A timeout facility has been added to allow automatic recovery from
deadlocks when communicating with systems (like IBM mainframes) that can't
time out.
The file transfer display has been reformatted, and includes more useful
information, including a percentage for outbound files. The various
counts are updated more reliably.
Several options are available for interrupting file transfer, including
^X (cancel current file), ^Z (cancel entire batch), ^E (user-generated
"error"), ^C (return immediately to command level), CR (simulate a timeout).
The options are displayed during file transfer.
There is a new end-of-file option to allow selection of DOS-style (believe
the DOS byte count) or CP/M-style (file ends at first CTRL-Z) EOF detection.
* Remote operation:
Kermit-MS may be run from the back port in either interactive or server mode.
This allows micro-to-micro file transfer without requiring an operator on
both ends.
* New Bootstrapping Procedure:
The Kermit .EXE files for the various systems are now encoded using a
printable 4-for-3 encoding, with compression of repeated 0 bytes. The
result tends to be smaller than the original .EXE file. A new set of
bootstrapping programs has been provided:
MSMKBOO.C Encode. Can be used on any binary file. Written in C.
MSBOOT.FOR Send the encoded file from the mainframe. Fortran.
MSPCTRAN.BAS Decode the encoded file on the micro. MS Basic.
MSPCBOOT.BAS Receive on the micro, decode on the fly. MS Basic.
* Documentation:
There's an entirely new manual, available now as a separate document,
soon to be incorporated into the Kermit User Guide. It describes
operation of the program in detail, along with the new bootstrapping
procedure.
* How To Get It:
Kermit is available for a wide variety of systems -- micros, minis, and
mainframes. It is distributed by Columbia University via network or on
magnetic tape. For further information about Kermit, send network mail to
INFO-KERMIT-REQUEST@COLUMBIA-20, or write to the Kermit Distribution
address below. To be added to the Info-Kermit network mailing list, mail
to INFO-KERMIT-REQUEST@COLUMBIA-20.
The new MS-DOS Kermit files are available from COLUMBIA-20 via anonymous
FTP after 6pm daily (ARPANET), though KERMSRV at CUVMA on BITNET (BITNET
users should type "SMSG RSCS MSG CUVMA KERMSRV HELP" for information about
the Columbia Kermit file server), and on all the Columbia DEC-20 systems
in the KERMIT area. The file names all begin with "MS" (on BITNET, omit
the "KER:" prefix).
The executable programs have the suffix .EXE and are in 8-bit binary
format. The corresponding 7-bit ASCII encoded files have the suffix .BOO.
The system-specific programs are available in both .EXE and .BOO formats.
KER:MSIBMPC -- IBM PC, XT
KER:MSIBMJR -- IBM PCjr (not yet availble)
KER:MSRB100 -- DEC Rainbow 100, 100+
KER:MSHP150 -- Hewlett-Packard 150
KER:MSHZ100 -- Heath/Zenith 100 (not yet available)
KER:MSWANG -- Wang PC
KER:MSGENER -- Generic DOS
KER:MS*.ASM, KER:MS*.H are the assembler source files.
KER:MSBUILD.HLP tells how to build the program.
KER:MSKERMIT.DOC is the new MS-DOS section for the Kermit User Guide.
KER:MSKERMIT.MSS is the Scribe source for the .DOC file.
Those without network access may write to the following address for
details of how to order a complete Kermit distribution on 9-track
magnetic tape:
KERMIT Distribution
Columbia University Center for Computing Activities
612 West 115th Street
New York, NY 10025
Version 2 of MS-DOS Kermit will be submitted to PC-SIG so that it can be
ordered on IBM PC floppy disks. Inquiries should be directed to
PC Software Interest Group
1556 Halford Avenue, Suite #130
Santa Clara, CA 95051
Phone 408-730-9291
Be sure to wait until they have version 2, because they are presently
distributing version 1 on their disks numbers 41 and 42. It may take
some time for them to update their distribution.
* Credit:
The bulk of the work was done by Daphne Tzoar and Jeff Damens of the
Columbia University Center for Computing Activities. Many ideas (and
"existence proofs") were contributed by Herm Fischer of Litton Data
Systems -- key redefinitions, remote and server operation, etc, but those
who have been using Herm's modified 1.20 will find that some of the
features he added have been done differently in this release. 8th-bit
quoting was originally added by Leslie Spira and her staff at The Source
Telecomputing to allow Kermit to transfer binary files over Telenet. The
new bootstrapping procedure and the new file transfer display were done by
Bill Catchings of Columbia. Filename completion came from Kimmo Laaksonen
at the Helsinki University of Technology. Some corporate support and
encouragement was provided by Digital Equipment Corporation, Wang
Laboratories, and IBM.
* Disclaimer:
Although we have been using the new version on several different kinds
of systems for a good while and have done extensive testing, some bugs
may have slipped through. Please hang on to your old release (1.20),
and don't hesitate to report any problems to Info-Kermit@COLUMBIA-20.
Suggestions and contributions are also welcome.
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 mskermit.msg
/bin/echo -n ' '; /bin/ls -ld mskermit.msg
fi
/bin/echo 'Extracting msmeta.ini'
sed 's/^X//' <<'//go.sysin dd *' >msmeta.ini
; TAKE'ing this file will make the ALT key function like a META key
; on the IBM PC.
set key scan 2064
\321
set key scan 2065
\327
set key scan 2066
\305
set key scan 2067
\322
set key scan 2068
\324
set key scan 2069
\331
set key scan 2070
\325
set key scan 2071
\311
set key scan 2072
\317
set key scan 2073
\320
set key scan 2078
\301
set key scan 2079
\323
set key scan 2080
\304
set key scan 2081
\306
set key scan 2082
\307
set key scan 2083
\310
set key scan 2084
\312
set key scan 2086
\313
set key scan 2087
\314
set key scan 2168
\261
set key scan 2169
\262
set key scan 2170
\263
set key scan 2171
\264
set key scan 2172
\265
set key scan 2173
\266
set key scan 2174
\267
set key scan 2175
\270
set key scan 2176
\271
set key scan 2177
\272
set key scan 2092
\332
set key scan 2093
\330
set key scan 2094
\303
set key scan 2095
\326
set key scan 2096
\302
set key scan 2097
\316
set key scan 2098
\317//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msmeta.ini
/bin/echo -n ' '; /bin/ls -ld msmeta.ini
fi
X/bin/echo 'Extracting msrbemacs.ini'
sed 's/^X//' <<'//go.sysin dd *' >msrbemacs.ini
; EMACS function key setup for Kermit-MS/Rainbow
;
; C-@ (set mark) on SELECT
set key select
\00
;
; M-h (select region) on CTRL-SELECT
set key scan 1313
\33h
;
; C-U 12 C-X C-I (rigidly indent region 12 spaces) on TAB
set key scan 9
\25\61\62\30\11
; C-X C-I (rigidly indent region) on SHIFT-TAB
set key scan 521
\30\11
;
; C-S (forward search) on FIND
set key find
\23
;
; C-R (reverse search) on CTRL-FIND
set key scan 1307
\22
;
; M-D (delete word) on REMOVE
set key remove
\33d
;
; M-K (delete sentence) on CTRL-REMOVE
set key scan 1311
\33k
;
; C-P (up line) on uparrow
set key scan 295
\20
;
; M-[ (up paragraph) on CTRL-uparrow
set key scan 1319
\33[
;
; C-X [ (up page) on SHIFT-uparrow
set key scan 807
\30[
;
; M-< (top of file) on CTRL-SHIFT-uparrow
set key scan 1831
\33<
;
; C-B (back character) on leftarrow
set key scan 301
\02
;
; C-A (beginning of line) on CTRL-leftarrow
set key scan 1325
\01
;
; M-A (back sentence) on SHIFT-leftarrow
set key scan 813
\33a
;
; C-N (next line) on downarrow
set key scan 297
\16
; M-] (down paragraph) on CTRL-downarrow
set key scan 1321
\33]
;
; C-X ] (down page) on SHIFT-downarrow
set key scan 809
\30]
;
; M-> (end of file) on CTRL-SHIFT-downarrow
set key scan 1833
\30>
;
; C-F (forward character) on rightarrow
set key scan 299
\06
;
; C-E (end of line) on CTRL-rightarrow
set key scan 1323
\05
;
; M-E (end of sentence) on SHIFT-rightarrow
set key scan 811
\33e
;
; C-X E (do keyboard macro) on DO
set key scan 257
\30e
;
; C-U C-X E (do keyboard macro 4x) on CTRL-DO
set key scan 1281
\25\30e
;
; C-U 8 C-X E (do keyboard macro 8x) on SHIFT-DO
set key scan 769
\25\70\30e
;
; C-U C-U C-X E (do keyboard macro 16x) on CTRL-SHIFT-DO
set key scan 1793
\25\25\30e
;
; ^_ on HELP
set key scan 256
\37
;
; C-X C-Z on EXIT
set key scan 271
\30\32
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msrbemacs.ini
/bin/echo -n ' '; /bin/ls -ld msrbemacs.ini
fi
X/bin/echo 'Extracting msrecv.asm'
sed 's/^X//' <<'//go.sysin dd *' >msrecv.asm
public read12, read2, rin21, rfile3, read, updrtr, nak, rrinit
include msdefs.h
datas segment public 'datas'
extrn fcb:byte, data:byte, bufpnt:word, chrcnt:word, curchk:byte
extrn comand:byte, flags:byte, pack:byte, trans:byte
ermes7 db '?Unable to receive initiate$'
ermes8 db '?Unable to receive file name$'
ermes9 db '?Unable to receive end of file$'
erms10 db '?Unable to receive data$'
infms1 db cr,' Receiving: In progress$'
infms3 db 'Completed$'
infms4 db 'Failed$'
infms6 db 'Interrupted$'
remmsg1 db 'Kermit-MS: Invalid filename'
filhlp2 db ' Confirm with carriage return or specify name '
db ' to use for incoming file $'
ender db bell,bell,'$'
crlf db cr,lf,'$'
temp dw 0
datas ends
code segment public
extrn gofil:near, outbuf:near, fixfcb:near, comnd:near
extrn spack:near, rpack:near, serini:near, serrst:near
extrn spar:near, rpar:near, init:near, init1:near, cxmsg:near
extrn error:near, ptchr:near, erpos:near, rtpos:near
extrn stpos:near, rprpos:near, nppos:near, nout:near
extrn dodec:near, doenc:near, errpack:near
extrn send11:near, clrmod:near
assume cs:code, ds:datas
; Update retry count and fall through to send a NAK.
nak0: call updrtr ; Update retry count.
nak: mov ax,pack.pktnum ; Get the packet number we're waiting for.
mov pack.argblk,ax
mov pack.argbk1,0
mov cx,0 ; No data, but this may change.
call doenc ; So call encode.
mov ah,'N' ; NAK that packet.
call spack
jmp abort
nop ; So 'jmp rskp' in SPACK comes here. [19a]
ret ; Go around again.
updrtr: cmp pack.state,'A' ; Supposed to abort?
je upd0 ; Yes, don't bother with retry count.
inc pack.numrtr ; Increment the number of retries.
cmp flags.xflg,1 ; Writing to screen?
je upd0
call rtpos ; Position cursor.
mov ax,pack.numrtr
call nout ; Write the number of retries.
upd0: ret
; Abort
ABORT PROC NEAR
mov pack.state,'A' ; Otherwise abort.
ret
ABORT ENDP
; init variables for read...
rrinit proc near
mov pack.numpkt,0 ; Set the number of packets to zero.
mov pack.numrtr,0 ; Set the number of retries to zero.
mov pack.pktnum,0 ; Set the packet number to zero.
mov pack.numtry,0 ; Set the number of tries to zero.
ret
rrinit endp
; RECEIVE command -- Some code moved to the GET routine. [21a]
READ PROC NEAR
mov comand.cmrflg,1 ; Say we're receiving a file. [21a start]
mov comand.cmcr,1 ; Allow bare CR after RECEIVE.
mov flags.droflg,0 ; Override default drive flag.
mov flags.nmoflg,0 ; Override file name from other host?
mov dx,offset fcb ; Put filename here.
mov bx,offset filhlp2 ; Text of help message.
mov ah,cmifi ; Read in the filename.
call comnd
jmp r
mov comand.cmrflg,0 ; Reset flag.
mov comand.cmcr,0
mov flags.wldflg,0 ; Just in case
mov ah,cmcfm ; Get a confirm.
call comnd
jmp r
read1: cmp flags.remflg,0 ; remote mode?
jne read12 ; yes, no printing
call init
read12: mov flags.cxzflg,0 ; Reset ^X/^Z flag. [20c]
call rrinit ; init variables for read
call serini ; Initialize serial port. [14]
cmp flags.remflg,0 ; in remote mode?
jne read12a ; yes, no printing
call init1 ; Clear the line and initialize the buffers.
call stpos
mov ah,prstr ; Be informative.
mov dx,offset infms1
int dos
call rtpos ; Position cursor.
mov ax,pack.numrtr
call nout ; Write the number of retries.
read12a:mov pack.state,'R' ; Set the state to receive initiate.
read2: cmp flags.xflg,1 ; Are we receiving to the screen. [21c]
je read21 ; Skip the screen stuff. [21c]
cmp flags.remflg,0 ; maybe remote mode?
jne read21 ; yup, skip the screen stuff
call nppos ; Position cursor for number of packets msg.
mov ax,pack.numpkt
call nout ; Write the number of packets.
read21: mov ah,pack.state ; Get the state. [21c]
cmp ah,'D' ; Are we in the data send state?
jne read3
call rdata
jmp read2
read3: cmp ah,'F' ; Are we in the file receive state?
jne read4
call rfile ; Call receive file.
jmp read2
read4: cmp ah,'R' ; Are we in the receive initiate state?
jne read5
call rinit
jmp read2
read5: cmp ah,'C' ; Are we in the receive complete state?
jne read6
call serrst ; Reset serial port. [14]
cmp flags.xflg,0 ; Did we write to the screen? [21c]
je read51 ; No so print status. [21c]
mov flags.xflg,0 ; Reset it. [21c]
jmp rskp ; Yes, so just return. [21c]
read51: cmp flags.remflg,0 ; remote mode?
jne read51a ; yes, keep going
call stpos ; Position cursor. [21c]
mov ah,prstr
mov dx,offset infms3 ; Plus a little cuteness.
cmp flags.cxzflg,0 ; Completed or interrupted? [20c]
je read13 ; Ended normally. [20c]
mov dx,offset infms6 ; Say was interrupted. [20c]
read13: int dos
cmp flags.belflg,0 ; Bell desired? [17a]
je readnb ; No. [17a]
mov dx,offset ender ; Ring them bells. [4]
int dos ; [4]
readnb: call clrmod ; clear 25th line
call rprpos ; Put prompt here.
read51a:jmp rskp
read6: call serrst ; Reset serial port. [14]
cmp flags.xflg,0 ; Did we write out to screen? [21c]
je read61 ; No so print status. [21c]
mov flags.xflg,0 ; Reset it. [21c]
jmp rskp ; Print onto screen. [21c]
read61: cmp flags.remflg,0 ; remote mode?
jne read7a ; yes, no printing.
call stpos ; Position cursor. [21c]
mov ah,prstr
mov dx,offset infms4 ; Plus a little cuteness.
int dos
cmp flags.belflg,0 ; Bell desired? [17a]
je read7 ; No. [17a]
mov dx,offset ender ; Ring them bells. [4]
int dos ; [4]
read7: call clrmod ; clear mode line
call rprpos ; Put prompt here.
read7a: jmp rskp
READ ENDP
; Receive routines
; Receive init
RINIT PROC NEAR
mov ah,pack.numtry ; Get the number of tries.
cmp ah,imxtry ; Have we reached the maximum number of tries?
jl rinit2
call erpos ; Position cursor.
mov dx,offset ermes7
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rinit2: inc ah ; Increment it.
mov pack.numtry,ah ; Save the updated number of tries.
mov ax,pack.argbk2 ; get packet type if here from get
cmp flags.getflg,1 ; Have we already read in the packet? [21a]
je rin21a ; Yes, so don't call RPACK. [21a]
mov ah,trans.chklen
mov curchk,ah ; Save checksum length we want to use.
mov trans.chklen,1 ; Use 1 char for init packet.
call rpack ; Get a packet.
jmp rin22 ; Trashed packet: nak, retry.
push ax
mov ah,curchk
mov trans.chklen,ah ; Reset to desired value.
pop ax
rin21a: cmp ah,'S' ; Is it a send initiate packet?
jne rinit3 ; If not see if its an error.
rin21: mov flags.getflg,0 ; Reset flag. [21a]
mov ah,pack.numtry ; Get the number of tries.
mov pack.oldtry,ah ; Save it.
mov pack.numtry,0 ; Reset the number of tries.
mov ax,pack.argblk ; Returned packet number. (Synchronize them.)
inc ax ; Increment it.
and ax,3FH ; Turn off the two high order bits.
mov pack.pktnum,ax ; Save modulo 64 of the number.
mov bx,pack.numpkt
inc bx ; Increment the number of packets.
mov pack.numpkt,bx
mov ax,pack.argbk1 ; Get the number of arguments received.
mov bx,offset data ; Get a pointer to the data.
call spar ; Get the data into the proper variables.
mov bx,offset data ; Get a pointer to our data block.
call rpar ; Set up the receive parameters.
xchg ah,al
mov ah,0
mov pack.argbk1,ax ; Store the returned number of arguments.
mov ah,trans.chklen ; Checksum length we'll use.
mov curchk,ah ; Save it.
mov trans.chklen,1 ; Use 1 char for init packet.
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
mov ah,curchk ; Checksum length we'll use.
mov trans.chklen,ah ; Reset to desired value.
mov ah,'F' ; Set the state to file send.
mov pack.state,ah
ret
rin22: mov ah,curchk
mov trans.chklen,ah ; Reset to desired value.
jmp nak0 ; Try again.
rinit3: cmp ah,'E' ; Is it an error packet?
jne rinit4
call error
rinit4: jmp abort
RINIT ENDP
; Receive file
RFILE PROC NEAR
cmp pack.numtry,maxtry ; Have we reached the maximum number of tries?
jl rfile1
call erpos ; Position cursor.
mov dx,offset ermes8
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rfile1: inc pack.numtry ; Save the updated number of tries.
call rpack ; Get a packet.
jmp nak0 ; Trashed packet: nak, retry.
cmp ah,'S' ; Is it a send initiate packet?
je rfil10
call dodec ; Decode all incoming packets.
jmp rfile2 ; No, try next type.
rfil10: cmp pack.oldtry,imxtry ; Have we reached the maximum number of tries?
jl rfil12 ; If not proceed.
call erpos ; Position cursor.
mov dx,offset ermes7
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rfil12: inc pack.oldtry ; Save the updated number of tries.
mov ax,pack.pktnum ; Get the present packet number.
cmp ax,0 ; Had we wrapped around? [18 start]
jne rfilx
mov ax,64
rfilx: dec ax ; Decrement. [18 end -- new label]
cmp ax,pack.argblk ; Is the packet's number one less than now?
je rfil13
jmp nak0 ; No, NAK and try again.
rfil13: call updrtr ; Update retry count.
mov pack.numtry,0 ; Reset the number of tries.
mov bx,offset data ; Get a pointer to our data block.
call rpar ; Set up the parameter information.
xchg ah,al
mov ah,0
mov pack.argbk1,ax ; Save the number of arguments.
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rfile2: cmp ah,'Z' ; Is it an EOF packet?
jne rfile3 ; No, try next type.
cmp pack.oldtry,maxtry ; Have we reached the maximum number of tries?
jl rfil21 ; If not proceed.
call erpos ; Position cursor.
mov dx,offset ermes9
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rfil21: inc pack.oldtry ; Increment it.
mov ax,pack.pktnum ; Get the present packet number.
cmp ax,0 ; Had we wrapped around? [18 start]
jne rfily
mov ax,64
rfily: dec ax ; Decrement. [18 end -- new label]
cmp ax,pack.argblk ; Is the packet's number one less than now?
je rfil24
jmp nak0 ; No, NAK and try again.
rfil24: call updrtr ; Update retry count.
mov pack.numtry,0
mov pack.argbk1,0 ; No data. (The packet number is in argblk.)
mov cx,0
call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rfile3: cmp ah,'F' ; Start of file?
je rfil31 ; Yes. [21c]
cmp ah,'X' ; Text header packet? [21c]
jne rfile4 ; Neither one.
rfil31: mov ax,pack.argblk ; Get the packet number. [21c]
cmp ax,pack.pktnum ; Is it the right packet number?
je rfil32
jmp nak ; No, NAK it and try again.
rfil32: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pack.pktnum,ax ; Save modulo 64 of the number.
inc pack.numpkt ; Increment the number of packets.
call gofil ; Get a file to write to.
jmp abort
call init1 ; Initialize all the buffers.
mov ah,pack.numtry ; Get the number of tries.
mov pack.oldtry,ah ; Save it.
mov pack.numtry,0 ; Reset the number of tries.
mov pack.argbk1,0 ; No data. (The packet number is in argblk.)
mov cx,0
call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
mov pack.state,'D' ; Set the state to data receive.
ret
rfile4: cmp ah,'B' ; End of transmission.
jne rfile5
mov ax,pack.pktnum
cmp ax,pack.argblk ; Do we match?
je rfil41
jmp nak ; No, NAK it and try again.
rfil41: mov pack.argbk1,0 ; No data. (Packet number already in argblk).
mov cx,0
call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
mov pack.state,'C' ; Set the state to complete.
ret
rfile5: cmp ah,'E' ; Is it an error packet.
jne rfile6
call error
rfile6: jmp abort
RFILE ENDP
; Receive data
RDATA PROC NEAR
cmp pack.numtry,maxtry ; Get the number of tries.
jl rdata1
call erpos ; Position cursor.
mov dx,offset erms10
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rdata1: inc pack.numtry ; Save the updated number of tries.
call rpack ; Get a packet.
jmp nak0 ; Trashed packet: nak, retry.
cmp ah,'D' ; Is it a data packet?
je rdat11
call dodec ; Decode data.
jmp rdata2 ; No, try next type.
rdat11: mov ax,pack.pktnum ; Get the present packet number.
cmp ax,pack.argblk ; Is the packet's number correct?
jz rdat14
cmp pack.oldtry,maxtry ; Have we reached the maximum number of tries?
jl rdat12 ; If not proceed.
call erpos ; Position cursor.
mov dx,offset erms10
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rdat12: inc pack.oldtry ; Save the updated number of tries.
mov ax,pack.pktnum
cmp ax,0 ; Had we wrapped around? [18 start]
jne rdatx
mov ax,64
rdatx: dec ax ; [14] [18 end -- new label]
cmp ax,pack.argblk ; Is the packet's number one less than now?
je rdat13
jmp nak0 ; No, NAK it and try again.
rdat13: call updrtr ; Update retry count.
mov pack.numtry,0 ; Reset number of tries.
mov pack.argbk1,0 ; No data. (The packet number is in argblk.)
mov cx,0
call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rdat14: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pack.pktnum,ax ; Save modulo 64 of the number.
inc pack.numpkt ; Increment the number of packets.
mov ah,pack.numtry ; Get the number of tries.
mov pack.oldtry,ah ; Save it.
mov ax,pack.argbk1 ; Get the length of the data.
cmp flags.cxzflg,0 ; Has the user typed a ^X or ^Z? [20c]
je rdt14x ; No, write out the data.
cmp flags.abfflg,1 ; Discard incomplete files?
je rdat15 ; If yes don't write data out to file. [20c]
rdt14x: mov bx,offset data ; Where the data is. [25]
call ptchr
jmp abort ; Unable to write out chars; abort.
rdat15: mov pack.numtry,0 ; Reset the number of tries.
mov pack.argbk1,0 ; No data. (Packet number still in argblk.)
mov cx,0
cmp flags.cxzflg,0 ; Interrupt file transfer? [20c]
je rdat16 ; Nope. [20c]
mov bx,offset data ; Send data in ACK in case remote... [20c]
mov ah,flags.cxzflg ; ... knows about ^X/^Z. [20c]
mov [bx],ah ; Put data into the packet. [20c]
mov pack.argbk1,1 ; Set data size to 1. [20c]
mov cx,1
rdat16: call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rdata2: cmp ah,'F' ; Start of file?
je rdat20 ; Yup. [21c]
cmp ah,'X' ; Text header packet? [21c]
jne rdata3 ; No, try next type.
rdat20: cmp pack.oldtry,maxtry ; Reached the max number of tries? [21c]
jl rdat21 ; If not proceed.
call erpos ; Position cursor.
mov dx,offset ermes8
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rdat21: inc pack.oldtry ; Save the updated number of tries.
mov ax,pack.pktnum
cmp ax,0 ; Had we wrapped around? [18 start]
jne rdaty
mov ax,64
rdaty: dec ax ; [14 Omitted accidentally - D.T.] [18 end]
cmp ax,pack.argblk ; Is the packet's number one less than now?
je rdat22
jmp nak0 ; No, NAK it and try again.
rdat22: call updrtr ; Update retry count.
mov pack.numtry,0 ; Reset number of tries.
mov pack.argbk1,0 ; No data. (The packet number is in argblk.)
mov cx,0
call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rdata3: cmp ah,'Z' ; Is it a EOF packet?
je rdat3x ; [13]
jmp rdata4 ; Try and see if its an error. [13]
rdat3x: mov ax,pack.pktnum ; Get the present packet number. [13]
cmp ax,pack.argblk ; Is the packet's number correct?
je rdat32
jmp nak0 ; No, NAK it and try again.
rdat32: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pack.pktnum,ax ; Save modulo 64 of the number.
inc pack.numpkt
cmp flags.cxzflg,0 ; Do we want to discard the file? [20c]
jne rdt32x ; Yes. [20c]
cmp pack.argbk1,1 ; One piece of data? [20c]
jne rdat33 ; Nope - finish writing out file? [20c]
mov bx,offset data ; Get data area. [20c]
mov ah,[bx] ; Get the data. [20c]
cmp ah,'D' ; "D" for discard? [20c]
jne rdat33 ; Nope - write out file. [20c]
rdt32x: cmp flags.abfflg,0 ; Keep incomplete files?
je rdat33 ; Yes, go write it out.
mov ah,closf ; First, close the file.
mov dx,offset fcb ; Give the file parameters. [20c]
int dos ; Kill it, ignore errors. [20c]
mov ah,delf ; Delete the file if opened. [20c]
int dos
cmp flags.cxzflg,'X' ; Kill one file or all? [20c]
jne rdat36 ; No so leave flag alone. [20c]
call cxmsg ; Clear msg about interrupt. [20c]
mov flags.cxzflg,0 ; Reset - ^X only kills one file. [20c]
jmp rdat36
rdat33: mov bx,bufpnt ; Get the dma pointer.
mov ax,80H
sub ax,chrcnt ; Get the number of chars left in the DMA.
cmp flags.eofcz,0 ; should we write a ^Z?
jz rdat35 ; no, keep going
cmp flags.xflg,0 ; writing to a file?
jne rdat35 ; no, skip ^Z
cmp ax,80H ; [13 start]
jne rdat34
call outbuf ; Write out buffer if no room for ^Z.
jmp abort
mov ax,0 ; [13 end]
inc chrcnt ; Increment size by one (not two). [21b]
rdat34: mov cl,'Z'-100O ; Put in a ^Z for EOF.
mov [bx],cl ; Add it. [21c]
inc ax
dec chrcnt
rdat35: mov cx,chrcnt
mov temp,cx
call outbuf ; Output the last buffer.
jmp abort ; Give up if the disk is full.
mov ax,temp ; Prepare for the function call.
call fixfcb
mov ah,closf ; Close up the file.
mov dx,offset fcb
int dos
rdat36: cmp flags.destflg,1 ; Writing to disk?
je rdat37 ; Yes, skip next part.
cmp flags.xflg,1 ; Writing to screen?
je rdat37 ; Yes, skip this part.
mov dl,ff ; Send a form feed.
mov ah,lstout ; Write out to first printer.
int dos
rdat37: mov ah,pack.numtry ; Get the number of tries.
mov pack.oldtry,ah ; Save it.
mov pack.numtry,0 ; Reset the number of tries.
mov pack.argbk1,0 ; No data. (The packet number is in argblk.)
mov cx,0
call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
mov pack.state,'F'
ret
rdata4: cmp ah,'E' ; Is it an error packet.
jne rdata5
call error
rdata5: jmp abort
RDATA ENDP
; 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
R PROC NEAR
ret
R ENDP
code ends
end
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msmeta.ini
/bin/echo -n ' '; /bin/ls -ld msmeta.ini
fi
/bin/echo 'Extracting msrecv.asm'
sed 's/^X//' <<'//go.sysin dd *' >msrecv.asm
public read12, read2, rin21, rfile3, read, updrtr, nak, rrinit
include msdefs.h
datas segment public 'datas'
extrn fcb:byte, data:byte, bufpnt:word, chrcnt:word, curchk:byte
extrn comand:byte, flags:byte, pack:byte, trans:byte
ermes7 db '?Unable to receive initiate$'
ermes8 db '?Unable to receive file name$'
ermes9 db '?Unable to receive end of file$'
erms10 db '?Unable to receive data$'
infms1 db cr,' Receiving: In progress$'
infms3 db 'Completed$'
infms4 db 'Failed$'
infms6 db 'Interrupted$'
remmsg1 db 'Kermit-MS: Invalid filename'
filhlp2 db ' Confirm with carriage return or specify name '
db ' to use for incoming file $'
ender db bell,bell,'$'
crlf db cr,lf,'$'
temp dw 0
datas ends
code segment public
extrn gofil:near, outbuf:near, fixfcb:near, comnd:near
extrn spack:near, rpack:near, serini:near, serrst:near
extrn spar:near, rpar:near, init:near, init1:near, cxmsg:near
extrn error:near, ptchr:near, erpos:near, rtpos:near
extrn stpos:near, rprpos:near, nppos:near, nout:near
extrn dodec:near, doenc:near, errpack:near
extrn send11:near, clrmod:near
assume cs:code, ds:datas
; Update retry count and fall through to send a NAK.
nak0: call updrtr ; Update retry count.
nak: mov ax,pack.pktnum ; Get the packet number we're waiting for.
mov pack.argblk,ax
mov pack.argbk1,0
mov cx,0 ; No data, but this may change.
call doenc ; So call encode.
mov ah,'N' ; NAK that packet.
call spack
jmp abort
nop ; So 'jmp rskp' in SPACK comes here. [19a]
ret ; Go around again.
updrtr: cmp pack.state,'A' ; Supposed to abort?
je upd0 ; Yes, don't bother with retry count.
inc pack.numrtr ; Increment the number of retries.
cmp flags.xflg,1 ; Writing to screen?
je upd0
call rtpos ; Position cursor.
mov ax,pack.numrtr
call nout ; Write the number of retries.
upd0: ret
; Abort
ABORT PROC NEAR
mov pack.state,'A' ; Otherwise abort.
ret
ABORT ENDP
; init variables for read...
rrinit proc near
mov pack.numpkt,0 ; Set the number of packets to zero.
mov pack.numrtr,0 ; Set the number of retries to zero.
mov pack.pktnum,0 ; Set the packet number to zero.
mov pack.numtry,0 ; Set the number of tries to zero.
ret
rrinit endp
; RECEIVE command -- Some code moved to the GET routine. [21a]
READ PROC NEAR
mov comand.cmrflg,1 ; Say we're receiving a file. [21a start]
mov comand.cmcr,1 ; Allow bare CR after RECEIVE.
mov flags.droflg,0 ; Override default drive flag.
mov flags.nmoflg,0 ; Override file name from other host?
mov dx,offset fcb ; Put filename here.
mov bx,offset filhlp2 ; Text of help message.
mov ah,cmifi ; Read in the filename.
call comnd
jmp r
mov comand.cmrflg,0 ; Reset flag.
mov comand.cmcr,0
mov flags.wldflg,0 ; Just in case
mov ah,cmcfm ; Get a confirm.
call comnd
jmp r
read1: cmp flags.remflg,0 ; remote mode?
jne read12 ; yes, no printing
call init
read12: mov flags.cxzflg,0 ; Reset ^X/^Z flag. [20c]
call rrinit ; init variables for read
call serini ; Initialize serial port. [14]
cmp flags.remflg,0 ; in remote mode?
jne read12a ; yes, no printing
call init1 ; Clear the line and initialize the buffers.
call stpos
mov ah,prstr ; Be informative.
mov dx,offset infms1
int dos
call rtpos ; Position cursor.
mov ax,pack.numrtr
call nout ; Write the number of retries.
read12a:mov pack.state,'R' ; Set the state to receive initiate.
read2: cmp flags.xflg,1 ; Are we receiving to the screen. [21c]
je read21 ; Skip the screen stuff. [21c]
cmp flags.remflg,0 ; maybe remote mode?
jne read21 ; yup, skip the screen stuff
call nppos ; Position cursor for number of packets msg.
mov ax,pack.numpkt
call nout ; Write the number of packets.
read21: mov ah,pack.state ; Get the state. [21c]
cmp ah,'D' ; Are we in the data send state?
jne read3
call rdata
jmp read2
read3: cmp ah,'F' ; Are we in the file receive state?
jne read4
call rfile ; Call receive file.
jmp read2
read4: cmp ah,'R' ; Are we in the receive initiate state?
jne read5
call rinit
jmp read2
read5: cmp ah,'C' ; Are we in the receive complete state?
jne read6
call serrst ; Reset serial port. [14]
cmp flags.xflg,0 ; Did we write to the screen? [21c]
je read51 ; No so print status. [21c]
mov flags.xflg,0 ; Reset it. [21c]
jmp rskp ; Yes, so just return. [21c]
read51: cmp flags.remflg,0 ; remote mode?
jne read51a ; yes, keep going
call stpos ; Position cursor. [21c]
mov ah,prstr
mov dx,offset infms3 ; Plus a little cuteness.
cmp flags.cxzflg,0 ; Completed or interrupted? [20c]
je read13 ; Ended normally. [20c]
mov dx,offset infms6 ; Say was interrupted. [20c]
read13: int dos
cmp flags.belflg,0 ; Bell desired? [17a]
je readnb ; No. [17a]
mov dx,offset ender ; Ring them bells. [4]
int dos ; [4]
readnb: call clrmod ; clear 25th line
call rprpos ; Put prompt here.
read51a:jmp rskp
read6: call serrst ; Reset serial port. [14]
cmp flags.xflg,0 ; Did we write out to screen? [21c]
je read61 ; No so print status. [21c]
mov flags.xflg,0 ; Reset it. [21c]
jmp rskp ; Print onto screen. [21c]
read61: cmp flags.remflg,0 ; remote mode?
jne read7a ; yes, no printing.
call stpos ; Position cursor. [21c]
mov ah,prstr
mov dx,offset infms4 ; Plus a little cuteness.
int dos
cmp flags.belflg,0 ; Bell desired? [17a]
je read7 ; No. [17a]
mov dx,offset ender ; Ring them bells. [4]
int dos ; [4]
read7: call clrmod ; clear mode line
call rprpos ; Put prompt here.
read7a: jmp rskp
READ ENDP
; Receive routines
; Receive init
RINIT PROC NEAR
mov ah,pack.numtry ; Get the number of tries.
cmp ah,imxtry ; Have we reached the maximum number of tries?
jl rinit2
call erpos ; Position cursor.
mov dx,offset ermes7
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rinit2: inc ah ; Increment it.
mov pack.numtry,ah ; Save the updated number of tries.
mov ax,pack.argbk2 ; get packet type if here from get
cmp flags.getflg,1 ; Have we already read in the packet? [21a]
je rin21a ; Yes, so don't call RPACK. [21a]
mov ah,trans.chklen
mov curchk,ah ; Save checksum length we want to use.
mov trans.chklen,1 ; Use 1 char for init packet.
call rpack ; Get a packet.
jmp rin22 ; Trashed packet: nak, retry.
push ax
mov ah,curchk
mov trans.chklen,ah ; Reset to desired value.
pop ax
rin21a: cmp ah,'S' ; Is it a send initiate packet?
jne rinit3 ; If not see if its an error.
rin21: mov flags.getflg,0 ; Reset flag. [21a]
mov ah,pack.numtry ; Get the number of tries.
mov pack.oldtry,ah ; Save it.
mov pack.numtry,0 ; Reset the number of tries.
mov ax,pack.argblk ; Returned packet number. (Synchronize them.)
inc ax ; Increment it.
and ax,3FH ; Turn off the two high order bits.
mov pack.pktnum,ax ; Save modulo 64 of the number.
mov bx,pack.numpkt
inc bx ; Increment the number of packets.
mov pack.numpkt,bx
mov ax,pack.argbk1 ; Get the number of arguments received.
mov bx,offset data ; Get a pointer to the data.
call spar ; Get the data into the proper variables.
mov bx,offset data ; Get a pointer to our data block.
call rpar ; Set up the receive parameters.
xchg ah,al
mov ah,0
mov pack.argbk1,ax ; Store the returned number of arguments.
mov ah,trans.chklen ; Checksum length we'll use.
mov curchk,ah ; Save it.
mov trans.chklen,1 ; Use 1 char for init packet.
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
mov ah,curchk ; Checksum length we'll use.
mov trans.chklen,ah ; Reset to desired value.
mov ah,'F' ; Set the state to file send.
mov pack.state,ah
ret
rin22: mov ah,curchk
mov trans.chklen,ah ; Reset to desired value.
jmp nak0 ; Try again.
rinit3: cmp ah,'E' ; Is it an error packet?
jne rinit4
call error
rinit4: jmp abort
RINIT ENDP
; Receive file
RFILE PROC NEAR
cmp pack.numtry,maxtry ; Have we reached the maximum number of tries?
jl rfile1
call erpos ; Position cursor.
mov dx,offset ermes8
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rfile1: inc pack.numtry ; Save the updated number of tries.
call rpack ; Get a packet.
jmp nak0 ; Trashed packet: nak, retry.
cmp ah,'S' ; Is it a send initiate packet?
je rfil10
call dodec ; Decode all incoming packets.
jmp rfile2 ; No, try next type.
rfil10: cmp pack.oldtry,imxtry ; Have we reached the maximum number of tries?
jl rfil12 ; If not proceed.
call erpos ; Position cursor.
mov dx,offset ermes7
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rfil12: inc pack.oldtry ; Save the updated number of tries.
mov ax,pack.pktnum ; Get the present packet number.
cmp ax,0 ; Had we wrapped around? [18 start]
jne rfilx
mov ax,64
rfilx: dec ax ; Decrement. [18 end -- new label]
cmp ax,pack.argblk ; Is the packet's number one less than now?
je rfil13
jmp nak0 ; No, NAK and try again.
rfil13: call updrtr ; Update retry count.
mov pack.numtry,0 ; Reset the number of tries.
mov bx,offset data ; Get a pointer to our data block.
call rpar ; Set up the parameter information.
xchg ah,al
mov ah,0
mov pack.argbk1,ax ; Save the number of arguments.
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rfile2: cmp ah,'Z' ; Is it an EOF packet?
jne rfile3 ; No, try next type.
cmp pack.oldtry,maxtry ; Have we reached the maximum number of tries?
jl rfil21 ; If not proceed.
call erpos ; Position cursor.
mov dx,offset ermes9
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rfil21: inc pack.oldtry ; Increment it.
mov ax,pack.pktnum ; Get the present packet number.
cmp ax,0 ; Had we wrapped around? [18 start]
jne rfily
mov ax,64
rfily: dec ax ; Decrement. [18 end -- new label]
cmp ax,pack.argblk ; Is the packet's number one less than now?
je rfil24
jmp nak0 ; No, NAK and try again.
rfil24: call updrtr ; Update retry count.
mov pack.numtry,0
mov pack.argbk1,0 ; No data. (The packet number is in argblk.)
mov cx,0
call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rfile3: cmp ah,'F' ; Start of file?
je rfil31 ; Yes. [21c]
cmp ah,'X' ; Text header packet? [21c]
jne rfile4 ; Neither one.
rfil31: mov ax,pack.argblk ; Get the packet number. [21c]
cmp ax,pack.pktnum ; Is it the right packet number?
je rfil32
jmp nak ; No, NAK it and try again.
rfil32: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pack.pktnum,ax ; Save modulo 64 of the number.
inc pack.numpkt ; Increment the number of packets.
call gofil ; Get a file to write to.
jmp abort
call init1 ; Initialize all the buffers.
mov ah,pack.numtry ; Get the number of tries.
mov pack.oldtry,ah ; Save it.
mov pack.numtry,0 ; Reset the number of tries.
mov pack.argbk1,0 ; No data. (The packet number is in argblk.)
mov cx,0
call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
mov pack.state,'D' ; Set the state to data receive.
ret
rfile4: cmp ah,'B' ; End of transmission.
jne rfile5
mov ax,pack.pktnum
cmp ax,pack.argblk ; Do we match?
je rfil41
jmp nak ; No, NAK it and try again.
rfil41: mov pack.argbk1,0 ; No data. (Packet number already in argblk).
mov cx,0
call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
mov pack.state,'C' ; Set the state to complete.
ret
rfile5: cmp ah,'E' ; Is it an error packet.
jne rfile6
call error
rfile6: jmp abort
RFILE ENDP
; Receive data
RDATA PROC NEAR
cmp pack.numtry,maxtry ; Get the number of tries.
jl rdata1
call erpos ; Position cursor.
mov dx,offset erms10
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rdata1: inc pack.numtry ; Save the updated number of tries.
call rpack ; Get a packet.
jmp nak0 ; Trashed packet: nak, retry.
cmp ah,'D' ; Is it a data packet?
je rdat11
call dodec ; Decode data.
jmp rdata2 ; No, try next type.
rdat11: mov ax,pack.pktnum ; Get the present packet number.
cmp ax,pack.argblk ; Is the packet's number correct?
jz rdat14
cmp pack.oldtry,maxtry ; Have we reached the maximum number of tries?
jl rdat12 ; If not proceed.
call erpos ; Position cursor.
mov dx,offset erms10
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rdat12: inc pack.oldtry ; Save the updated number of tries.
mov ax,pack.pktnum
cmp ax,0 ; Had we wrapped around? [18 start]
jne rdatx
mov ax,64
rdatx: dec ax ; [14] [18 end -- new label]
cmp ax,pack.argblk ; Is the packet's number one less than now?
je rdat13
jmp nak0 ; No, NAK it and try again.
rdat13: call updrtr ; Update retry count.
mov pack.numtry,0 ; Reset number of tries.
mov pack.argbk1,0 ; No data. (The packet number is in argblk.)
mov cx,0
call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rdat14: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pack.pktnum,ax ; Save modulo 64 of the number.
inc pack.numpkt ; Increment the number of packets.
mov ah,pack.numtry ; Get the number of tries.
mov pack.oldtry,ah ; Save it.
mov ax,pack.argbk1 ; Get the length of the data.
cmp flags.cxzflg,0 ; Has the user typed a ^X or ^Z? [20c]
je rdt14x ; No, write out the data.
cmp flags.abfflg,1 ; Discard incomplete files?
je rdat15 ; If yes don't write data out to file. [20c]
rdt14x: mov bx,offset data ; Where the data is. [25]
call ptchr
jmp abort ; Unable to write out chars; abort.
rdat15: mov pack.numtry,0 ; Reset the number of tries.
mov pack.argbk1,0 ; No data. (Packet number still in argblk.)
mov cx,0
cmp flags.cxzflg,0 ; Interrupt file transfer? [20c]
je rdat16 ; Nope. [20c]
mov bx,offset data ; Send data in ACK in case remote... [20c]
mov ah,flags.cxzflg ; ... knows about ^X/^Z. [20c]
mov [bx],ah ; Put data into the packet. [20c]
mov pack.argbk1,1 ; Set data size to 1. [20c]
mov cx,1
rdat16: call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rdata2: cmp ah,'F' ; Start of file?
je rdat20 ; Yup. [21c]
cmp ah,'X' ; Text header packet? [21c]
jne rdata3 ; No, try next type.
rdat20: cmp pack.oldtry,maxtry ; Reached the max number of tries? [21c]
jl rdat21 ; If not proceed.
call erpos ; Position cursor.
mov dx,offset ermes8
mov ah,prstr
int dos ; Print an error message.
mov bx,dx
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
rdat21: inc pack.oldtry ; Save the updated number of tries.
mov ax,pack.pktnum
cmp ax,0 ; Had we wrapped around? [18 start]
jne rdaty
mov ax,64
rdaty: dec ax ; [14 Omitted accidentally - D.T.] [18 end]
cmp ax,pack.argblk ; Is the packet's number one less than now?
je rdat22
jmp nak0 ; No, NAK it and try again.
rdat22: call updrtr ; Update retry count.
mov pack.numtry,0 ; Reset number of tries.
mov pack.argbk1,0 ; No data. (The packet number is in argblk.)
mov cx,0
call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
ret
rdata3: cmp ah,'Z' ; Is it a EOF packet?
je rdat3x ; [13]
jmp rdata4 ; Try and see if its an error. [13]
rdat3x: mov ax,pack.pktnum ; Get the present packet number. [13]
cmp ax,pack.argblk ; Is the packet's number correct?
je rdat32
jmp nak0 ; No, NAK it and try again.
rdat32: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pack.pktnum,ax ; Save modulo 64 of the number.
inc pack.numpkt
cmp flags.cxzflg,0 ; Do we want to discard the file? [20c]
jne rdt32x ; Yes. [20c]
cmp pack.argbk1,1 ; One piece of data? [20c]
jne rdat33 ; Nope - finish writing out file? [20c]
mov bx,offset data ; Get data area. [20c]
mov ah,[bx] ; Get the data. [20c]
cmp ah,'D' ; "D" for discard? [20c]
jne rdat33 ; Nope - write out file. [20c]
rdt32x: cmp flags.abfflg,0 ; Keep incomplete files?
je rdat33 ; Yes, go write it out.
mov ah,closf ; First, close the file.
mov dx,offset fcb ; Give the file parameters. [20c]
int dos ; Kill it, ignore errors. [20c]
mov ah,delf ; Delete the file if opened. [20c]
int dos
cmp flags.cxzflg,'X' ; Kill one file or all? [20c]
jne rdat36 ; No so leave flag alone. [20c]
call cxmsg ; Clear msg about interrupt. [20c]
mov flags.cxzflg,0 ; Reset - ^X only kills one file. [20c]
jmp rdat36
rdat33: mov bx,bufpnt ; Get the dma pointer.
mov ax,80H
sub ax,chrcnt ; Get the number of chars left in the DMA.
cmp flags.eofcz,0 ; should we write a ^Z?
jz rdat35 ; no, keep going
cmp flags.xflg,0 ; writing to a file?
jne rdat35 ; no, skip ^Z
cmp ax,80H ; [13 start]
jne rdat34
call outbuf ; Write out buffer if no room for ^Z.
jmp abort
mov ax,0 ; [13 end]
inc chrcnt ; Increment size by one (not two). [21b]
rdat34: mov cl,'Z'-100O ; Put in a ^Z for EOF.
mov [bx],cl ; Add it. [21c]
inc ax
dec chrcnt
rdat35: mov cx,chrcnt
mov temp,cx
call outbuf ; Output the last buffer.
jmp abort ; Give up if the disk is full.
mov ax,temp ; Prepare for the function call.
call fixfcb
mov ah,closf ; Close up the file.
mov dx,offset fcb
int dos
rdat36: cmp flags.destflg,1 ; Writing to disk?
je rdat37 ; Yes, skip next part.
cmp flags.xflg,1 ; Writing to screen?
je rdat37 ; Yes, skip this part.
mov dl,ff ; Send a form feed.
mov ah,lstout ; Write out to first printer.
int dos
rdat37: mov ah,pack.numtry ; Get the number of tries.
mov pack.oldtry,ah ; Save it.
mov pack.numtry,0 ; Reset the number of tries.
mov pack.argbk1,0 ; No data. (The packet number is in argblk.)
mov cx,0
call doenc
mov ah,'Y' ; Acknowledge packet.
call spack ; Send the packet.
jmp abort
mov pack.state,'F'
ret
rdata4: cmp ah,'E' ; Is it an error packet.
jne rdata5
call error
rdata5: jmp abort
RDATA ENDP
; 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
R PROC NEAR
ret
R ENDP
code ends
end
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msrecv.asm
/bin/echo -n ' '; /bin/ls -ld msrecv.asm
fiknutson@ut-ngp.UUCP (Jim Knutson) (10/05/84)
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting mssend.asm'
sed 's/^X//' <<'//go.sysin dd *' >mssend.asm
public spar, rpar, error, error1, nout, send, flags, trans, pack
public dodec, doenc, curchk, inichk, packlen, send11
include msdefs.h
spmin equ 20 ; Minimum packet size.
spmax equ 94 ; Maximum packet size.
datas segment public 'datas'
extrn buff:byte, data:byte, fcb:byte, cpfcb:byte, filbuf:byte
extrn decbuf:byte, chrcnt:word, bufpnt:word, comand:byte
extrn rptq:byte, origr:byte, rptct:byte, rptval:byte
flags flginfo <>
trans trinfo <>
pack pktinfo <>
crlf db cr,lf,'$'
ender db bell,bell,'$' ; [4]
erms14 db '?Unable to receive an acknowledgment from the host$'
erms15 db '?Unable to find file$'
erms20 db 'Unable to send init packet$'
erms21 db 'Unable to send file header$'
erms22 db 'Unable to send data$'
erms23 db 'Unable to send end-of-file packet$'
erms24 db 'Unable to send break packet$'
infms2 db cr,' Sending: In progress$'
infms3 db 'Completed$'
infms4 db 'Failed$'
infms6 db 'Interrupted$'
infms7 db cr,' Percent transferred: 100%$'
remmsg1 db 'Kermit-MS: File not found$'
filhlp db ' Input file spec (possibly wild) $'
filmsg db ' File name to use on target system or confirm with'
db ' a carriage return $'
curchk db 0 ; Use to store checksum length.
inichk db 1 ; Original or set checksum length.
chrptr dw ? ; Position in character buffer.
fcbpt dw ? ; Position in FCB.
datptr dw ? ; Position in packet data buffer.
siz dw ? ; Size of data from gtchr.
temp dw 0
temp4 dw 0
sendas dw 50 dup(0) ; Buffer for file name.
difnam db 0 ; Send under different name?
difsiz db 0 ; Size of new file name.
asmsg db ' as $'
datas ends
code segment public
extrn serini:near, serrst:near, comnd:near, init:near
extrn spack:near, rpack:near, gtnfil:near, gtchr:near
extrn getfil:near, clrfln:near, nppos:near, rprpos:near
extrn erpos:near, rtpos:near, cxmsg:near, stpos:near
extrn encode:near, nulref:near, decode:near, nulr:near
extrn errpack:near, updrtr:near, clrmod:near, fcbcpy:near
extrn perpos:near
assume cs:code,ds:datas
; This routine sets up the data for init packet (either the
; Send_init or ACK packet).
RPAR PROC NEAR
mov ah,trans.rpsiz ; Get the receive packet size.
add ah,' ' ; Add a space to make it printable.
mov [bx],ah ; Put it in the packet.
mov ah,trans.rtime ; Get the receive packet time out.
add ah,' ' ; Add a space.
mov 1[bx],ah ; Put it in the packet.
mov ah,trans.rpad ; Get the number of padding chars.
add ah,' '
mov 2[bx],ah ; Put it in the packet.
mov ah,trans.rpadch ; Get the padding char.
add ah,100O ; Uncontrol it.
and ah,7FH
mov 3[bx],ah ; Put it in the packet.
mov ah,trans.reol ; Get the EOL char.
add ah,' '
mov 4[bx],ah ; Put it in the packet.
mov ah,trans.rquote ; Get the quote char.
mov 5[bx],ah ; Put it in the packet.
mov ah,trans.ebquot ; Get 8-bit quote char. [21b]
mov 6[bx],ah ; Add it to the packet. [21b]
mov ah,trans.chklen ; Length of checksum.
add ah,48 ; Make into a real digit.
mov 7[bx],ah
mov ah,rptq ; Repeat quote char.
cmp ah,0 ; Null means no.
jne rpar0
mov ah,' ' ; Send a blank instead.
rpar0: mov 8[bx],ah
mov ah,09H ; Nine pieces of data.
ret
RPAR ENDP
; This routine reads in all the send_init packet information.
SPAR PROC NEAR
cmp ax,1
jge sparx
mov ah,dspsiz ; Data not supplied by host, use default.
jmp sparx2
sparx: mov temp4,ax ; Save the number of arguments.
mov ah,trans.spsiz
cmp ah,dspsiz ; Is current value the default?
jne sparx2 ; No, assume changed by user.
mov ah,[bx] ; Get the max packet size.
sub ah,' ' ; Subtract a space.
cmp ah,spmin ; Can't be below the minimum.
jge sparx1
mov ah,spmin
jmp sparx2
sparx1: cmp ah,spmax ; Or above the maximum.
jle sparx2
mov ah,spmax
sparx2: mov trans.spsiz,ah ; Save it.
mov ax,temp4
cmp al,2 ; Fewer than two pieces?
jge spar0
mov ah,dstime ; Data not supplied by host, use default.
jmp spar02
spar0: mov ah,trans.stime
cmp ah,dstime ; Is current value the default?
jne spar02 ; No, assume changed by user.
mov ah,1[bx] ; Get the timeout value.
sub ah,' ' ; Subtract a space.
cmp ah,0
ja spar01 ; Must be non-negative.
mov ah,0
spar01: cmp ah,trans.rtime ; Same as other side's timeout.
jne spar02
add ah,5 ; If so, make it a little different.
spar02: mov trans.stime,ah ; Save it.
mov ax,temp4
cmp al,3 ; Fewer than three pieces?
jge spar1
mov ah,dspad ; Data not supplied by host, use default.
jmp spar11
spar1: mov ah,trans.spad
cmp ah,dspad ; Is current value the default?
jne spar11 ; No, assume changed by user.
mov ah,2[bx] ; Get the number of padding chars.
sub ah,' '
cmp ah,0
ja spar11 ; Must be non-negative.
mov ah,0
spar11: mov trans.spad,ah
mov ax,temp4
cmp al,4 ; Fewer than four pieces?
jge spar2
mov ah,dspadc ; Data not supplied by host, use default.
jmp spar21
spar2: mov ah,trans.spadch
cmp ah,dspadc ; Is current value the default?
jne spar21 ; No, assume changed by user.
mov ah,3[bx] ; Get the padding char.
add ah,100O ; Re-controlify it.
and ah,7FH
cmp ah,del ; Delete?
je spar21 ; Yes, then it's OK.
cmp ah,0
jge spar20
mov ah,0 ; Below zero is no good.
jmp spar21 ; Use zero (null).
spar20: cmp ah,31 ; Is it a control char?
jle spar21 ; Yes, then OK.
mov ah,0 ; No, use null.
spar21: mov trans.spadch,ah
mov ax,temp4
cmp al,5 ; Fewer than five pieces?
jge spar3
mov ah,dseol ; Data not supplied by host, use default.
jmp spar31
spar3: mov ah,trans.seol
cmp ah,dseol ; Is current value the default?
jne spar31 ; No, assume changed by user.
mov ah,4[bx] ; Get the EOL char.
sub ah,' '
cmp ah,0
jge spar30 ; Cannot be negative.
mov ah,cr ; If it is, use default of carriage return.
jmp spar31
spar30: cmp ah,31 ; Is it a control char?
jle spar31 ; Yes, then use it.
mov ah,cr ; Else, use the default.
spar31: mov trans.seol,ah
mov ax,temp4
cmp al,6 ; Fewer than six pieces?
jge spar4
mov ah,dsquot ; Data not supplied by host, use default.
jmp spar41
spar4: mov ah,trans.squote
cmp ah,dsquot ; Is current value the default?
jne spar41 ; No, assume changed by user.
mov ah,5[bx] ; Get the quote char.
cmp ah,' ' ; Less than a space?
jge spar40
mov ah,dsquot ; Yes, use default.
jmp spar41
spar40: cmp ah,'~' ; Must also be less then a tilde.
jle spar41
mov ah,dsquot ; Else, use default.
spar41: mov trans.squote,ah
cmp al,7 ; Fewer than seven pieces? [21b begin]
jge spar5
mov trans.ebquot,'Y' ; Data not supplied by host, use default.
jmp spar51
spar5: mov ah,6[bx] ; Get other sides 8-bit quote request.
call doquo ; And set quote char. [21b end]
spar51: cmp al,8 ; Fewer than eight pieces?
jge spar6
mov trans.chklen,1
jmp spar61
spar6: mov ah,inichk
mov trans.chklen,ah ; Checksum length we really want to use.
mov ah,7[bx] ; Get other sides checksum length.
call dochk ; Determine what size to use.
spar61: cmp al,9 ; Fewer than nine pieces?
jge spar7
mov rptq,0
ret
spar7: mov ah,8[bx] ; Get other sides repeat count prefix.
mov ch,drpt
mov rptq,0
call dorpt
ret
SPAR ENDP
; Set 8-bit quote character based on my capabilities and the other
; Kermit's request. [21b]
DOQUO PROC NEAR
cmp trans.ebquot,'N' ; Can I do 8-bit quoting at all?
je dq3 ; No - so forget it.
cmp trans.ebquot,'Y' ; Can I do it if requested?
jne dq0 ; No - it's a must that I do it.
mov trans.ebquot,ah ; Do whatever he wants.
jmp dq1
dq0: cmp ah,'Y' ; I need quoting - can he do it?
je dq1 ; Yes - then all is settled.
cmp ah,'N' ; No - then don't quote.
je dq3
cmp ah,trans.ebquot ; Both need quoting - chars must match.
jne dq3
dq1: mov ah,trans.ebquot
cmp ah,'Y' ; If Y or N, don't validate prefix.
je dq2
cmp ah,'N'
je dq2
call prechk ; Is it in range 33-62, 96-126?
mov ah,'Y' ; Failed, don't do quoting.
nop
cmp ah,trans.rquote ; Same prefix?
je dq3 ; Not allowed, so don't do quoting.
cmp ah,trans.squote ; Same prefix here?
je dq3 ; This is illegal too.
mov trans.ebquot,ah ; Remember what we decided on.
dq2: ret
dq3: mov trans.ebquot,'N' ; Quoting will not be done.
ret
DOQUO ENDP
; Check if prefix in AH is in the proper range: 33-62, 96-126.
; RSKP if so else RETURN.
prechk: cmp ah,33
jge prec0 ; It's above 33.
ret
prec0: cmp ah,62
jg prec1
jmp rskp ; And below 62. OK.
prec1: cmp ah,96
jge prec2 ; It's above 96.
ret
prec2: cmp ah,126
jg prec3
jmp rskp ; And below 126. OK.
prec3: ret
; Set checksum length.
dochk: cmp ah,'1' ; Must be 1, 2, or 3.
jl doc1
cmp ah,'3'
jle doc2
doc1: mov ah,'1'
doc2: sub ah,48 ; Don't want it printable.
cmp ah,trans.chklen ; Do we want the same thing?
je dochk0 ; Yes, then we're done.
mov trans.chklen,1 ; No, use single character checksum.
dochk0: ret ; Just return for now.
; Set repeat count quote character. The one used must be different than
; the control and eight-bit quote characters. Also, both sides must
; use the same character.
dorpt: call prechk ; Is it in the valid range?
mov ah,0 ; No, don't use their value.
nop
cmp ah,trans.squote ; Same as the control quote char?
je dorpt0 ; Yes, that's illegal, no repeats.
cmp ah,trans.rquote ; How about this one?
je dorpt0 ; No good.
cmp ah,trans.ebquot ; Same as eight bit quote char?
je dorpt0 ; Yes, that's illegal too, no repeats.
cmp ah,ch ; Are we planning to use the same char?
jne dorpt0 ; No, that's no good either.
mov rptq,ch ; Use repeat quote char now.
dorpt0: ret
; Send command
SEND PROC NEAR
mov comand.cmcr,0 ; Filename must be specified.
mov difnam,0 ; Assume we'll use original filename.
mov flags.wldflg,0 ; Re-initialize every time.
mov ah,cmifi ; Parse an input file spec.
mov dx,offset fcb ; Give the address for the FCB.
mov bx,offset filhlp ; Text of help message.
call comnd
jmp r ; Give up on bad parse.
cmp flags.wldflg,0FFH ; Any wildcards seen?
je send1 ; Yes, get a confirm.
mov bx,offset sendas ; See if want to send file under dif name.
mov dx,offset filmsg ; In case user needs help.
mov ah,cmtxt
call comnd
jmp r
cmp ah,0 ; Different name supplied?
je send11 ; No - keep as it.
mov difnam,1 ; Yes - send different filename.
mov difsiz,ah ; Remember length of new name.
jmp send11
send1: mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
send11: mov flags.droflg,0 ; Reset flags from fn parsing. [21a]
mov flags.nmoflg,0 ; Reset flags from fn parsing. [21a]
mov ah,sfirst ; Get the first file.
mov dx,offset fcb
int dos
cmp al,0FFH ; Any found?
jne send12
cmp pack.state,'R' ; was this from a remote GET?
jne sen11a ; no, print error and continue
mov bx,offset remmsg1 ; else get error message
call errpack ; go complain
jmp abort ; and abort this
sen11a: mov ah,prstr
mov dx,offset crlf
int dos
mov ah,prstr
mov dx,offset erms15
int dos
ret
send12: cmp flags.wldflg,0 ; Any wildcards. [7 start]
je send16 ; Nope, so no problem.
mov bx,offset fcb ; Remember what FCB looked like.
mov di,offset cpfcb
mov cl,37 ; Size of FCB.
call fcbcpy
mov di,offset fcb+1 ; Copy filename from DTA to FCB.
mov bx,offset buff+1
mov cl,11
call fcbcpy ; [7 end]
send16: call serini ; Initialize serial port. [14]
mov pack.pktnum,0 ; Set the packet number to zero.
mov pack.numtry,0 ; Set the number of tries to zero.
mov pack.numpkt,0 ; Set the number of packets to zero.
mov pack.numrtr,0 ; Set the number of retries to zero.
mov pack.state,'S' ; Set the state to receive initiate.
cmp flags.remflg,0 ; remote mode?
jne send2a ; yes, continue below.
call init ; Clear the line and initialize the buffers.
call rtpos ; Position cursor.
mov ax,0
call nout ; Write the number of retries.
call stpos ; Print status of file transfer.
mov ah,prstr ; Be informative.
mov dx,offset infms2
int dos
send2: cmp flags.remflg,0 ; remote mode?
jne send2a ; yes, skip printing
call nppos ; Number of packets sent.
mov ax,pack.numpkt
call nout ; Write the packet number.
send2a: cmp pack.state,'D' ; Are we in the data send state?
jne send3
call sdata
jmp send2
send3: cmp pack.state,'F' ; Are we in the file send state?
jne send4
call sfile ; Call send file.
jmp send2
send4: cmp pack.state,'Z' ; Are we in the EOF state?
jne send5
call seof
jmp send2
send5: cmp pack.state,'S' ; Are we in the send initiate state?
jne send6
call sinit
jmp send2
send6: cmp pack.state,'B' ; Are we in the eot state?
jne send7
call seot
jmp send2
send7: cmp pack.state,'C' ; Are we in the send complete state?
jne send8
call serrst ; Reset serial port. [14]
cmp flags.remflg,0 ; remote mode?
jne send7a ; yes, no printing.
cmp flags.cxzflg,0 ; completed normally?
jne send7b ; no, don't bother with this
call perpos
mov ah,prstr
mov dx,offset infms7
int dos
send7b: call stpos
mov ah,prstr
mov dx,offset infms3 ; Plus a little cuteness.
cmp flags.cxzflg,0 ; Completed or interrupted?
je snd71 ; Ended normally.
mov dx,offset infms6 ; Say was interrupted.
snd71: int dos ; New label.
cmp flags.belflg,0 ; Bell desired? [17a]
je sendnb ; [17a]
mov dx,offset ender ; Ring them bells. [4]
int dos
sendnb: call clrmod
call rprpos
send7a: jmp rskp
send8: call serrst ; Reset serial port. [14]
cmp flags.remflg,0 ; remote mode?
jne send9a ; no, no printing.
call stpos
mov ah,prstr
mov dx,offset infms4 ; Plus a little cuteness.
int dos
cmp flags.belflg,0 ; Bell desired? [17a]
je send9 ; No. [17a]
mov dx,offset ender ; Ring them bells. [4]
int dos ; [4]
send9: call clrmod
call rprpos
send9a: jmp rskp
SEND ENDP
; Send routines
; Send initiate
SINIT PROC NEAR
cmp pack.numtry,imxtry ; Have we reached the maximum number of tries?
jl sinit2
call erpos
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
mov bx,offset erms20
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
sinit2: inc pack.numtry ; Save the updated number of tries.
mov bx,offset data ; Get a pointer to our data block.
call rpar ; Set up the parameter information.
xchg ah,al
mov ah,0
mov pack.argbk1,ax ; Save the number of arguments.
mov ax,pack.numpkt ; Get the packet number.
mov pack.argblk,ax
mov ah,trans.chklen
mov curchk,ah ; Store checksum length we want to use.
mov trans.chklen,1 ; Send init checksum is always 1 char.
mov ah,'S' ; Send initiate packet.
call spack ; Send the packet.
jmp abort
call rpack ; Get a packet.
jmp sini23 ; Trashed packet don't change state, retry.
push ax
mov ah,curchk
mov trans.chklen,ah ; Checksum length we want to use.
pop ax
cmp ah,'Y' ; ACK?
jne sinit3 ; If not try next.
mov ax,pack.pktnum ; Get the packet number.
cmp ax,pack.argblk ; Is it the right packet number?
je sini22
ret ; If not try again.
sini22: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pack.pktnum,ax ; Save modulo 64 of the number.
inc pack.numpkt ; Increment the number of packets.
mov ax,pack.argbk1 ; Get the number of pieces of data.
mov bx,offset data ; Pointer to the data.
call spar ; Read in the data.
call packlen ; Get max send packet size. [21b]
mov ah,pack.numtry ; Get the number of tries.
mov pack.oldtry,ah ; Save it.
mov pack.numtry,0 ; Reset the number of tries.
mov pack.state,'F' ; Set the state to file send.
call getfil ; Open the file.
jmp abort ; Something is wrong, die.
ret
sini23: mov ah,curchk ; Restore desired checksum length.
mov trans.chklen,ah
call updrtr ; Update retry counter.
ret ; And retry.
sinit3: cmp ah,'N' ; NAK?
jne sinit4 ; If not see if its an error.
call rtpos ; Position cursor.
inc pack.numrtr ; Increment the number of retries
mov ax,pack.numrtr
call nout ; Write the number of retries.
ret
sinit4: cmp ah,'E' ; Is it an error packet.
jne sinit5
call error
sinit5: jmp abort
SINIT ENDP
; Send file header
SFILE PROC NEAR
cmp pack.numtry,maxtry ; Have we reached the maximum number of tries?
jl sfile1
call erpos
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
mov bx,offset erms21
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
sfile1: inc pack.numtry ; Increment it.
mov flags.cxzflg,0 ; Clear ^X,^Z flag.
mov datptr,offset data ; Get a pointer to our data block.
mov bx,offset fcb+1 ; Pointer to file name in FCB.
mov fcbpt,bx ; Save position in FCB.
mov cl,0 ; Counter for chars in file name.
mov ch,0 ; Counter for number of chars in FCB.
sfil11: cmp ch,8H ; Ninth char?
jne sfil12
mov ah,'.'
mov bx,datptr
mov [bx],ah ; Put dot in data packet.
inc bx
mov datptr,bx ; Save new position in data packet.
inc cl
sfil12: inc ch
cmp ch,0CH ; Twelve?
jns sfil13
mov bx,fcbpt
mov ah,[bx] ; Get char of filename.
inc bx
mov fcbpt,bx ; Save position in FCB.
cmp ah,'!' ; Is it a good char?
jl sfil11 ; If not, get the next.
mov bx,datptr
mov [bx],ah ; Put char in data buffer.
inc cl ; Increment counter.
inc bx
mov datptr,bx ; Save new position.
jmp sfil11 ; Get another char.
sfil13: mov ch,0
cmp flags.remflg,0 ; remote mode?
jne sfil13a ; yes, no printing.
push cx ; Don't forget the size.
mov bx,datptr
mov ah,'$'
mov [bx],ah ; Put dollar sign for printing.
call clrfln
mov ah,prstr
mov dx,offset data ; Print file name.
int dos
pop cx
sfil13a:cmp difnam,0 ; Sending file under different name.
je sfl13x ; No, so don't give new name.
call newfn
sfl13x: call doenc ; Do encoding.
mov ax,pack.pktnum ; Get the packet number.
mov pack.argblk,ax
mov ah,'F' ; File header packet.
call spack ; Send the packet.
jmp abort
call rpack ; Get a packet.
jmp tryagn ; Trashed packet don't change state, retry.
call dodec ; Do all decoding.
cmp ah,'Y' ; ACK?
jne sfile2 ; If not try next.
mov ax,pack.pktnum ; Get the packet number.
cmp ax,pack.argblk
je sfil14
ret ; If not hold out for the right one.
sfil14: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pack.pktnum,ax ; Save modulo 64 of the number.
inc pack.numpkt ; Increment the number of packets.
mov ah,pack.numtry ; Get the number of tries.
mov pack.oldtry,ah ; Save it.
mov pack.numtry,0 ; Reset the number of tries.
sfil15: mov ah,0 ; Get a zero.
mov bx,offset fcb
add bx,20H
mov [bx],ah ; Set the record number to zero.
; mov flags.eoflag,ah ; Indicate not EOF. (Done in GETFIL).
mov ah,0FFH
mov flags.filflg,ah ; Indicate file buffer empty.
call gtchr
jmp sfil16 ; Error go see if its EOF.
nop
jmp sfil17 ; Got the chars, proceed.
sfil16: cmp ah,0FFH ; Is it EOF?
je sfl161
jmp abort ; If not give up.
sfl161: mov ah,'Z' ; Set the state to EOF.
mov pack.state,ah
ret
sfil17: mov siz,ax
mov pack.state,'D' ; Set the state to data send.
ret
sfile2: cmp ah,'N' ; NAK?
jne sfile3 ; Try if error packet.
call rtpos ; Position cursor.
inc pack.numrtr ; Increment the number of retries
mov ax,pack.numrtr
call nout ; Write the number of retries.
mov ax,pack.pktnum ; Get the present packet number.
inc ax ; Increment.
and ax,03FH ; Account for wraparound. [18]
cmp ax,pack.argblk ; Is the packet's number one more than now?
jz sfil14 ; Just as good as a ACK; go to the ACK code.
ret ; If not go try again.
sfile3: cmp ah,'E' ; Is it an error packet.
jne sfile4
call error
sfile4: jmp abort
SFILE ENDP
; Send data
SDATA PROC NEAR
cmp flags.cxzflg,0 ; Have we seen ^X or ^Z?
je sdata2 ; Nope, just continue.
cmp flags.cxzflg,'C' ; Stop it all? [25]
jne sdata1 ; It was a ^X or ^Z.
mov pack.state,'A' ; It was a ^C -- abort [25]
ret
sdata1: mov pack.state,'Z' ; Else, abort sending the file.
ret
sdata2: cmp pack.numtry,maxtry ; Have we reached the maximum number of tries?
jl sdata3
call erpos
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
mov bx,offset erms22
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
sdata3: inc pack.numtry ; Increment it.
mov datptr,offset data ; Get a pointer to our data block.
mov chrptr,offset filbuf ; Pointer to chars to be sent.
mov cx,siz ; number to transfer
mov si,chrptr ; source of characters
mov di,datptr ; destination
cmp flags.eofcz,0 ; stopping on ctl-z's?
jz sdata6 ; no, do blind copy
sdata4: lodsb ; get a byte
cmp al,'Z'-40H ; is it a ctl-z?
je sdata5 ; yes, break loop
stosb ; else copy it
loop sdata4 ; and keep going
sdata5: mov ax,siz ; size to send
sub ax,cx ; minus actually sent...
jmp short sdata7
sdata6: rep movsb ; just copy data
mov ax,siz ; this is how many were moved
sdata7: mov pack.argbk1,ax
mov ax,pack.pktnum ; Get the packet number.
mov pack.argblk,ax
mov ah,'D' ; Data packet.
call spack ; Send the packet.
jmp tryagn ; if can't send it, retry before giving up
call rpack ; Get a packet.
jmp tryagn ; Trashed packet don't change state, retry.
call dodec ; Do all decoding.
cmp ah,'Y' ; ACK?
jne sdat14 ; If not try next.
mov ax,pack.pktnum ; Get the packet number.
cmp ax,pack.argblk ; Is it the right packet number?
jz sdata8
ret ; If not hold out for the right one.
sdata8: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pack.pktnum,ax ; Save modulo 64 of the number.
inc pack.numpkt ; Increment the number of packets.
mov ah,pack.numtry ; Get the number of tries.
mov pack.oldtry,ah ; Save it.
mov pack.numtry,0 ; Reset the number of tries.
cmp pack.argbk1,1 ; Does the ACK contain data?
jne sdat11 ; Nope, so continue.
mov bx,offset data ; If yes, check the data field.
mov ah,[bx] ; Pick it up.
cmp ah,'X' ; Other side requests ^X?
jne sdata9 ; Nope.
jmp sdat10 ; And leave.
sdata9: cmp ah,'Z' ; Other side requests ^Z?
jne sdat11 ; Nope.
sdat10: mov flags.cxzflg,ah ; Yes remember it.
mov pack.state,'Z' ; Abort sending file(s).
ret
sdat11: call gtchr
jmp sdat12 ; Error go see if its EOF.
mov siz,ax ; Save the size of the data gotten.
ret
sdat12: cmp ah,0FFH ; Is it EOF?
je sdat13
jmp abort ; If not give up.
sdat13: mov pack.state,'Z' ; Set the state to EOF.
ret
sdat14: cmp ah,'N' ; NAK?
jne sdat15 ; See if is an error packet.
call rtpos ; Position cursor.
inc pack.numrtr ; Increment the number of retries
mov ax,pack.numrtr
call nout ; Write the number of retries.
mov ax,pack.pktnum ; Get the present packet number.
inc ax ; Increment.
and ax,03FH ; Account for wraparound. [18]
cmp ax,pack.argblk ; Is the packet's number one more than now?
jz sdata8 ; Just as good as ACK; goto ACK code.
ret ; If not go try again.
sdat15: cmp ah,'E' ; Is it an error packet.
jne sdat16
call error
sdat16: jmp abort
SDATA ENDP
; Send EOF
SEOF PROC NEAR
cmp pack.numtry,maxtry ; Have we reached the maximum number of tries?
jl seof1
call erpos ; Position cursor.
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
mov bx,offset erms23
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
seof1: inc pack.numtry ; Increment it.
mov ax,pack.pktnum ; Get the packet number.
mov pack.argblk,ax
mov pack.argbk1,0 ; No data.
cmp flags.cxzflg,0 ; Seen a ^X or ^Z?
je seof11 ; Nope, send normal EOF packet.
mov bx,offset data ; Get data area of packet.
mov ah,'D' ; Use "D" for discard.
mov [bx],ah ; And add it to the packet.
mov pack.argbk1,1 ; Set data size to 1.
seof11: mov cx,pack.argbk1 ; Put size in CX.
call doenc ; Encode the packet.
mov ah,'Z' ; EOF packet.
call spack ; Send the packet.
jmp abort
call rpack ; Get a packet.
jmp tryagn ; Trashed packet don't change state, retry.
call dodec ; Do decoding.
cmp ah,'Y' ; ACK?
jne seof2 ; If not try next.
mov ax,pack.pktnum ; Get the packet number.
cmp ax,pack.argblk ; Is it the right packet number?
jz seof12
ret ; If not hold out for the right one.
seof12: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pack.pktnum,ax ; Save modulo 64 of the number.
inc pack.numpkt ; Increment the number of packets.
mov ah,pack.numtry ; Get the number of tries.
mov pack.oldtry,ah ; Save it.
mov pack.numtry,0 ; Reset the number of tries.
mov ah,closf ; Close the file.
mov dx,offset fcb
int dos
call gtnfil ; Get the next file.
jmp seof13 ; No more.
mov pack.state,'F' ; Set the state to file send.
cmp flags.cxzflg,'X' ; Control-X seen?
jne seof14
call cxmsg ; Clear out the interrupt msg.
seof14: mov flags.cxzflg,0 ; Reset the flag.
ret
seof13: mov pack.state,'B' ; Set the state to EOT.
ret
seof2: cmp ah,'N' ; NAK?
jne seof3 ; Try and see if its an error packet.
call rtpos ; Position cursor.
inc pack.numrtr ; Increment the number of retries
mov ax,pack.numrtr
call nout ; Write the number of retries.
mov ax,pack.pktnum ; Get the present packet number.
inc ax ; Increment.
and ax,03FH ; Account for wraparound. [18]
cmp ax,pack.argblk ; Is the packet's number one more than now?
jz seof12 ; Just as good as a ACK; go to the ACK code.
ret ; If not go try again.
seof3: cmp ah,'E' ; Is it an error packet?
jne seof4
call error
seof4: jmp abort
SEOF ENDP
; Send EOT
SEOT PROC NEAR
cmp pack.numtry,maxtry ; Have we reached the maximum number of tries?
jl seot1
call erpos ; Position cursor.
mov dx,offset erms14
mov ah,prstr
int dos ; Print an error message.
mov bx,offset erms24
call errpack ; Send error packet just in case.
jmp abort ; Change the state to abort.
seot1: inc pack.numtry ; Increment it.
mov ax,pack.pktnum ; Get the packet number.
mov pack.argblk,ax
mov pack.argbk1,0 ; No data.
mov cx,pack.argbk1
call doenc ; Encode packet.
mov ah,'B' ; EOF packet.
call spack ; Send the packet.
jmp abort
call rpack ; Get a packet.
jmp tryagn ; Trashed packet don't change state, retry.
call dodec ; Decode packet.
cmp ah,'Y' ; ACK?
jne seot2 ; If not try next.
mov ax,pack.pktnum ; Get the packet number.
cmp ax,pack.argblk ; Is it the right packet number?
jz seot12
ret ; If not hold out for the right one.
seot12: inc ax ; Increment the packet number.
and ax,3FH ; Turn off the two high order bits.
mov pack.pktnum,ax ; Save modulo 64 of the number.
inc pack.numpkt ; Increment the number of packets.
mov ah,pack.numtry ; Get the number of tries.
mov pack.oldtry,ah ; Save it.
mov pack.numtry,0 ; Reset the number of tries.
mov pack.state,'C' ; Set the state to file send.
ret
seot2: cmp ah,'N' ; NAK?
jne seot3 ; Is it error.
call rtpos ; Position cursor.
inc pack.numrtr ; Increment the number of retries
mov ax,pack.numrtr
call nout ; Write the number of retries.
mov ax,pack.pktnum ; Get the present packet number.
inc ax ; Increment.
and ax,03FH ; Account for wraparound. [18]
cmp ax,pack.argblk ; Is the packet's number one more than now?
jz seot12 ; Just as good as a ACK; go to the ACK code.
ret ; If not go try again.
seot3: cmp ah,'E' ; Is it an error packet.
jne seot4
call error
seot4: jmp abort
SEOT ENDP
tryagn: call updrtr
ret
newfn: mov ah,prstr
mov dx,offset asmsg
int dos
mov ah,dconio
mov si,offset sendas ; Buffer where the name is.
mov di,offset data
mov ch,0
mov cl,difsiz ; Length of name.
newf0: lodsb ; Get a char.
cmp al,61H
jb newf1 ; Leave alone if less than 'a'?
cmp al,7AH
ja newf1 ; Leave alone if over 'z'.
sub al,20H ; Uppercase the letters.
newf1: stosb
mov dl,al
cmp flags.remflg,0 ; should we print?
jne newf2 ; no, we're in remote mode.
int dos ; Print them.
newf2: loop newf0
mov ch,0
mov cl,difsiz ; Reset the length field.
ret
; Do encoding. Expectx CX to be the data size.
doenc: jcxz doen0
mov chrcnt,cx ; Number of chars in filename.
mov bx,offset data ; Source of data.
mov bufpnt,bx
mov bx,offset nulref ; Null routine for refilling buffer.
mov ah,rptq
mov origr,ah ; Save repeat prefix here.
mov rptct,1 ; Number of times char is repeated.
mov rptval,0 ; Value of repeated char.
call encode ; Make a packet with size in AX.
nop
nop
nop
mov pack.argbk1,ax ; Save number of char in filename.
mov cx,ax
call movpak ; Move to data part of packet.
doen0: ret
; CX is set before this is called.
movpak: push es
mov ax,ds
mov es,ax
mov si,offset filbuf ; Move from here
mov di,offset data ; to here
repne movsb
pop es
ret
; Do decoding.
dodec: cmp pack.argbk1,0
je dodc0
push ax ; Save packet size.
mov cx,pack.argbk1 ; Size of data.
mov bx,offset data ; Address of data.
mov ax,offset nulr ; Routine to dump buffer (null routine).
mov bufpnt,offset decbuf ; Where to put output.
mov chrcnt,80H ; Buffer size.
call decode
nop
nop
nop
call decmov ; Move decoded data back to "data" buffer.
pop ax
dodc0: ret
; Move decoded data from decode buffer back to "data".
decmov: push si
push di
push es
mov ax,ds
mov es,ax
mov cx,bufpnt ; Last char we added.
sub cx,offset decbuf ; Get actual number of characters.
mov pack.argbk1,cx ; Remember size of real data.
lea si,decbuf ; Data is here.
lea di,data ; Move to here.
repne movsb ; Copy the data.
pop es
pop di
pop si
ret
; Abort
ABORT PROC NEAR
mov pack.state,'A' ; Otherwise abort.
ret
ABORT ENDP
; This is where we go if we get an error packet. A call to ERROR
; positions the cursor and prints the message. A call to ERROR1
; just prints a CRLF and then the message. [8]
ERROR PROC NEAR
mov pack.state,'A' ; Set the state to abort.
call erpos ; Position the cursor.
jmp error2
error1: mov ah,prstr
mov dx,offset crlf
int dos
error2: mov bx,pack.argbk1 ; Get the length of the data.
add bx,offset data ; Get to the end of the string.
mov ah,'$' ; Put a dollar sign at the end.
mov [bx],ah
mov ah,prstr ; Print the error message.
mov dx,offset data
int dos
ret
ERROR ENDP
; Set the maximum data packet size. [21b]
PACKLEN PROC NEAR
mov ah,trans.spsiz ; Maximum send packet size.
sub ah,4 ; Size minus control info.
sub ah,trans.chklen ; And minus checksum chars.
sub ah,2 ; Leave room at end: 2 for possible #X.
cmp trans.ebquot,'N' ; Doing 8-bit quoting?
je pack0 ; Nope so we've got our size.
cmp trans.ebquot,'Y'
je pack0 ; Not doing it in this case either.
sub ah,1 ; Another 1 for 8th-bit quoting.
pack0: cmp rptq,0 ; Doing repeat character quoting?
je pack1 ; Nope, so that's all for now.
sub ah,2 ; Another 2 for repeat prefix.
pack1: mov trans.maxdat,ah ; Save max length for data field.
ret
PACKLEN ENDP
; Print the number in AX on the screen in decimal rather that hex. [19a]
NOUT PROC NEAR
cmp flags.xflg,1 ; Writing to screen? [21c]
je nout1 ; Yes, just leave. [21c]
push ax
push dx
mov temp,10 ; Divide quotient by 10.
; cwd ; Convert word to doubleword.
mov dx,0 ; High order word should be zero.
div temp ; AX <-- Quo, DX <-- Rem.
cmp ax,0 ; Are we done?
jz nout0 ; Yes.
call nout ; If not, then recurse.
nout0: add dl,'0' ; Make it printable.
mov temp,ax
mov ah,conout
int dos
mov ax,temp
pop dx
pop ax
nout1: ret ; We're done. [21c]
NOUT ENDP
; 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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 mssend.asm
/bin/echo -n ' '; /bin/ls -ld mssend.asm
fi
/bin/echo 'Extracting msserv.asm'
sed 's/^X//' <<'//go.sysin dd *' >msserv.asm
public logout, bye, finish, remote, get, server
include msdefs.h
datas segment public 'datas'
extrn data:byte, flags:byte, trans:byte, pack:byte, curchk:byte
extrn fcb:byte
remcmd db 0 ; Remote command to be executed. [21c]
rempac db 0 ; Packet type: C (host) or G (generic). [21c]
cmer05 db cr,lf,'?Filename must be specified$' ; [21a]
ermes7 db '?Unable to receive initiate$'
erms18 db cr,lf,'?Unable to tell host that session is finished$'
erms19 db cr,lf,'?Unable to tell host to logout$'
erms21 db cr,lf,'?Unable to tell host to execute command$' ; [21c]
infms1 db 'Entering server mode',cr,lf,'$'
remms1 db 'Kermit-MS: Unknown server command$'
remms2 db 'Kermit-MS: Illegal file name$'
remms3 db 'Kermit-MS: Unknown generic command$'
pass db lf,cr,' Password: $' ; When change directory. [21c]
crlf db cr,lf,'$'
tmp db ?,'$'
temp dw 0
oloc dw 0 ; Original buffer location. [21c]
osiz dw 0 ; Original buffer size. [21c]
inpbuf dw 0 ; Pointer to input buffer. [21c]
cnt dw 0
delinp db BS,BS,BS,' ',BS,BS,BS,'$' ; When DEL key is used. [21d]
clrspc db ' ',10O,'$' ; Clear space.
srvchr db 'SRGIE' ; server cmd characters
srvfln equ $-srvchr ; length of tbl
srvfun dw srvsnd,srvrcv,srvgen,srvini,serv1
remhlp db cr,lf,'CWD connect to a directory' ; [21c start]
db cr,lf,'DELETE a file'
db cr,lf,'DIRECTORY listing'
db cr,lf,'HELP'
db cr,lf,'HOST command'
db cr,lf,'SPACE in a directory'
db cr,lf,'TYPE a file$' ; [21c end]
remtab db 07H ; Seven entries. [21c start]
mkeyw 'CWD',remcwd
mkeyw 'DELETE',remdel
mkeyw 'DIRECTORY',remdir
mkeyw 'HELP',remhel
mkeyw 'HOST',remhos
mkeyw 'SPACE',remdis
mkeyw 'TYPE',remtyp ; [21c end]
remfnm db ' Remote Source File: $'
lclfnm db ' Local Destination File: $'
filhlp db ' File name to receive as$'
filmsg db ' Remote file specification or confirm with carriage return $'
frem db ' Name of file on remote system $'
genmsg db ' Enter text to be sent to remote server $'
rdbuf db 80H DUP(?)
datas ends
code segment public
extrn comnd:near, serrst:near, spack:near, rpack5:near, init:near
extrn read12:near, serini:near, read2:near, rpar:near, spar:near
extrn rin21:near, rfile3:near, error1:near, clrfln:near
extrn dodel:near, clearl:near, dodec: near, doenc:near
extrn packlen:near, send11:near, errpack:near, init1:near
extrn rpack:near,nak:near, rrinit:near, cmblnk:near
extrn error:near, erpos:near, rprpos:near, clrmod:near
extrn prompt:near
assume cs:code,ds:datas
; LOGOUT - tell remote KERSRV to logout.
LOGOUT PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r
call logo
jmp rskp ; Go get another command whether we ....
jmp rskp ; .... succeed or fail.
LOGOUT ENDP
LOGO PROC NEAR
mov pack.numtry,0 ; Initialize count.
mov pack.numrtr,0 ; No retries yet.
call serini ; Initialize port. [14]
mov ah,trans.chklen ; Don't forget the checksum length.
mov curchk,ah
mov trans.chklen,1 ; Use one char for server functions.
logo1: cmp pack.state,'A' ; Did user type a ^C?
je logo2x ; Yes just leave.
mov ah,pack.numtry
cmp ah,maxtry ; Too many times?
js logo3 ; No, try it.
logo2: mov ah,prstr
mov dx,offset erms19
int dos
logo2x: call serrst ; Reset port. [14]
mov ah,curchk
mov trans.chklen,ah ; Restore value.
ret
logo3: inc pack.numtry ; Increment number of tries.
mov pack.argblk,0 ; Packet number zero.
mov pack.argbk1,1 ; One piece of data.
mov bx,offset data
mov ah,'L'
mov [bx],ah ; Logout the remote host.
mov cx,1 ; One piece of data.
call doenc ; Do encoding.
mov ah,'G' ; Generic command packet.
call spack
jmp logo2 ; Tell user and die.
nop
call rpack5 ; Get ACK (w/o screen msgs.)
jmp logo1 ; Go try again.
nop
push ax
call dodec ; Decode packet.
mov ah,curchk
mov trans.chklen,ah ; Restore value.
pop ax
cmp ah,'Y' ; ACK?
jne logo4
call serrst ; Reset port. [14]
jmp rskp
logo4: cmp ah,'E' ; Error packet?
jnz logo1 ; Try sending the packet again.
call error1
call serrst ; Reset port. [14]
ret
LOGO ENDP
; FINISH - tell remote KERSRV to exit.
FINISH PROC NEAR
mov ah,cmcfm ; Parse a confirm.
call comnd
jmp r
mov pack.numtry,0 ; Initialize count.
mov pack.numrtr,0 ; No retries yet.
call serini ; Initialize port. [14]
mov ah,trans.chklen ; Don't forget the checksum length.
mov curchk,ah
mov trans.chklen,1 ; Use one char for server functions.
fin1: cmp pack.state,'A' ; ^C typed?
je fin2x
mov ah,pack.numtry
cmp ah,maxtry ; Too many times?
js fin3 ; Nope, try it.
fin2: mov ah,prstr
mov dx,offset erms18
int dos
fin2x: call serrst ; Reset port. [14]
mov ah,curchk
mov trans.chklen,ah ; Restore value.
jmp rskp ; Go home.
fin3: inc pack.numtry ; Increment number of tries.
mov pack.argblk,0 ; Packet number zero.
mov pack.argbk1,1 ; One piece of data.
mov bx,offset data
mov ah,'F'
mov [bx],ah ; Finish running Kermit.
mov cx,1 ; One piece of data.
call doenc ; Do encoding.
mov ah,'G' ; Generic command packet.
call spack
jmp fin2 ; Tell user and die.
nop
call rpack5 ; Get ACK (w/o screen stuff).
jmp fin1 ; Go try again.
nop
push ax
call dodec ; Decode data.
mov ah,curchk
mov trans.chklen,ah ; Restore value.
pop ax
cmp ah,'Y' ; Got an ACK?
jnz fin4
call serrst ; Reset port. [14]
jmp rskp ; Yes, then we're done.
fin4: cmp ah,'E' ; Error packet?
jnz fin1 ; Try sending it again.
call error1
call serrst ; Reset port. [14]
jmp rskp
FINISH ENDP
; BYE command - tell remote KERSRV to logout & exits to DOS.
BYE PROC NEAR
mov ah,cmcfm ; Parse a confirm.
call comnd
jmp r
call logo ; Tell the mainframe to logout.
jmp rskp ; Failed - don't exit.
mov flags.extflg,1 ; Set exit flag.
jmp rskp ; [8 end]
BYE ENDP
; Tell remote server to send the specified file(s).
get PROC NEAR
mov flags.droflg,0 ; Reset flags from fn parsing.
mov flags.nmoflg,0 ; Reset flags from fn parsing.
mov flags.cxzflg,0 ; no ctl-c typed yet...
mov bx,offset data ; Where to put text. [8 start]
mov dx,offset filmsg ; In case user needs help.
mov ah,cmtxt
call comnd ; Get text or confirm.
jmp r ; Fail.
cmp ah,0 ; Read in any chars?
jne get4 ; Yes, then OK.
; empty line, ask for file names
get1: mov dx,offset remfnm ; ask for remote first
call prompt
mov bx,offset data
mov dx,offset frem
mov ah,cmtxt
call comnd ; get a line of text
jmp r
cmp flags.cxzflg,'C' ; ctl-C typed?
jne get2 ; no, continue
jmp rskp
get2: cmp ah,0
je get1 ; ignore empty lines
mov bl,ah
mov bh,0
mov byte ptr data[bx],'$' ; terminate name for printing
mov pack.argbk1,bx ; remember length here
mov dx,offset lclfnm
call prompt
mov ah,cmifi
mov bx,offset filhlp
mov dx,offset fcb
call comnd
jmp r
mov ah,cmcfm
call comnd
jmp r
cmp flags.cxzflg,'C' ; control-C typed?
jne get3 ; no, keep going
jmp rskp
get3: mov flags.nmoflg,1 ; remember changed name
jmp short get5
get4: mov al,ah
mov ah,0
mov pack.argbk1,ax ; Remember number of chars we read.
mov byte ptr [bx],'$' ; use for printing.
get5: cmp flags.remflg,0 ; remote mode?
jne get6 ; yes, don't print anything
call init ; Clear line and initialize buffers.
call clrfln ; Prepare to print filename.
mov ah,prstr
mov dx,offset data ; Print file name.
int dos
get6: call init1 ; init buffers
mov pack.numtry,0 ; Initialize count.
mov pack.numrtr,0 ; No retries yet.
mov pack.state,'R' ; this is what state will soon be...
call serini ; Initialize port.
mov cx,pack.argbk1 ; Data size.
call doenc ; Encode data.
mov ah,trans.chklen ; Don't forget the checksum length.
mov curchk,ah
mov trans.chklen,1 ; Use one char for server functions.
get7: cmp pack.state,'A' ; Did user type a ^C?
je get9 ; Yes - just return to main loop.
mov ah,pack.numtry
cmp ah,maxtry ; Too many times?
jbe get10 ; Nope, try it.
get8: cmp flags.remflg,0 ; remote mode?
jne get9 ; yes, no printing
call erpos
mov ah,prstr
mov dx,offset ermes7 ; Can't get init packet.
int dos
get9: call serrst ; Reset port.
mov ah,curchk
mov trans.chklen,ah ; Restore value.
jmp rskp ; Go home.
get10: inc pack.numtry ; Increment number of tries.
mov pack.argblk,0 ; Start at packet zero.
mov ah,'R' ; Receive init packet.
call spack ; Send the packet.
jmp get8 ; Tell user we can't do it.
nop
call rpack5 ; Get ACK (w/o screen stuff).
jmp get7 ; Got a NAK - try again.
nop
push ax
mov ah,curchk
mov trans.chklen,ah ; Restore value.
pop ax
mov pack.argbk2,ax ; this is where rinit wants pkt type if getting
mov flags.getflg,1 ; "Get" as vs "Receive".
jmp read12 ; go join read code
get11: mov ah,prstr ; Complain if no filename.
mov dx,offset cmer05
int dos
jmp rskp
GET ENDP
; server command
server proc near
mov ah,cmcfm
call comnd
jmp r
push es
mov ax,ds
mov es,ax ; address data segment
mov al,flags.remflg ; get remote flag
push ax ; preserve for later
mov flags.remflg,1 ; set remote if server
call cmblnk ; clear screen
mov ah,prstr
mov dx,offset infms1
int dos
; should reset to default parms here...
; should increase timeout interval
serv1: call serini ; init serial line (send & recv reset it)
mov trans.chklen,1 ; checksum len = 1
mov pack.pktnum,0 ; pack number resets to 0
mov pack.numtry,0 ; no retries yet.
call rpack ; get a packet
jmp short serv2 ; no good, nak and continue
nop
jmp short serv3 ; try to figure this out
serv2: cmp flags.cxzflg,'C' ; ctl-C?
je serv5 ; yes, stop this.
call nak ; nak the packet
jmp serv1 ; and keep readiserv2 packets
serv3: mov di,offset srvchr ; server characters
mov cx,srvfln ; length of striserv2
mov al,ah ; packet type
repne scasb ; hunt for it
je serv4 ; we know this one, go handle it
mov bx,offset remms1 ; else give a message
call errpack ; back to local kermit
jmp serv1 ; and keep lookiserv2 for a cmd
serv4: sub di,offset srvchr+1 ; find offset, +1 for pre-increment
shl di,1 ; convert to word index.
call srvfun[di] ; call the appropriate handler
jmp serv5 ; someone wanted to exit...
; should we reset serial line?
jmp serv1 ; else keep goiserv2 for more cmds.
serv5:
;** restore timer values
pop ax ; get this off stack
mov flags.remflg,al ; restore old flag
call serrst ; reset serial handler
pop es ; restore register
jmp rskp ; and return
server endp
; server commands.
; srvsnd - receives a file that the local kermit is sending.
srvsnd proc near
mov bx,offset data
call spar ; parse the send-init packet
call packlen ; figure max packet
mov bx,offset data
call rpar ; make answer for them
mov al,ah ; length of packet
mov ah,0
mov pack.argbk1,ax ; store length for spack
mov ah,'Y' ; ack
call spack ; answer them
jmp rskp ; can't answer, forget this
call rrinit ; init variables for init
inc pack.pktnum ; count the send-init packet.
mov pack.state,'F' ; expecting file name about now
call read2 ; and join read code
nop
nop
nop ; ignore errors
jmp rskp ; and return for more
srvsnd endp
; srvrcv - send a file that they're receiving.
srvrcv proc near
mov si,offset data ; this should be filename
mov di,offset fcb ; this is where filename goes
mov al,1 ; skip leading separators
mov ah,prsfcb ; parse an fcb
int dos ; let dos do the work
cmp al,0ffh ; invalid?
jne srvrc1 ; no, keep going
mov bx,offset remms2 ; complain
call errpack ; that we can't find it
jmp rskp ; and return
srvrc1: mov pack.state,'R' ; remember state.
call send11 ; this should send it
jmp rskp
jmp rskp ; return in any case
srvrcv endp
; srvgen - generic server commands.
; We only support Logout and Finish right now.
srvgen proc near
mov al,data ; get 1st packet char
cmp al,'F' ; maybe finish?
je srvge1 ; yup, handle
cmp al,'L' ; logout?
jne srvge2 ; no.
srvge1: mov pack.argbk1,0 ; 0-length data
mov ah,'Y'
call spack ; ack it
nop
nop
nop ; *** ignore error?
ret ; and return to signal exit.
srvge2: mov bx,offset remms3
call errpack
jmp rskp
srvgen endp
; srvini - init parms based on init packet
srvini proc near
mov bx,offset data
call spar ; parse info
call packlen ; this should really be part of spar, but...
mov bx,offset data
call rpar ; get receive info
mov al,ah
mov ah,0
mov pack.argbk1,ax ; set size of return info
mov ah,'Y'
call spack ; send the packet off
jmp rskp
jmp rskp ; and go succeed
srvini endp
; This is the REMOTE command. [21c]
REMOTE PROC NEAR
mov dx,offset remtab ; Parse a keyword from the REMOTE table.
mov bx,offset remhlp
mov ah,cmkey
call comnd
jmp r
call bx ; Call the appropriate routine.
jmp r ; Command failed.
jmp rskp
REMOTE ENDP
; REMDIS - Get disk usage on remote system. [21c]
REMDIS PROC NEAR
mov remcmd,'U' ; Disk usage command.
mov rempac,'G' ; Packet type = generic.
jmp genric ; Execute generic Kermit command.
REMDIS ENDP
; REMHEL - Get help about remote commands. [21c]
REMHEL PROC NEAR
mov remcmd,'H' ; Help......
mov rempac,'G' ; Packet type = generic.
jmp genric ; Execute generic Kermit command.
REMHEL ENDP
; REMTYP - Print a remote file. [21c]
REMTYP PROC NEAR
mov remcmd,'T' ; Type the file.
mov rempac,'G' ; Packet type = generic.
jmp genric
REMTYP ENDP
; REMHOS - Execute a remote host command. [21c]
REMHOS PROC NEAR
mov remcmd,' ' ; Don't need one.
mov rempac,'C' ; Packet type = remote command.
jmp genric
REMHOS ENDP
; REMDIR - Do a directory. [21c]
REMDIR PROC NEAR
mov remcmd,'D'
mov rempac,'G' ; Packet type = generic.
jmp genric
REMDIR ENDP
; REMDEL - Delete a remote file. [21c]
REMDEL PROC NEAR
mov remcmd,'E'
mov rempac,'G' ; Packet type = generic.
jmp genric
REMDEL ENDP
; REMCWD - Change remote working directory. [21c]
REMCWD PROC NEAR
mov remcmd,'C'
mov rempac,'G' ; Packet type = generic.
jmp genric
REMCWD ENDP
; GENRIC - Send a generic command to a remote Kermit server. [21c]
GENRIC PROC NEAR
mov bx,offset rdbuf ; Where to put the text.
cmp rempac,'C' ; Remote host command?
je genra ; Yes, leave as is.
add bx,2 ; Leave room for type and size.
genra: mov ah,cmtxt ; Parse arbitrary text up to a CR.
mov dx,offset genmsg ; In case they want text.
call comnd
jmp r
mov al,ah ; Don't forget the size.
mov ah,0
mov cnt,ax ; Save it here.
cmp rempac,'C' ; Remote host command?
jne genrb ; No, skip this part.
call ipack
jmp genr2
mov pack.numtry,0
mov ah,trans.chklen
mov curchk,ah ; Save desired checksum length.
mov trans.chklen,1 ; Use 1 char for server functions.
mov pack.numrtr,0 ; No retries yet.
jmp genr1 ; Send the packet.
genrb: mov ax,cnt
cmp ax,0 ; Any data?
je genr0 ; Nope.
mov ah,al ; Don't overwrite the real count value.
add ah,32 ; Do the char function.
mov temp,bx ; Remember where we are.
mov bx,offset rdbuf+1 ; Size of remote command.
mov [bx],ah
mov ah,0
inc al ; For the size field.
cmp remcmd,'C' ; Change working directory?
jne genr0 ; No, so don't ask for password.
mov cnt,ax ; Save here for a bit.
mov ah,prstr
mov dx,offset pass ; Send along an optional password.
int dos
mov bx,temp ; Where to put the password.
push bx ; Is safe since subroutine never fails.
inc bx ; Leave room for count field.
call input ; Read in the password.
mov temp,bx ; Remember end of data pointer.
pop bx ; Where to put the size.
cmp ah,0 ; No password given?
jne genrc
mov ax,cnt
jmp genr0 ; Then that's it.
genrc: mov al,ah
add ah,32 ; Make it printable.
mov [bx],ah ; Tell remote host the size.
mov ah,0
push ax ; Remember the count.
call clearl ; Clear to end-of-line.
pop ax
inc al ; For second count value.
add ax,cnt ; Total for both fields of input.
genr0: inc al ; For the char representing the command.
mov pack.argbk1,ax ; Set the size.
mov cnt,ax ; And remember it.
mov pack.numtry,0 ; Initialize count
mov bx,offset rdbuf ; Start of data buffer.
mov ah,remcmd ; Command subtype.
mov [bx],ah
call ipack ; Send init parameters.
jmp genr2
nop ; Make it 3 bytes long.
mov ah,trans.chklen
mov curchk,ah ; Save desired checksum length.
mov trans.chklen,1 ; Use 1 char for server functions.
mov pack.numrtr,0 ; No retries yet.
genr1: cmp pack.state,'A' ; Did the user type a ^C?
je genr2x
mov ah,pack.numtry
cmp ah,maxtry ; Too many tries?
js genr3 ; Nope, keep trying.
genr2: mov ah,prstr
mov dx,offset erms21 ; Print error msg and fail.
int dos
genr2x: call serrst ; Reset the port.
mov ah,curchk
mov trans.chklen,ah ; Restore.
jmp rskp
genr3: push es ; Prepare to put string into packet.
mov ax,ds
mov es,ax
mov si,offset rdbuf ; Move from here
mov di,offset data ; to here.
mov cx,cnt ; Move this many characters.
rep movsb ; Perform the string move.
pop es
mov ax,cnt
mov pack.argbk1,ax ; How much data to send.
mov cx,ax ; Size of data.
call doenc ; Encode it.
inc pack.numtry ; Increment number of trials.
mov pack.argblk,0 ; Packet number 0.
mov ah,rempac ; Packet type.
call spack ; Send the packet.
jmp genr2 ; Tell user we can't do it.
nop
call rpack5 ; Get ACK (w/o screen stuff)
jmp genr1 ; Got a NAK - try again.
nop
push ax
mov ah,curchk
mov trans.chklen,ah ; Restore.
pop ax
cmp ah,'Y' ; Is all OK?
jne genr4
cmp pack.argbk1,0 ; Any data in the ACK?
je genr31 ; Nope - just return.
call dodec ; Decode data.
mov ah,prstr
mov dx,offset crlf ; First go to a new line.
int dos
mov di,offset data ; Where the reply is.
mov cx,pack.argbk1 ; How much data we have.
call prtscr ; Print it on the screen.
genr31: jmp rskp ; And we're done.
genr4: cmp ah,'X' ; Text packet?
je genr5
cmp ah,'S' ; Handling this like a file?
jne genr6
mov pack.state,'R' ; Set the state.
mov bx,offset rin21 ; Where to go to.
jmp genr51 ; Continue.
genr5: mov pack.state,'F'
call dodec ; Decode data.
mov bx,offset rfile3 ; Jump to here.
genr51: mov tmp,ah ; Save packet type.
mov flags.xflg,1 ; Remember we saw an "X" packet.
mov pack.numtry,0
mov pack.numrtr,0
mov pack.numpkt,0
mov pack.pktnum,0
mov flags.cxzflg,0
mov ah,tmp ; Packet type.
call bx ; Handle it almost like filename.
call read2 ; Receive the rest.
jmp r ; Oops, we failed.
jmp rskp ; Done OK.
genr6: cmp ah,'E' ; Error packet?
je genr6x
jmp genr1 ; Try again.
genr6x: call dodec ; Decode data.
call error1 ; Print the error messge.
call serrst
jmp rskp ; And return.
GENRIC ENDP
; Send "I" packet with transmission parameters. [21c]
IPACK PROC NEAR
mov ah,trans.chklen
mov curchk,ah ; Initialize.
call serini
mov pack.pktnum,0 ; Use packet number 0.
mov pack.numtry,0 ; Number of retries.
ipk0: cmp pack.state,'A' ; Did user type a ^C?
je ipk0x
cmp pack.numtry,imxtry ; Reached our limit?
jl ipk1
ipk0x: ret ; Yes, so we fail.
ipk1: inc pack.numtry ; Save the updated number of tries.
mov bx,offset data ; Get a pointer to our data block.
call rpar ; Set up the parameter information.
xchg ah,al
mov ah,0
mov pack.argbk1,ax ; Save the number of arguments.
mov pack.argblk,0 ; Use packet number 0.
mov ah,trans.chklen
mov curchk,ah ; Save real value.
mov trans.chklen,1 ; One char for server function.
mov ah,'I' ; "I" packet.
call spack ; Send the packet.
jmp ipk4
nop
call rpack5 ; Get a packet.
jmp ipk4 ; Try again.
nop
push ax
mov ah,curchk
mov trans.chklen,ah ; Reset.
pop ax
cmp ah,'Y' ; ACK?
jne ipk3 ; If not try next.
mov ax,pack.pktnum ; Get the packet number.
cmp ax,pack.argblk ; Is it the right packet number?
je ipk2
jmp ipk0 ; If not try again.
ipk2: mov ax,pack.argbk1 ; Get the number of pieces of data.
mov bx,offset data ; Pointer to the data.
call spar ; Read in the data.
mov ah,trans.chklen
mov curchk,ah ; This is what we decided on.
call packlen ; Get max send packet size. [21b]
mov pack.numtry,0 ; Reset the number of tries.
jmp rskp
ipk3: cmp ah,'N' ; NAK?
je ipk0 ; Yes, try again.
cmp ah,'E' ; Is it an error packet.
je ipk3x
jmp ipk0 ; Trashed data.
ipk3x: jmp rskp ; Other side doesn't know about "I" packet.
ipk4: mov ah,curchk
mov trans.chklen,ah ; Reset.
jmp ipk0 ; Keep trying.
IPACK ENDP
; Returns in AH the count of characters read in.
; in BX the updated pointer to the input buffer.
INPUT PROC NEAR
mov cl,0 ; Keep a count.
mov inpbuf,bx ; Where to put data.
input0: mov ah,conin ; Read in a char.
int dos
cmp al,CR ; Done with input?
jne input1
mov ah,cl ; Return count in AH.
jmp r
input1: cmp al,BS ; Backspace?
je inpt11 ;
cmp al,DEL ; Or delete?
jne input3
call dodel ; Erase weird character.
inpt11: dec cl ; Don't include in char count.
cmp cl,0 ; Backspaced too much?
jns input2 ; No, is OK.
push bx
call clearl
pop bx
mov ah,conout
mov dl,bell
int dos
mov cl,0
jmp input0
input2: dec bx ; 'Remove' from buffer.
mov ah,prstr
mov dx,offset clrspc
int dos
jmp input0 ; Go get more.
input3: cmp al,'U'-64 ; Control-U?
jne input4
mov ah,prstr
mov dx,offset pass+1
int dos
push bx
push cx
call clearl ; Blank out the line.
pop cx
pop bx
mov cl,0 ; Reset count to zero.
mov bx,inpbuf ; Start at head of buffer.
jmp input0
input4: cmp al,0 ; Two character sequence?
jne input5
mov ah,conin
int dos ; Get second char.
cmp al,83 ; Delete key?
je inpt40 ; Yup.
cmp al,75 ; Backarrow key?
je inpt40
call dodel ; Erase weird character.
jmp input0 ; And go on computing.
inpt40: mov ah,prstr
mov dx,offset delinp ; Erase weird character.
int dos
jmp inpt11 ; Remove the offending char.
input5: mov [bx],al ; Add char to buffer.
inc cl ; Include in count.
inc bx
jmp input0
INPUT ENDP
; Print data onto the screen. If text has no "$" in it, just print
; it. Else, do special output for the "$".
; Routine expects: DI = Start of buffer we are to print.
; CX = Number of characters to print. [21c]
PRTSCR PROC NEAR
mov al,'$' ; This is what we're looking for.
mov oloc,di ; Remember original buffer address.
mov osiz,cx ; And original size.
push es
mov bx,ds
mov es,bx ; Have ES point to data area.
prts0: repnz scasb ; Search for "$" in the buffer.
cmp cx,0 ; Found one?
je prts1 ; No, do a regular DOS call.
mov ah,prstr
mov dx,oloc ; Print up to the "$".
int dos
mov ah,dconio
mov dl,'$'
int dos ; Print the "$"
mov oloc,di ; New starting location.
mov osiz,cx ; New size.
jmp prts0
prts1: mov bx,oloc ; The buffer location.
add bx,osiz ; Point past the data.
mov [bx],al ; Add "$" for printing.
mov ah,prstr
mov dx,oloc
int dos
pop es
ret
PRTSCR ENDP
; 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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msserv.asm
/bin/echo -n ' '; /bin/ls -ld msserv.asm
fi
/bin/echo 'Extracting msset.asm'
sed 's/^X//' <<'//go.sysin dd *' >msset.asm
public setcom, status, stat0, baudprt, escprt, prmptr, dodef
public setcpt, docom, shomac, atoi
include msdefs.h
setextra equ 100
macmax equ 20 ; max # of macros
datas segment public 'datas'
extrn comand:byte, flags:byte, trans:byte, cptfcb:byte, takadr:word
extrn taklev:byte, inichk:byte, portval:word, curdsk:byte
extrn setktab:byte, setkhlp:byte
kerm db 'Kermit-MS>$'
crlf db cr,lf,'$'
crlfsp db cr,lf,' ' ; crlf space
db '$'
eqs db ' = $'
ermes1 db cr,lf,'?Too many macros$'
ermes2 db cr,lf,'?No room in table for macro$'
ermes3 db cr,lf,'?Not confirmed$'
ermes4 db cr,lf,'?No room in take stack to expand macro$'
ermes5 db cr,lf,'?Not implemented$'
erms23 db cr,lf,'?0 or null scan code not allowed$' ;[jd]
erms24 db cr,lf,'?Capture file already open (use close command)$' ;[jd]
filhlp db ' Input file specification for session logging$'
macmsg db ' Specify macro name followed by body of macro $'
shmmsg db ' Confirm with carriage return $'
prmmsg db ' Enter new prompt string $'
sk1msg db ' Decimal scan code for key $'
sk2msg db ' Redefinition string for key $'
prterr db '?Unrecognized value$'
unrec db 'Baud rate is unknown$'
defpmp db 'Definition string: $'
esctl db 'Control-$' ; [6]
nonmsg db 'none$'
delmsg db 'delete$'
onmsg db 'On'
offmsg db 'Off'
tmp db ?,'$'
sum db 0
min db 0
max db 0
desta dw 0
numerr dw 0
numhlp dw 0
stflg db 0 ; Says if setting SEND or RECEIVE parameter.
srtmp db 0
savsp dw 0
temp dw 0
temp1 dw ? ; Temporary storage.
temp2 dw ? ; Temporary storage.
locst db 'Local echo $'
belon db 'Ring bell after transfer$'
beloff db 'No bell after transfer$'
vtemst db 'HEATH-19 emulation $'
cm1st db 'Communications port: 1$'
cm2st db 'Communications port: 2$'
capmsg db 'Session logging $'
eofmsg db 'EOF mode: $'
flost db 'No flow control used$'
floxmsg db 'Flow control: XON/XOFF $'
handst db 'Handshake used: $'
destst db 'File destination: $'
diskst db 'Default disk: $'
blokst db 'Block check used: $'
ebyst db '8-bit quoting done only on request$'
ebvst db '8-bit quoting will be done with: $'
sqcst db 'Send cntrl char prefix: $'
rqcst db 'Receive cntrl char prefix: $'
debon db 'Debug mode $'
flwon db 'Warning $'
parmsg db 'Parity $'
abfdst db 'Discard incomplete file$'
abfkst db 'Keep incomplete file$'
eolst db 'End-of-line character: $'
ssohst db 'Send start-of-packet char: $'
rsohst db 'Receive start-of-packet char: $'
stimst db 'Send timeout (seconds): $'
rtimst db 'Receive timeout (seconds): $'
spakst db 'Send packet size: $'
rpakst db 'Receive packet size: $'
snpdst db '# of send pad chars: $'
rnpdst db '# of receive pad chars: $'
timmsg db 'Timer $'
escmes db 'Escape character: $'
b03st db 'Baud rate is 300$'
b12st db 'Baud rate is 1200$'
b18st db 'Baud rate is 1800$'
b24st db 'Baud rate is 2400$'
b48st db 'Baud rate is 4800$'
b96st db 'Baud rate is 9600$'
b04st db 'Baud rate is 45.5$'
b05st db 'Baud rate is 50$'
b07st db 'Baud rate is 75$'
b11st db 'Baud rate is 110$'
b13st db 'Baud rate is 134.5$'
b15st db 'Baud rate is 150$'
b06st db 'Baud rate is 600$'
b20st db 'Baud rate is 2000$'
b19st db 'Baud rate is 19200$'
b38st db 'Baud rate is 38400$'
eolhlp db cr,lf,'Decimal number between 0 and 31$'
eolerr db cr,lf,'Illegal end-of-line character$'
timerr db cr,lf,'Illegal timeout value$'
timhlp db cr,lf,'Decimal number between 0 and 94$'
soherr db cr,lf,'Illegal start-of-packet character$'
quohlp db cr,lf,'Decimal number between 33 and 126$'
quoerr db cr,lf,'Illegal control character prefix$'
pakerr db cr,lf,'Illegal packet length$'
pakhlp db cr,lf,'Decimal number between 20 and 94$'
npderr db cr,lf,'Illegal number of pad characters$'
npdhlp db cr,lf,'Decimal number between 0 and 99$'
paderr db cr,lf,'Illegal pad character$'
padhlp db cr,lf,'Decimal number between 0 and 31 or 127$'
eschlp db cr,lf,'Enter literal value (ex: Cntrl ]) $'
desterr db cr,lf,'Illegal destination device$'
dskhlp db cr,lf,'Default disk drive to use, such as A:$'
dskerr db cr,lf,'Invalid drive specification$'
sethlp db cr,lf,'BAUD rate'
db cr,lf,'BELL'
db cr,lf,'BLOCK-CHECK-TYPE'
db cr,lf,'DEBUG'
db cr,lf,'DEFAULT-DISK'
db cr,lf,'DESTINATION'
db cr,lf,'END-OF-LINE character'
db cr,lf,'EOF CTRL-Z or NOCTRL-Z'
db cr,lf,'ESCAPE character change'
db cr,lf,'FLOW-CONTROL'
db cr,lf,'HANDSHAKE'
db cr,lf,'HEATH-19'
db cr,lf,'INCOMPLETE file'
db cr,lf,'KEY'
db cr,lf,'LOCAL-ECHO echoing (half-duplex)'
db cr,lf,'PARITY type'
db cr,lf,'PORT for communication'
db cr,lf,'PROMPT'
db cr,lf,'RECEIVE parameter'
db cr,lf,'REMOTE on/off'
db cr,lf,'SEND parameter'
db cr,lf,'TAKE-ECHO'
db cr,lf,'TIMER'
db cr,lf,'WARNING'
db '$'
settab db 24
mkeyw 'BAUD',baudst
mkeyw 'BELL',bellst
mkeyw 'BLOCK-CHECK-TYPE',blkset
mkeyw 'DEBUG',debst
mkeyw 'DEFAULT-DISK',dskset
mkeyw 'DESTINATION',desset
mkeyw 'END-OF-LINE',eolset
mkeyw 'EOF',seteof
mkeyw 'ESCAPE',escape
mkeyw 'FLOW-CONTROL',floset
mkeyw 'HANDSHAKE',hndset
mkeyw 'HEATH19-EMULATION',vt52em
mkeyw 'INCOMPLETE',abfset
mkeyw 'KEY',setkey
mkeyw 'LOCAL-ECHO',lcal
mkeyw 'PARITY',setpar
mkeyw 'PORT',comset
mkeyw 'PROMPT',promset
mkeyw 'RECEIVE',recset
mkeyw 'REMOTE',remset
mkeyw 'SEND',sendset
mkeyw 'TAKE-ECHO',takset
mkeyw 'TIMER',timset
mkeyw 'WARNING',filwar
seoftab db 2
mkeyw 'CTRL-Z',1
mkeyw 'NOCTRL-Z',0
stsrtb db 06 ; Number of options.
mkeyw 'PACKET-LENGTH',srpack
mkeyw 'PADCHAR',srpad
mkeyw 'PADDING',srnpd
mkeyw 'QUOTE',srquo
mkeyw 'START-OF-PACKET',srsoh
mkeyw 'TIMEOUT',srtim
ontab db 02H ; Two entries.
mkeyw 'OFF',00H
mkeyw 'ON',01H
destab db 02H ; Two choices.
mkeyw 'DISK',01H
mkeyw 'PRINTER',00H
; What type of block check to use.
blktab db 03H
mkeyw '1-CHARACTER-CHECKSUM',1
mkeyw '2-CHARACTER-CHECKSUM',2
mkeyw '3-CHARACTER-CRC-CCITT',3
; If abort when receiving files, can keep what we have or discard. [20d]
abftab db 02H ; Only two options.
mkeyw 'DISCARD',01H
mkeyw 'KEEP',00H
partab db 05H ; Five entries. [10 start]
mkeyw 'EVEN',PAREVN
mkeyw 'MARK',PARMRK
mkeyw 'NONE',PARNON
mkeyw 'ODD',PARODD
mkeyw 'SPACE',PARSPC
flotab db 2
mkeyw 'NONE',flonon
mkeyw 'XON/XOFF',floxon
hndtab db 7
mkeyw 'BELL',bell
mkeyw 'CR',cr
mkeyw 'ESC',esc
mkeyw 'LF',lf
mkeyw 'NONE',0
mkeyw 'XOFF',xoff
mkeyw 'XON',xon
BStab db 02H ;Two entries [19c start]
mkeyw 'BACKSPACE',00H
mkeyw 'DELETE',01H
bdtab db 010H ; 16 entries
mkeyw '110',b0110
mkeyw '1200',b1200
mkeyw '134.5',b01345
mkeyw '150',b0150
mkeyw '1800',b1800
mkeyw '19200',b19200
mkeyw '2000',b2000
mkeyw '2400',b2400
mkeyw '300',b0300
mkeyw '38400',b38400
mkeyw '45.5',b00455
mkeyw '4800',b4800
mkeyw '50',b0050
mkeyw '600',b0600
mkeyw '75',b0075
mkeyw '9600',b9600
ten dw 10 ; multiplier for setatoi
rdbuf db 80H DUP(?)
prm db 30 dup(0) ; Buffer for new prompt.
prmptr dw kerm ; pointer to prompt
defkw db 100 dup (?)
macnum dw 0 ; one macro yet
mactab dw ibmmac ; default ibm mac is macro 0
dw macmax dup (?) ; empty macro table
defptr dw macbuf
macbuf db macmax*100 dup (?) ; buffer for macro defs
rmlft db setextra ; space left in set table
mcctab db 1 ; macro cmd table, one initially
mkeyw 'IBM',0 ; macro # 0
db setextra dup (?) ; room for more.
ibmmac db imlen-1
db 'set timer on',cr,'set parity mark',cr
db 'set local-echo on',cr,'set handshake xon',cr
db 'set flow none',cr
imlen equ $-ibmmac
; structure for status information
stent struc
sttyp dw ? ; type (actually routine to call)
msg dw ? ; message to print
val2 dw ? ; needed value: another message, or tbl addr
tstcel dw ? ; address of cell to test, in data segment
basval dw 0 ; base value, if non-zero
stent ends
sttab stent <onoff,vtemst,,flags.vtflg>
stent <onoff,locst,,ecoflg,portval>
stent <baudprt>
stent <srchkw,parmsg,partab,parflg,portval>
stent <onechr,escmes,,trans.escchr>
stent <onoff,capmsg,,flags.capflg>
stent <msg2,flost,floxmsg,floflg,portval>
stent <prhnd>
stent <srchkw,destst,destab,flags.destflg>
stent <drnum,diskst,,curdsk>
stent <onoff,flwon,,flags.flwflg>
stent <msg2,beloff,belon,flags.belflg>
stent <msg2,abfkst,abfdst,flags.abfflg>
stent <srchkw,eofmsg,seoftab,flags.eofcz>
stent <onechr,sqcst,,trans.rquote>
stent <onechr,rqcst,,trans.squote>
stent <onechr,rsohst,,trans.rsoh>
stent <onechr,ssohst,,trans.ssoh>
stent <stnum,rtimst,,trans.rtime>
stent <stnum,stimst,,trans.stime>
stent <stnum,rpakst,,trans.rpsiz>
stent <stnum,spakst,,trans.spsiz>
stent <stnum,snpdst,,trans.spad>
stent <stnum,rnpdst,,trans.rpad>
stent <onoff,timmsg,,flags.timflg>
stent <pr8bit>
stent <onechr,eolst,,trans.seol>
stent <srchkw,blokst,blktab,trans.chklen>
stent <msg2,cm2st,cm1st,flags.comflg>
stent <onoff,debon,,flags.debug>
dw 0 ; end of table
sttbuf db 2000 dup (?) ; big buffer for status msg.
datas ends
code segment public
extrn cmcfrm:near, prserr:near, comnd:near, dobaud:near
extrn cmgtch:near, repars:near, coms:near, vts:near, defkey:near
extrn inicpt:near, prompt:near, nout:near, prtscr:near
extrn prkey:near
assume cs:code,ds:datas
; This is the SET command.
SETCOM PROC NEAR
mov dx,offset settab ; Parse a keyword from the set table.
mov bx,offset sethlp
mov ah,cmkey
call comnd
jmp r
call bx
nop
nop
nop
jmp rskp
SETCOM endp
docom proc near
mov dx,offset mcctab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd
pop bx
ret
nop
pop bx
cmp taklev,maxtak ; room in take level?
jl docom2 ; yes, continue
mov dx,offset ermes4 ; else complain
jmp reterr
docom2: inc taklev ; increment take level (overflow)
add takadr,size takinfo
shl bx,1
mov si,mactab[bx] ; point to macro
mov cl,[si] ; get size from macro
mov ch,0
inc si ; point to actual definition
mov bx,takadr ; point to current buffer
mov [bx].takfcb,0ffh ; flag as a macro
mov [bx].takptr,si ; point to beginning of def
mov [bx].takchl,cl ; # of chars left in buffer
mov [bx].takcnt,cx ; and in definition
mov word ptr [bx].takcnt+2,0 ; zero high order...
jmp rskp
docom endp
; the define command
dodef proc near
cmp macnum,macmax ; get current macro count
jl dode1 ; no, go on
mov dx,offset ermes1 ; else complain
jmp reterr ; and return
dode1: mov ah,cmtxt
mov bx,offset defkw+1 ; buffer for keyword
mov dx,offset macmsg
call comnd
ret
nop
nop
cmp ah,0
jne dode2
ret
dode2: push es
mov bx,ds
mov es,bx
cld
mov cl,ah
mov ch,0 ; length
mov si,offset defkw+1 ; pointer to keyword
mov ah,0 ; # of chars in keyword
; uppercase keyword, look for end
dode3: lodsb ; get a byte
cmp al,'a'
jb dode4
cmp al,'z'
ja dode4
sub al,'a'-'A'
mov [si-1],al ; uppercase if necessary
dode4: inc ah ; increment word count
cmp al,' ' ; is it the break character?
loopne dode3 ; no, loop thru rest of word
dode5: jne dode6 ; ended with break char?
dec ah ; yes, don't count in length
dode6: mov defkw,ah ; store length in front of it
add ah,4 ; add keyword overhead length
cmp ah,rmlft ; will it fit in buffer
jb dode7 ; yes, keep going
mov dx,offset ermes2 ; else complain
jmp reterr
dode7: sub rmlft,ah ; subtract space used in tbl
mov di,defptr ; pointer to free space
inc macnum ; count the macro
mov bx,macnum
shl bx,1 ; double for word idx!!!
mov mactab[bx],di ; install into table
mov [di],cl ; store length
inc di
jcxz dode10 ; no copy if 0 length
; copy definition into buffer, changing commas to crs
dode8: lodsb ; get a byte
cmp al,',' ; comma?
jne dode9 ; no, keep going
mov al,cr ; else replace with cr
dode9: stosb
loop dode8 ; keep copying
dode10: mov defptr,di ; update free ptr
mov bl,defkw
mov bh,0
lea di,defkw+1[bx] ; end of keyword
mov al,'$'
stosb
mov ax,macnum
stosb ; low-order
mov al,0 ; high-order is always 0.
stosb
; now install into table
pop es
mov bx,offset mcctab
mov dx,offset defkw
call addtab
jmp rskp
dodef endp
; add an entry to a keyword table
; enter with bx/ table address, dx/ ptr to new entry
; no check is made to see if the entry fits in the table.
addtab PROC NEAR
push es
cld
mov ax,ds
mov es,ax ; address data segment
mov bp,bx ; remember where tbl starts
mov cl,[bx] ; pick up length of table
mov ch,0
inc bx ; point to actual table...
addta1: push cx ; preserve count
mov si,dx ; point to entry
lodsb ; get length of new entry
mov cl,[bx] ; and length of table entry...
mov ah,0 ; assume they're the same size
cmp al,cl ; are they the same?
lahf ; remember result of comparison...
jae addta2 ; is new smaller? no, use table length
mov cl,al ; else use length of new entry
addta2: mov ch,0
lea di,[bx+1] ; point to actual keyword
repe cmpsb ; compare strings
pop cx ; restore count
jb addta4 ; below, insert before this one
jne addta3 ; not below or same, keep going
sahf ; same. get back result of length comparison
jb addta4 ; if new len is smaller, insert here
jne addta3 ; if not same size, keep going
mov si,bx ; else this is where entry goes
jmp short addta6 ; no insertion required...
addta3: mov al,[bx]
mov ah,0
add bx,ax ; skip this entry
add bx,4 ; len + $ + value...
loop addta1 ; and keep looking
addta4: mov si,bx ; this is first location to move
mov di,bx
inc ds:byte ptr [bp] ; remember we're adding one...
jcxz addta6 ; no more entries, forget this stuff
mov bh,0 ; this stays 0
addta5: mov bl,[di] ; get length
lea di,[bx+di+4] ; end is origin + length + 4 for len, $, value
loop addta5 ; loop thru remaining keywords
mov cx,di
sub cx,si ; compute # of bytes to move
push si ; preserve loc for new entry
mov si,di ; first to move is last
dec si ; minus one
mov di,dx ; new entry
mov bl,[di] ; get length
lea di,[bx+si+4] ; dest is source + length of new + 4
std ; move backwards
rep movsb ; move the table down
cld ; put flag back
pop si
addta6: mov di,si ; this is where new entry goes
mov si,dx ; this is where it comes from
mov cl,[si] ; length
mov ch,0
add cx,4 ; overhead bytes
rep movsb ; stick it in
pop es
ret ; and return
addtab endp
; Show defined macros.
SHOMAC PROC NEAR
mov ah,cmtxt
mov bx,offset rdbuf
mov dx,offset shmmsg
call comnd
jmp r
cmp ah,0 ; Bare CR means show all macros.
jne shom2 ; No, he wants specific macro expanded.
mov si,offset mcctab ; Table of macro names.
lodsb
mov cl,al ; Number of macro entries.
mov ch,0
shom0: jcxz shom1 ; Done if none left to display.
lodsb ; Length of macro name.
push ax ; Don't forget it.
mov ah,prstr
mov dx,offset crlfsp ; Go to new line.
int dos
mov dx,si ; Print macro name.
int dos
mov dx,offset eqs
int dos
pop ax
mov ah,0
add si,ax ; Skip over name.
inc si ; Get to macro number.
mov bx,[si] ; Pick it up.
call expmac ; Expand the macro.
dec cx
add si,2 ; Skip over macro number.
jmp shom0 ; And do the rest.
shom1: mov ah,prstr
mov dx,offset crlf
int dos
jmp rskp
shom2: mov ah,prstr
mov dx,offset ermes3
int dos
jmp rskp
SHOMAC ENDP
; Expand the macro, called with BX/macro number.
expmac: push si
push cx
mov si,offset mactab ; Table of address expansions.
shl bx,1 ; Double and use as index into table.
mov si,[si+bx] ; Get address of expansion in question.
mov ax,si ; Address of string.
inc ax ; Don't print length.
mov cl,[si] ; Length of string.
mov ch,0
call prkey ; Print it.
pop cx
pop si
ret
seteof proc near
mov ah,cmkey
mov bx,0
mov dx,offset seoftab
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd
jmp seteo1 ; error return...
nop
pop bx
mov flags.eofcz,bl ; set value
jmp rskp ; and return
seteo1: pop bx
ret
seteof endp
; This is the ESCAPE character SET subcommand. [6 start]
ESCAPE PROC NEAR
call cmgtch ; Get a char.
cmp ah,0
jns es1 ; Terminator or no?
and ah,7FH ; Turn off minus bit.
cmp ah,'?'
jne es0
mov dx,offset eschlp
mov ah,prstr
int dos
mov dx,offset crlf
int dos
mov dx,comand.cmprmp
int dos
mov bx,comand.cmdptr
mov al,'$'
mov [bx],al
mov dx,offset comand.cmdbuf
int dos
dec comand.cmcptr ; Ignore dollar sign.
dec comand.cmccnt
mov comand.cmaflg,0
jmp repars
es0: mov ah,prstr
mov dx,offset ermes3
int dos
ret
es1: mov temp,ax
call cmcfrm
jmp es0
nop ; Take up 3 bytes.
mov ax,temp
mov trans.escchr,ah ; Save new value.
ret
ESCAPE ENDP ; [6 end]
; This is the End-of-line character SET subcommand.
EOLSET PROC NEAR
mov min,0
mov max,1FH
mov sum,0
mov tmp,10
mov temp1,0
mov desta,offset trans.seol
mov numhlp,offset eolhlp
mov numerr,offset eolerr
jmp num0 ; Common routine for parsing numerical input.
EOLSET ENDP
num0: call cmgtch ; Get the first char into AH.
cmp ah,0
js num1
cmp ah,'0'
jl num1
cmp ah,'9'
ja num1
mov temp1,1
sub ah,30H
mov dl,ah
mov al,sum
mul tmp
add al,dl
mov sum,al
jmp num0
num1: and ah,7FH
cmp ah,CR
jne num2
cmp temp1,0
je num21
mov al,sum
cmp al,min
jl num3
cmp al,max
jg num3
mov bx,desta
mov [bx],al
ret
num2: cmp ah,03FH ; Question mark?
je num4
num21: mov ah,prstr
mov dx,offset ermes3
int dos
jmp prserr
num3: mov ah,prstr
mov dx,numerr
int dos
jmp prserr
num4: mov ah,prstr
mov dx,numhlp
int dos
mov dx,offset crlf
int dos
mov dx,comand.cmprmp
int dos
mov bx,comand.cmdptr
mov al,'$'
mov [bx],al
mov dx,offset comand.cmdbuf
int dos
dec comand.cmcptr ; Don't count the dollar sign.
dec comand.cmccnt ; Or the question mark.
mov comand.cmaflg,0 ; Check for more input.
jmp repars
; This is the LOCAL echo SET subcommand.
LCAL PROC NEAR
mov dx,offset ontab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx ; Save the parsed value.
mov ah,cmcfm
call comnd ; Get a confirm.
jmp lcl0 ; Didn't get a confirm.
nop
pop bx
mov si,portval
mov [si].ecoflg,bl ; Set the local echo flag.
mov [si].hndflg,bl ; This goes on/off with local echo.
xor bl,01 ; Toggle this.
mov [si].floflg,bl ; This is the opposite.
ret
lcl0: pop bx
ret
LCAL ENDP
; This is the VT52 emulation SET subcommand.
VT52EM PROC NEAR
call vts
ret
VT52EM ENDP
; This is the SET subcommand to choose between COM1 and COM2. [19b]
COMSET PROC NEAR
call coms
ret
COMSET ENDP
FILWAR PROC NEAR
mov dx,offset ontab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp fil0 ; Didn't get a confirm.
nop
pop bx
mov flags.flwflg,bl ; Set the filewarning flag.
ret
fil0: pop bx
ret
FILWAR ENDP
; This is the SET aborted-file command. [20d]
ABFSET PROC NEAR
mov dx,offset abftab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp abf0 ; Didn't get a confirm.
nop
pop bx
mov flags.abfflg,bl ; Set the aborted file flag.
ret
abf0: pop bx
ret
ABFSET ENDP
; This is the SET Parity command. [10 start]
SETPAR PROC NEAR
mov dx,offset partab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp par0 ; Didn't get a confirm.
nop
pop bx
mov si,portval
mov [si].parflg,bl ; Set the parity flag.
cmp bl,parnon ; Resetting parity to none? [21b]
je setp0 ; Yes, reset 8 bit quote character. [21b]
mov trans.ebquot,dqbin ; Else, do quoting. [21b]
ret ; That's it. [21b]
setp0: mov trans.ebquot,'Y' ; If none, say will quote upon request. [21b]
ret
par0: pop bx
ret
SETPAR ENDP ; [10 end]
; Sets debugging mode on and off.
DEBST PROC NEAR
mov dx,offset ontab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp deb0 ; Didn't get a confirm.
nop
pop bx
mov flags.debug,bl ; Set the DEBUG flag.
ret
deb0: pop bx
ret
DEBST ENDP
; Turn bell on or off. [17a start]
BELLST PROC NEAR
mov dx,offset ontab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd
jmp bel0
nop
pop bx
mov flags.belflg,bl
ret
bel0: pop bx
ret
BELLST ENDP ; [17a end]
; Toggle echo'ing of TAKE file to be either ON or OFF.
TAKSET PROC NEAR
mov dx,offset ontab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd
jmp tak0
nop
pop bx
mov flags.takflg,bl
ret
tak0: pop bx
ret
TAKSET ENDP ; [17a end]
; Set timer ON/OFF during file transfer.
TIMSET PROC NEAR
mov dx,offset ontab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd
jmp tim0
nop
pop bx
mov flags.timflg,bl
ret
tim0: pop bx
ret
TIMSET ENDP ; [17a end]
; Allow user to change the "Kermit-MS>" prompt.
PROMSET PROC NEAR
mov ah,cmtxt
mov bx,offset prm ; Read in the prompt.
mov dx,offset prmmsg
call comnd
jmp r
cmp ah,0 ; Just a bare CR?
jne prom0
mov ax,offset kerm
jmp prom1
prom0: mov byte ptr [bx],'$' ; End of string.
mov ax,offset prm
prom1: mov prmptr,ax ; Remember it.
jmp rskp
PROMSET ENDP
; Set Flow-Control subcommand.
FLOSET PROC NEAR
mov dx,offset flotab
xor bx,bx
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp flox ; Didn't get a confirm.
nop
pop bx
mov si,portval
mov [si].flowc,bx ; Flow control value.
cmp bx,0 ; Turning it off?
je flo0 ; Yes.
mov [si].floflg,1 ; Say we're doing flow control.
mov [si].hndflg,0 ; So don't do handshaking.
ret
flo0: mov [si].floflg,bl ; Say we're not doing flow control.
ret
flox: pop bx
ret
FLOSET ENDP
; Set Handshake subcommand.
HNDSET PROC NEAR
mov dx,offset hndtab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp hndx ; Didn't get a confirm.
nop
pop bx
mov si,portval
cmp bl,0 ; Setting handshake off?
je hnd0 ; Yes.
mov [si].floflg,0 ; Else, turn flow control off.
mov [si].hndflg,1 ; And turn on handshaking.
mov [si].hands,bl ; Use this char as the handshake.
ret
hnd0: mov [si].hndflg,0 ; No handshaking.
mov [si].floflg,1 ; If one is off, the other is on.
ret
hndx: pop bx
ret
HNDSET ENDP
; Set block check type sub-command.
BLKSET PROC NEAR
mov dx,offset blktab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp blk0 ; Didn't get a confirm.
nop
pop bx
mov trans.chklen,bl ; Use this char as the handshake.
mov inichk,bl ; Save here too.
ret
blk0: pop bx
ret
BLKSET ENDP
; Set destination for incoming file.
DESSET PROC NEAR
mov dx,offset destab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp des0 ; Didn't get a confirm.
nop
pop bx
mov flags.destflg,bl ; Set the destination flag.
ret
des0: pop bx
ret
DESSET ENDP
; Set default disk for sending/receiving, etc.
DSKSET PROC NEAR
mov comand.cmcr,1 ; Don't want filename specified.
mov ah,cmifi ; Parse for drive specification.
mov dx,offset rdbuf ; Read into handy buffer.
mov bx,offset dskhlp ; Text of help message.
call comnd
jmp r
mov ah,cmcfm
call comnd
jmp r
cmp flags.nmoflg,0 ; Fail if specified file name.
je dsk1
dsk0: mov ah,prstr
mov dx,offset dskerr ; Illegal drive specification.
int dos
ret
dsk1: mov bx,offset rdbuf
mov ah,[bx] ; Get the drive they said to use.
cmp ah,0 ; Did they type a bare CR?
je dsk0 ; Yes, complain.
mov curdsk,ah ; And remember it.
dec ah
mov dl,ah
mov ah,seldsk
int dos
ret
DSKSET ENDP
; This function sets the baud rate.
BAUDST PROC NEAR
mov dx,offset bdtab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp bau0 ; Didn't get one.
nop
pop bx
mov si,portval
mov ax,[si].baud ; Remember original value. [25]
mov [si].baud,bx ; Set the baud rate.
call dobaud ; Use common code. [19a]
ret
bau0: pop bx
ret
BAUDST ENDP
SENDSET PROC NEAR
mov stflg,'S' ; Setting SEND parameter
sndst0: mov dx,offset stsrtb ; Parse a keyword.
mov bx,0
mov ah,cmkey
call comnd
jmp r
call bx
nop
nop
nop
jmp rskp
SENDSET ENDP
recset: mov stflg,'R' ; Setting RECEIVE paramter.
jmp sndst0
remset proc near
mov ah,cmkey
mov dx,offset ontab
mov bx,0
call comnd
jmp r
push bx ; save parsed value
mov ah,cmcfm
call comnd ; confirm
pop bx
ret ; return on failure
nop
pop bx
mov flags.remflg,bl ; set remote setting
jmp rskp ; and return
remset endp
; Set send/receive start-of-header.
srsoh: mov min,0
mov max,1FH
mov sum,0
mov tmp,10
mov desta,offset trans.ssoh ; Assume SEND.
cmp stflg,'S' ; Setting SEND paramter?
je srsoh0
mov desta,offset trans.rsoh
srsoh0: mov numhlp,offset eolhlp ; Reuse help message.
mov numerr,offset soherr
mov temp1,0
jmp num0 ; Common routine for parsing numerical input.
; Set send/receive timeout.
srtim: mov min,0
mov max,94
mov sum,0
mov tmp,10
mov desta,offset trans.stime ; Assume SEND.
cmp stflg,'S' ; Setting SEND paramter?
je srtim0
mov desta,offset trans.rtime
srtim0: mov numhlp,offset timhlp ; Reuse help message.
mov numerr,offset timerr
mov temp1,0
jmp num0 ; Common routine for parsing numerical input.
; Set send/receive packet length.
srpack: mov min,20
mov max,94
mov sum,0
mov tmp,10
mov desta,offset trans.spsiz
cmp stflg,'S' ; Setting SEND paramter?
je srpak0
mov desta,offset trans.rpsiz
srpak0: mov numhlp,offset pakhlp
mov numerr,offset pakerr
mov temp1,0
jmp num0 ; Parse numerical input.
; Set send/receive number of padding characters.
srnpd: mov min,0
mov max,99
mov sum,0
mov tmp,10
mov desta,offset trans.spad
cmp stflg,'S' ; Setting SEND paramter?
je srnpd0
mov desta,offset trans.rpad
srnpd0: mov numhlp,offset npdhlp
mov numerr,offset npderr
mov temp1,0
jmp num0 ; Parse numerical input.
; Set send/receive padding character.
srpad: mov min,0
mov max,127
mov sum,0
mov tmp,10
mov srtmp,0FFH ; Haven't seen anything yet.
mov desta,offset srtmp
mov numhlp,offset padhlp
mov numerr,offset paderr
mov temp1,0
mov savsp,sp
call num0 ; Parse numerical input.
mov sp,savsp
mov temp,offset trans.spadch
cmp stflg,'S'
je srpad1
mov temp,offset trans.rpadch
srpad1: mov bx,offset srtmp
mov ah,[bx]
cmp ah,0FFH ; Did they end up not doing the command?
je srpad3
cmp ah,127 ; This is allowed.
je srpad2
cmp ah,32
jb srpad2 ; Between 0 and 31 is OK too.
mov ah,prstr
mov dx,offset paderr
int dos
ret
srpad2: mov bx,temp ; Set the real pad char.
mov [bx],ah
srpad3: ret
; Set send/receive control character prefix.
srquo: mov min,33
mov max,126
mov sum,0
mov tmp,10
mov desta,offset trans.rquote ; Used for outgoing packets.
cmp stflg,'S' ; Setting outgoing quote char?
je srquo0
mov desta,offset trans.squote ; For incoming quote char.
srquo0: mov numhlp,offset quohlp
mov numerr,offset quoerr
mov temp1,0
jmp num0 ; Parse numerical input.
; This is the STATUS command.
STATUS PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
mov dx,offset crlf
mov ah,prstr
int dos ; initial crlf
call stat0
mov cx,di ; End of buffer
sub cx,ax ; Get length of buffer.
dec cx ; Account for null.
mov di,ax ; Buffer pointer.
call prtscr ; Put data onto the screen.
jmp rskp
STATUS ENDP
; Return a pointer to status message in AX, ptr to end in DI.
STAT0 PROC NEAR
push es
mov ax,ds
mov es,ax ; address data segment
cld ; make sure strings go the right way
mov di,offset sttbuf ; point to destination buffer
mov bx,offset sttab ; table to control printing
mov al,' ' ; start with a space
stosb ; in the buffer
mov ax,0 ; need-new-line flag
stat01: cmp word ptr [bx],0 ; end of table?
je stat02 ; yes, exit routine
push bx
push di ; remember important values
push ax
call [bx].sttyp ; call the appropriate routine
pop ax
pop cx ; return buffer value
pop bx ; and ptr
or ax,ax ; do we need a newline?
jne stat03 ; yes, go put one in
sub cx,di ; else see how many columns they used
add cx,40 ; this is where we'd like to be
; if cx is negative here, we have a problem...
mov al,' '
rep stosb ; add right # of spaces
mov ax,1 ; note we need a newline next time
jmp short stat04 ; and keep looping around
stat03: mov cx,3
mov si,offset crlfsp
rep movsb ; append crlf to string
xor ax,ax ; reset newline flag
stat04: add bx,size stent ; advance to next one
jmp stat01
stat02: mov al,0 ; end buffer
stosb
mov ax,offset sttbuf
pop es ; restore this
ret ; and return
STAT0 ENDP
; handler routines for status
; all are called with di/ destination buffer, bx/ stat ptr. They
; can change any register but the segment registers, must update
; di to the end of the buffer.
; copy the message into the buffer
stmsg proc near
mov si,[bx].msg ; get message address
stms1: lodsb ; get a byte
stosb ; drop it off
cmp al,'$' ; end of message?
jne stms1 ; no, keep going
dec di ; else back up ptr
ret ; and return
stmsg endp
; get address of test value in stent. Returns address in si
stval proc near
mov si,[bx].basval ; get base value
cmp si,0 ; any there?
je stva1 ; no, keep going
mov si,[si] ; yes, use as base address
stva1: add si,[bx].tstcel ; add offset of test cell
ret ; and return it
stval endp
; print a single character
onechr proc near
call stmsg ; copy message part first
call stval ; pick up test value address
mov al,[si] ; this is char to print
cmp al,' ' ; printable?
jae onech1 ; yes, keep going
add al,64 ; make printable.
mov byte ptr [di],'^'
inc di ; note ctrl char
onech1: stosb ; drop char off
ret ; and return
onechr endp
; numeric field...
stnum proc near
call stmsg ; copy message
call stval ; pick up value address
mov al,[si] ; get value
mov ah,0 ; high order is 0
call outnum ; put number into buffer
ret ; and return
stnum endp
; translate the number in ax...
outnum proc near
cwd
mov bx,10
div bx ; divide to get digit
push dx ; save remainder digit
or ax,ax ; test quotient
jz outnu1 ; zero, no more of number
call outnum ; else call for rest of number
outnu1: pop ax ; get digit back
add al,'0' ; make printable
stosb ; drop it off
ret ; and return
outnum endp
; on/off field
onoff proc near
call stmsg ; copy message
call stval ; get value cell
mov al,[si]
mov si,offset onmsg
mov cx,2 ; assume 2-byte 'ON' message
or al,al ; test value
jnz onof1 ; on, have right msg
mov si,offset offmsg
mov cx,3
onof1: rep movsb ; copy right message in
ret ; and return
onoff endp
; print first message if false, second if true
msg2 proc near
call stval ; get value cell
mov al,[si]
mov si,[bx].msg ; assume off
or al,al ; is it?
jz msg21 ; yes, continue
mov si,[bx].val2 ; else use alternate message
msg21: jmp stms1 ; handle copy and return
msg2 endp
; search a keyword table for a value, print that value
srchkw proc near
call stmsg ; first print message
call stval
mov al,[si] ; get value to hunt for
mov ah,0 ; high order is 0
mov bx,[bx].val2 ; this is table address
jmp prttab ; and look in table.
srchkw endp
; Print the drive name.
drnum proc near
call stmsg ; copy message part first
call stval ; pick up test value address
mov al,[si] ; this is char to print
add al,'@' ; Make it printable.
stosb
mov byte ptr [di],':'
inc di ; end with a colon
ret ; and return
drnum endp
; print 8-bit quoting
pr8bit proc near
mov bl,trans.ebquot ; get quote char
mov si,offset ebyst ; assume no 8-bit quoting
cmp bl,'Y' ; on request only?
je pr8bi1 ; yes, continue
mov si,offset ebvst ; else variable
pr8bi1: call stms1 ; copy message in
cmp bl,'Y' ; not doing it?
je pr8bi2 ; no, forget this part
mov [di],bl ; else drop off char too
inc di
pr8bi2: ret ; and return
pr8bit endp
; Print the handshake.
prhnd: mov si,offset handst ; copy in initial message
call stms1
mov si,offset nonmsg ; assume no handshake
mov bx,portval
cmp [bx].hndflg,0 ; Is handshaking in effect?
jne prh0 ; Yes, print what we're using.
jmp stms1 ; no, say so and return
prh0: mov al,'^' ; Doing handshaking with control char.
stosb
mov al,[bx].hands
add al,40H ; Make printable.
stosb ; put in buffer
ret ; and return
; Print the pad character in AL.
prpad: cmp al,127 ; Are they using a delete?
jne prpad0
mov ah,prstr
mov dx,offset delmsg
int dos
ret
prpad0: mov dl,'^'
mov ah,conout
push ax
int dos
pop ax
mov dl,al
add dl,40H ; Make printable.
int dos
ret
; Print value from table. BX/address of table, AL/value of variable.
prttab: mov cl,[bx] ; Number of entries in our table.
inc bx ; Point to the data.
prtt0: mov dl,[bx] ; Length of keyword.
inc bx ; Point to keyword.
mov dh,0
inc dx ; Account for "$" in table.
mov si,dx ; Put to index register.
cmp ax,[bx+si] ; Is this the one?
je prtt1
add bx,dx ; Go to end of keyword.
add bx,2 ; Point to next keyword.
dec cl ; Any more keywords to check?
jnz prtt0 ; Yes, go to it.
mov bx,offset prterr
prtt1: mov si,bx
prtt2: jmp stms1 ; copy in message
ret ; and return
; This routine prints out the escape character in readable format.
ESCPRT PROC NEAR ; [6 start]
mov dl,trans.escchr
cmp dl,' '
jge escpr2
push dx
mov ah,prstr
mov dx,offset esctl
int dos
pop dx
add dl,040H ; Make it printable.
escpr2: mov ah,conout
int dos
ret
ESCPRT ENDP ; [6 end]
; Print information on the baud rate. [19a]
BAUDPRT PROC NEAR
mov si,portval
mov ax,[si].baud
mov dx,offset b48st ; Assume 4800 baud.
cmp ax,B4800
jnz bdprt0
jmp bdprt2
bdprt0: mov dx,offset b12st
cmp ax,B1200
jnz bdprt1
jmp bdprt2
bdprt1: mov dx,offset b18st
cmp ax,B1800
jz bdprt2
mov dx,offset b24st
cmp ax,B2400
jz bdprt2
mov dx,offset b96st
cmp ax,B9600
jz bdprt2
mov dx,offset b03st
cmp ax,B0300
jz bdprt2
mov dx,offset b04st
cmp ax,B00455
jz bdprt2
mov dx,offset b05st
cmp ax,B0050
jz bdprt2
mov dx,offset b07st
cmp ax,b0075
jz bdprt2
mov dx,offset b11st
cmp ax,B0110
jz bdprt2
mov dx,offset b13st
cmp ax,B01345
jz bdprt2
mov dx,offset b15st
cmp ax,B0150
jz bdprt2
mov dx,offset b06st
cmp ax,B0600
je bdprt2
mov dx,offset b20st
cmp ax,B2000
jz bdprt2
mov dx,offset b19st
cmp ax,B19200
jz bdprt2
mov dx,offset b38st
cmp ax,B38400
jz bdprt2
mov dx,offset unrec ; Unrecognized baud rate.
bdprt2: mov si,dx ; this is baud rate
bdprt3: jmp stms1 ; go copy it and return
BAUDPRT ENDP
setkey proc near
cmp setktab,0 ; any table?
jne setk0 ; yes, use it
mov dx,offset ermes5
jmp reterr ; else print error message
setk0: mov dx,offset setktab ; set key options
mov bx,offset setkhlp
mov ah,cmkey
call comnd
jmp r
cmp bx,-1 ;[jd] do we have scan code?
jne setk1 ;[jd] yes, skip this part
mov ah,cmtxt
mov bx,offset rdbuf ; handy buffer
mov dx,offset sk1msg
call comnd
jmp r ; fail return
mov si,offset rdbuf ; this is parsed number
call atoi ; Convert input to real number.
jmp reterr ; No good.
mov bx,ax ; put accumulation into bl
setat3: cmp bx,0 ; is scan code 0?
jne setk2 ; no, have scan code, look for def
setk1: push bx ; save our scan code
mov ah,cmcfm
call comnd
jmp short setkx ; no good, pop bx and return
nop ; waste a byte
pop bx
; scan code is in bl, ask for string part
setk2: push bx
mov dx,offset defpmp
call prompt
mov ah,cmtxt
mov bx,offset rdbuf
mov dx,offset sk2msg
call comnd ; read the definition
jmp short setkx ; pop bx and fail return
nop
mov cl,ah
mov ch,0 ; set up length of definition
pop ax ; get scan code back
mov si,offset rdbuf ; point to definition
call defkey ; go define the key
ret ; use ret for now...
jmp rskp ; and return
setkx: pop bx ; pop junk off stack
ret ; and return
setkey endp
; Convert input in buffer pointed to by SI to real number which is returned
; in AX. Return on failure, return skip on success.
ATOI PROC NEAR
mov cl,ah ; Number of chars of input.
mov ch,0 ; size of string
jcxz atoi4 ; Fail on no input.
mov ax,0 ; init sum
mov bh,0 ; high order of this stays 0.
atoi0: xchg al,bl ; save current sum
lodsb ; grab a byte
cmp al,' ' ; leading space?
jne atoi1 ; no, continue
xchg al,bl ; put sum back
jmp short atoi2 ; and continue loop
atoi1: cmp al,'9'
ja atoi3 ; out of range, done
cmp al,'0'
jb atoi3
xchg al,bl ; put sum back into al
mul ten ; shift one digit
sub bl,'0' ; convert to binary
add ax,bx ; add to sum
atoi2: loop atoi0 ; loop thru all chars
atoi3: jmp rskp
atoi4: mov dx,offset erms23 ; complain and return
ret
ATOI ENDP
; addition for capture of raw output
setcpt proc near
test flags.capflg,0FFH
jz setcp1 ; no capture file, keep going
mov dx,offset erms24
jmp reterr
setcp1: mov comand.cmcr,0 ; Filename must be specified.
mov ah,cmifi
mov dx,offset cptfcb
mov bx,offset filhlp
call comnd
jmp r
mov ah,cmcfm
call comnd ; confirm with carriage return
jmp r
mov ah,delf
mov dx,offset cptfcb
int dos ; open up file
mov ah,makef
mov dx,offset cptfcb
int dos
mov cptfcb+32,0
call inicpt ; init capture variables
mov flags.capflg,0FFH ; know we have capture routine
jmp rskp ; and return
setcpt endp
; 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
; routine to print an error message, then retskp
; expects message in dx
reterr proc near
mov ah,prstr
int dos
jmp rskp
reterr endp
code ends
end//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msset.asm
/bin/echo -n ' '; /bin/ls -ld msset.asm
fiknutson@ut-ngp.UUCP (Jim Knutson) (10/05/84)
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting msterm.asm'
sed 's/^X//' <<'//go.sysin dd *' >msterm.asm
public clscpt, defkey, cptfcb, inicpt, clscpi, telnet
public dopar, shokey, prkey
include msdefs.h
datas segment public 'datas'
extrn flags:byte, trans:byte, buff:byte, portval:word
targ termarg <0,1,80,24,cptchr,2dch,0,scntab,deftab,0,,parnon>
ssp dw 0 ; Save SP in Telnet.
crlf db cr,lf,'$'
tmp db ?,'$'
temp dw 0
temp1 dw ? ; Temporary storage.
temp2 dw ? ; Temporary storage.
tmsg1 db cr,lf,'[Connecting to host, type $'
tmsg3 db ' C to return to PC]',cr,lf,cr,lf,cr,lf,'$'
tmsg2 db cr,lf,'[Back at micro]',cr,lf,'$'
erms22 db cr,lf,'?No capture file open$' ;[jd]
esctl db 'Control-$' ; [6]
inthlp db cr,lf,' ? This message'
db cr,lf,' C Close the connection'
db cr,lf,' S Status of the connection'
db cr,lf,' B Send a break'
db cr,lf,' M Toggle mode line'
db cr,lf,' Q Quit logging'
db cr,lf,' R Resume logging'
db cr,lf,' 0 Send a null'
db cr,lf,' Typing the escape character will send it to the host'
db 0
intprm db 'Command>$'
CPTFCB DB 25H DUP (?)
CAPBUF DB 200 DUP (?)
CAPBP DW ?
CAPLFT DB ?
SCNTLEN EQU 200 ; MAX # OF DEFINITIONS ONE can have
defbsiz equ 400 ; combined length of all definitions...
scntab dw scntlen dup (?) ; scan codes redefined
deftab dw scntlen dup (?) ; pointer to definition strings
defbuf db defbsiz dup (?)
defptr dw defbuf ; pointer starts at beginning
deflen dw defbsiz ; amt of space left in buffer
sttmsg db 'Type space to continue$'
shkmsg db cr,lf,'Press key: $'
datas ends
code segment public
extrn comnd:near, outchr:near, stat0:near
extrn escprt:near, clrbuf:near, term:near
extrn cmblnk:near, locate:near, prtchr:near
extrn beep:near, puthlp:near
extrn serini:near,serrst:near, sendbr:near, showkey:near
assume cs:code, ds:datas
; the show key command.
shokey proc near
mov ah,cmcfm ; confirm with carriage return
call comnd
jmp r ; uh oh...
mov dx,offset shkmsg
mov ah,prstr
int dos ; print a prompt for it
mov ax,offset targ ; give it terminal arg block.
call showkey ; show them the key definition
push ax
push cx ; save results
mov dx,offset crlf
mov ah,prstr
int dos
pop cx
pop ax
call prkey ; print the buffer
mov dx,offset crlf
mov ah,prstr
int dos
jmp rskp ; and return
shokey endp
; pass a string pointer in ax, length in cx.
; Prints the string, quoting any unprintables, except crlf.
prkey proc near
mov si,ax ; copy string ptr
jcxz prke6 ; no string, stop here
prke1: push cx ; save counter
lodsb ; get a byte
and al,7fH ; only consider low-order 7 bits.
cmp al,' ' ; printable?
jb prke2 ; no, print the hard way
cmp al,7fH ; maybe a delete?
jne prke4 ; no, can just put into string
prke2: jcxz prke3 ; last char, can't be crlf
cmp al,cr ; carriage return?
jne prke3 ; no, go on
cmp byte ptr [si],lf ; followed by linefeed?
jne prke3
mov ah,prstr
mov dx,offset crlf
int dos ; else just print crlf
inc si ; skip over lf
pop cx ; careful...
dec cx
push cx
jmp short prke5
prke3: push ax ; preserve the char
mov ah,conout
mov dl,'\'
int dos ; print the quote character
pop ax
call proct ; print the octal byte
jmp short prke5
prke4: mov dl,al ; normal char, just print it
mov ah,conout
int dos
prke5: pop cx ; restore count
loop prke1
prke6: ret ; and return
prkey endp
; print the byte in al as an octal number
proct proc near
mov dl,al ; get the byte
and dl,7h ; keep low-order byte
mov cl,3
shr al,cl ; shift to get next digit
jz proc1 ; 0, no more to print
push dx ; else save current digit
call proct ; print rest
pop dx
proc1: mov ah,conout
add dl,'0' ; make printable
int dos
ret
proct endp
; This is the CONNECT command.
TELNET PROC NEAR
mov ah,cmcfm
call comnd ; Get a confirm.
jmp r ; Didn't get a confirm.
mov ah,prstr ; Output
mov dx,offset crlf ; a crlf.
int dos
call domsg ; Reassure user. [19b]
mov al,targ.flgs ; get present flags
and al,modoff ; this is only one we can keep around
or al,havtt ; defaults (!)
cmp flags.debug,0 ; debug mode?
jz tel0 ; no, keep going
or al,trnctl ; yes, show control chars
tel0: cmp flags.vtflg,0 ; vt52 emulation?
jz tel1
or al,emheath
tel1: mov bx,portval
cmp [bx].ecoflg,0 ; echoing?
jz tel2
or al,lclecho
tel2: mov targ.flgs,al ; store flags
mov ah,flags.comflg
mov targ.prt,ah ; Port 1 or 2
mov ah,trans.escchr
mov targ.escc,ah
mov ah,[bx].parflg
mov targ.parity,ah
mov ax,[bx].baud
mov targ.baudb,al
mov ah,flags.capflg
and ah,capt
or targ.flgs,ah
call serini ; init serial port
tem: mov ax,offset targ ; Point to terminal arguments
call term
or targ.flgs,scrsam ; assume screen is the same.
intchr: mov ah,dconio ; Direct console I/O.
mov dl,0FFH ; Input.
int dos ; Get a char.
jz intchr ; no char, keep looking
mov ah,al
jz intchr ; If so, go until we get a char.
cmp ah,' ' ; space - ignore it
je tem
mov bh,ah ; Save the actual char.
and ah,not ('a'-'A') ; Convert to upper case.
or ah,40H ; convert ctl-char to actual char.
cmp ah,'C' ; Is it close?
jne intch1
call serrst ; reset serial port
jmp rskp ; and return
intch1: cmp ah,'S' ; Is it status?
jnz intch2
call stat0 ; If so, call stat0.
call puthlp ; put help on screen
mov dx,offset sttmsg
mov ah,prstr
int dos
intch1a:mov ah,8 ; console input, no echo
int dos
cmp al,' ' ; space?
jne intch1a
and targ.flgs,not scrsam ; remember screen changed.
jmp tem
intch2: cmp ah,'B' ; Send a break? [20g]
jne intch3 ; No. [20g]
call sendbr ; Yes, so send a break. [20g]
jmp tem ; And return. [20g]
intch3: cmp ah,'M' ; mode line?
jne intch4
xor targ.flgs,modoff ; toggle mode line
jmp tem ; and reconnect
intch4: cmp bh,'?' ; Is it help?
jne intch5 ; If not, go to the next check.
mov ax,offset inthlp ; If so, get the address of the help message.
call puthlp ; write help msg
mov dx,offset intprm
mov ah,prstr ; Print it.
int dos
and targ.flgs,not scrsam ; remember screen changed
jmp intchr ; Get another char.
intch5: cmp bh,trans.escchr ; Is it the escape char?
jne intch7 ; If not, go send a beep to the user.
intch6: mov ah,al
call outchr
nop
nop
nop
jmp tem ; Return, we are done here.
intch7: cmp ah,'Q' ; maybe want to stop logging?
jne intch8
test targ.flgs,capt ; not capturing, can't do this
jz intc10
and targ.flgs,not capt ; stop capturing
jmp tem ; and resume
intch8: cmp ah,'R' ; maybe resume?
jne intch9 ; no, keep going
cmp flags.capflg,0 ; can we capture?
jz intc10 ; no, forget it
test targ.flgs,capt ; already capturing?
jnz intc10 ; yes, can't toggle back on then
or targ.flgs,capt ; else turn flag on
jmp tem ; and resume
intch9: cmp bh,'0' ; perhaps want a null (note original chr in bh)
jne intc10
mov ah,0
call outchr
nop
nop
nop
jmp tem
intc10: call beep
jmp tem
TELNET ENDP
; Reassure user about connection to the host. Tell him what escape
; sequence to use to return and the communications port and baud
; rate being used. [19b]
DOMSG PROC NEAR
mov ah,prstr
mov dx,offset tmsg1
int dos
call escprt
mov ah,prstr
mov dx,offset tmsg3
int dos
ret
DOMSG ENDP
; Set parity for character in Register AL.
dopar: push bx
mov bx,portval
cmp [bx].parflg,parnon ; No parity? [10 start]
je parret ; Just return
cmp [bx].parflg,parevn ; Even parity?
jne dopar0
and al,07FH ; Strip parity.
jpe parret ; Already even, leave it.
or al,080H ; Make it even parity.
jmp parret
dopar0: cmp [bx].parflg,parmrk ; Mark parity?
jne dopar1
or al,080H ; Turn on the parity bit.
jmp parret
dopar1: cmp [bx].parflg,parodd ; Odd parity?
jne dopar2
and al,07FH ; Strip parity.
jpo parret ; Already odd, leave it.
or al,080H ; Make it odd parity.
jmp parret
dopar2: and al,07FH ; Space parity - turn off parity bit.
parret: pop bx
ret ; [10 end]
inicpt proc near
mov capbp,offset capbuf
mov caplft,128 ; init buffer ptr & chrs left
ret ; and return
inicpt endp
cptchr proc near ; capture routine, char in al
push di
mov di,capbp
mov byte ptr [di],al
inc di
mov capbp,di ; restore pointer
pop di
dec caplft ; decrement chars remaining
jnz cptch1 ; more room, forget this part
call cptdmp ; dump the info
call inicpt ; re-init ptrs.
cptch1: ret ; and return
cptchr endp
cptdmp proc near ; empty the capture buffer
push ax
push dx
mov ah,setdma
mov dx,offset capbuf ; the capture routine buffer
int dos
mov ah,writef
mov dx,offset cptfcb
int dos ; write out the block
;*** must be fixed... check error returns, disable capturing,
;*** figure out how to put dma address back
mov dx,offset buff
mov ah,setdma
int dos ; put dma back
pop dx
pop ax
ret
cptdmp endp
clscpt proc near
test flags.capflg,0FFH ; doing capture
jnz clscp1 ; yes, go ahead
mov dx,offset erms22
mov ah,prstr
int dos
jmp rskp
clscp1: mov ah,cmcfm
call comnd
jmp r
clscpi: mov al,'Z'-64 ; control-z for eof...
call cptchr ; output to file
mov al,caplft
cmp al,128 ; is buffer empty?
je clscp2 ; yes, forget this stuff
call cptdmp ; dump buffer (preserves registers)
clscp2: mov ah,0
sub word ptr cptfcb+16,ax ; subtract remaining from low filsize
sbb word ptr cptfcb+18,0 ; and from high size (with borrow)
mov ah,closf
mov dx,offset cptfcb
int dos ; close up file
mov flags.capflg,0 ; no longer capturing...
jmp rskp ; and return
clscpt endp
; enter with ax/scan code to define, si/ pointer to definition, cx/ length
; of definition. Defines it in definition table.
;*** somewhere should check for overflow etc of defbuf, and of scntab
defkey proc near
push ax ; save scan code
mov ax,ds
mov es,ax ; address data segment
mov di,defptr ; this is where the def gets built
inc di ; leave a byte for length
defk1: lodsb ; get a byte from the source
cmp al,'\' ; escape?
jne defk2 ; no, just deposit him
dec cx ; count available is one less
call trnesc ; translate the escape sequence
inc cx ; account for '\' (loop will decrement again).
defk2: stosb ; drop off character
loop defk1 ; and keep going while we have more
mov ax,di ; get ptr to end
dec ax ; back up pointer to end
mov si,defptr ; pick up old ptr value
sub ax,si ; this is actual length used
mov byte ptr [si],al ; fill in length of entry
mov defptr,di ; this is next free byte
; definition address is in si
pop ax ; recover scan code
mov cx,targ.klen ; length of scan table
jcxz defk4 ; not there, just go add it
mov di,offset scntab ; the scan code table
repne scasw ; look for this one
jne defk4 ; not defined already
sub di,offset scntab + 2 ; compute index into table
mov deftab[di],si ; fill in address
ret ; and return
defk4: mov di,targ.klen ; get length again
inc di
cmp di,scntlen
ja defk5 ;** ignore def if over size
mov targ.klen,di ; update length
shl di,1 ; double for word index
mov scntab[di-2],ax ; put scan code into table
mov deftab[di-2],si ; and fill in definition
defk5: ret ; that's it
defkey endp
; enter with si/ source pointer, cx/ count
; converts an escape sequence, updates all pointers
trnesc proc near
push bx
push dx ; preserve these
mov al,0 ; this is current accumulation
jcxz trnes2 ; empty string, forget it
mov bl,3 ; this is max # of digits to use
mov bh,8 ; this is radix
trnes1: mov dl,[si]
cmp dl,'0'
jb trnes2 ; out of range, stop here
cmp dl,'7'
ja trnes2
inc si ; accept character
sub dl,'0' ; convert to binary
mul bh ; shift accumulation
add al,dl ; add to accumulation
dec bl ; decrement digit counter
loopnz trnes1 ; and keep trying
trnes2: pop dx
pop bx
ret ; and return
trnesc endp
; 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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msterm.asm
/bin/echo -n ' '; /bin/ls -ld msterm.asm
fi
/bin/echo 'Extracting msapc.hlp'
sed 's/^X//' <<'//go.sysin dd *' >msapc.hlp
This note describes the capabilities of MS-DOS MSKermit as implemented for
the NEC Advanced Personal Computer (APC). The APC system dependent portion of
the code (both port and terminal handlers) resides in the file MSXAPC.ASM.
This is the only module required in addition to those that all implementations
need.
MSKermit on the APC supports both the standard serial port (as port 1) and
the optional (H14) add-on serial port (as port 2). Port selection is
performed using the SET PORT command. Any baud rate up to 38400 is legal
although 38400 has never been tested and may not work well. The port is
always configured as 8 data bits, no parity, and 1 stop bit. Any necessary
parity is supplied by Kermit.
The interrupt vector used by the optional port is jumper-selectable. Kermit
is set up to use IR8 by default, so if another vector is required the
MSXAPC.ASM file must be altered and reassembled. The changes are well
commented, and only amount to changing the value of a conditional.
Terminal mode support on the APC is relatively primitive. The only provisions
that have been made for emulation are in the operating system firmware, which
supports a limited subset of both VT100/ANSI and ADM-3A commands.
Two pages of screen memory and rollback are also provided by the firmware.
Control-uparrow scrolls back one line, while control-downarrow scrolls forward
a line.
Screen printing is performed by the CRTDUMP resident extension to MS-DOS
using the control-print command. The print (or control-P) key alone causes
Kermit to toggle echoing of the screen display to the printer.
Key redefinition is provided, but only for the keyboard keys. The function
keys must be defined using the system's KEY program. There is no direct
access to the keyboard's scan codes on the APC, so instead each key is
redefined by its ASCII value, limiting the usefulness of this function.
The default escape character is control-]. Bugs in the firmware prevent
this control sequence from being returned to the program, however, so it
is necessary to instead use the left arrow key which sends the control-]
code. Another alternative is to redefine the escape character in your
MSKERMIT.INI initialization file.
Despite these limitations, MSKermit for the APC is being released so that
the benefits of its file transfer capability are available to APC MS-DOS
users. It is to be hoped that these users will take it on themselves to
enhance the capabilities.
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msapc.hlp
/bin/echo -n ' '; /bin/ls -ld msapc.hlp
fi
/bin/echo 'Extracting mskermit.hlp'
sed 's/^X//' <<'//go.sysin dd *' >mskermit.hlp
KERMIT VERSION 2.26 FOR MS-DOS AND PC-DOS
July 26, 1984
Kermit-MS is a program that provides terminal emulation and file trans-
fer for Intel 8088- and 8086-based microcomputers running the MS-DOS or
PC-DOS operating system. The Kermit file transfer protocol was
developed and the Kermit-MS program were developed at the Columbia
University Center for Computing Activities.
* Program Operation
Kermit-MS can be run interactively, from a batch file, or as an
"external" DOS command. Commands consist of one or more fields,
separated by "whitespace" -- one or more spaces or tabs. Upon startup,
the program executes any commands found in the file MSKERMIT.INI in the
current path.
X. Interactive Operation:
To run Kermit-MS interactively, invoke the program from DOS command
level by typing its name. When you see the command's prompt,
"Kermit-MS>", you may type Kermit commands repeatedly until you are
ready to exit the program. You can use these special characters while
typing commands.
BACKSPACE Delete the character most recently typed. May be typed
repeatedly to delete backwards. You may also use DELETE,
RUBOUT, or equivalent keys.
CTRL-W Delete the most recent "word", or field, on the command line.
May be typed repeatedly.
CTRL-U Delete the entire command line.
CTRL-C Cancel the current command and return to the "Kermit-MS>"
prompt.
? Type a brief message describing what you are expected to type in
the current field.
ESC If enough characters have been supplied in the current field
(keyword or file name) to uniquely identify it, supply the
remainder of the field and position to the next field of the
command. Otherwise, sound a beep.
= Wildcard character for matching single characters in filenames,
equivalent to MS-DOS "?".
X. Command Line Invocation:
Kermit-MS may also be invoked with command line arguments from DOS com-
mand level, for instance:
A>kermit send foo.bar
or
A>kermit set port 1, set baud 9600, connect
When invoked with command line arguments, Kermit-MS will behave as if it
were an external DOS command, like MODE. Note that several commands may
be given on the command line, separated by commas.
* Kermit-MS Commands
Kermit-MS V2.26 has the following commands:
BYE to remote server.
CLOSE log file and stop logging remote session.
CONNECT as terminal to remote system.
DEFINE macros of Kermit-MS commands.
DELETE local files.
DIRECTORY listing of local files.
DO a macro expansion.
EXIT from Kermit-MS.
FINISH Shut down remote server.
GET remote files from server.
HELP about Kermit-MS.
LOCAL prefix for local file management commands.
LOG remote terminal session.
LOGOUT remote server.
PUSH to MS-DOS command level.
QUIT from Kermit-MS
RECEIVE files from remote Kermit.
REMOTE prefix for remote file management commands.
RUN an MS-DOS program.
SEND files to remote Kermit.
SERVER mode of remote operation.
SET various parameters.
SHOW various parameters.
SPACE inquiry.
STATUS inquiry.
TAKE commands from file.
The following SET commands are available in Kermit-MS:
BAUD Communications port line speed
BELL Whether to beep at the end of a transaction
BLOCK-CHECK-TYPE Level of error checking for file transfer
DEBUG Display packet contents during file transfer
DEFAULT-DISK Default disk drive for file i/o
DESTINATION Default destination device for incoming files
END-OF-LINE Packet terminator
EOF Method for determining or marking end of file
ESCAPE Escape character for CONNECT
FLOW-CONTROL Enable or disable XON/XOFF
HANDSHAKE Half-duplex line turnaround option
HEATH19 Heath/Zenith-19 terminal emulation
INCOMPLETE What to do with an incompletely received file
KEY Specify key redefinitions, or "keystroke macros"
LOCAL-ECHO Specify which host does the echoing during CONNECT
PARITY Character parity to use
PORT Select a communications port
PROMPT Change the "Kermit-MS>" prompt to something else
RECEIVE Request remote Kermit to use specified parameters
REMOTE For running Kermit-MS interactively from back port
SEND Use the specified parameters during file transfer
TAKE-ECHO Control echoing of commands from TAKE files
TIMER Enable/disable timeouts during file transfer
WARNING Specify how to handle filename collisions
The STATUS command shows the values of parameters which may be SET.
* Command Macros
Kermit-MS provides a facility for combining commands into "macros."
Command macro definitions may be included in your MSKERMIT.INI file,
TAKEn explicitly from a specified file, or typed interactively, and may
be invoked with the DO command.
* Command Macros
Kermit-MS command macros are constructed with the DEFINE command. The
syntax is
DEFINE macro-name [command [, command [, ...]]]
Any Kermit-MS commands may be included. Example:
define telenet set parity mark, set baud 1200, connect
A Kermit-MS command macro is invoked using the DO command. For in-
stance, Kermit-MS comes with a predefined macro to allow convenient
setup for IBM communications; to invoke it, you would type
do ibm
The IBM macro is defined as "parity mark, handshake xon, local-echo on,
timer on". You can delete or replace this definition by adding a new
(perhaps null) definition, such as
define ibm parity even, handshake cr, local-echo on, timer on]
or
define ibm
Command macro definitions can be displayed with the SHOW MACROS command.
* Terminal Emulation
Here are the terminal emulation options for the systems presently sup-
ported by Kermit-MS:
System EscChar Cabilities Terminal Service
IBM PC, XT ^] R M P K Heath19 emulation
DEC Rainbow ^] R P K VT102 firmware
HP-150 ^] R HP-2623 firmware
Wang PC ^A Wang firmware
Generic DOS ^] Depends on system
Under Capabilities, R means rollback, M means mode line, P means printer
control, and K means key redefinition.
IBM PC/XT Kermit can disable Heath-19 emulation and use an external con-
sole device driver like ANSI.SYS instead.
The escape character is used to regain the attention of Kermit-MS. When
you type the escape character, Kermit-MS waits for you to follow it with
a single character command:
? Help -- prints the available single-character commands.
C Close the connection and return to Kermit-MS prompt level.
S Show the status of the connection.
B Send a BREAK signal to the port.
0 (the digit zero) Send a NUL (ASCII 0) to the port.
Q Temporarily quit logging the remote session.
R Resume logging the remote session.
M Toggle the mode line, i.e. turn it off if it is on & vice versa.
^] (or whatever you have set the escape character to be)
Typing the escape character twice sends one copy of it to the con-
nected host.
Typing any other character (except the space bar, which is the "null
command") after the escape character will cause Kermit-MS to beep, but
will do no harm. The escape character can be changed to something other
than Control-Rightbracket by using the SET ESCAPE command.
Kermit-MS includes several advanced features for use during terminal
emulation, including screen scroll, printer control, and key redefini-
tions.
X. Screen Scroll
Kermit-MS provides several pages of screen memory, which may be scrolled
up and down using keys as follows:
Function IBM PC/XT Rainbow HP-150
Screen Down PgDn PrevScreen Prev
Line Down Ctrl-PgDn Ctrl-PrevScreen Shift-UpArrow
Screen Up PgUp NextScreen Next
Line Up Ctrl-PgUp Ctrl-NextScreen Shift-DownArrow
Top of Memory Home
Bottom of Memory End
X. Printer Control
A locally attached printer may be controlled in the normal manner, on
most systems. Pushing the "Print Screen" key (shifted on some systems)
will cause the current contents of the screen to be printed or spooled;
holding down CTRL while depressing Print Screen will start or stop the
spooling of incoming characters to the printer.
CTRL-Print-Screen can be simulated with the Kermit-MS LOG PRN and CLOSE
commands.
X. Key Redefinitions
Use SHOW KEY to find out the scan code of the key you want to redefine,
then use SET KEY SCAN xxx to define the new value. Control characters
are entered in the definition string as \ooo (a backslash followed by 2
or 3 octal digits denoting the ASCII value of the character).
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 mskermit.hlp
/bin/echo -n ' '; /bin/ls -ld mskermit.hlp
fi
/bin/echo 'Extracting msmkboo.c'
sed 's/^X//' <<'//go.sysin dd *' >msmkboo.c
X/* MSNKBOO.C
*
* This program takes a file and encodes it into printable characters.
* These printable files can then be decoded by the programs MSPCBOOT.BAS
* or MSPCTRAN.BAS as the need may be. The file is encoded by taking
* three consecutive eight bit bytes and dividing them into four six bit
* bytes. An ASCII zero was then added to the resulting four characters.
* to make them all printable ASCII characters in the range of the
* character zero to the character underscore. In order to reduce the
* size of the file null repeat count was used. The null repeat count
* compresses up to 78 consecutive nulls into only two characters. This
* is done by using the character tilde (~) as an indication that a group
* of repetitive nulls has occured. The character following the tilde is
* number of nulls in the group. The number is also converted in to a
* printable character by adding an ASCII zero. The highest number of
* nulls is therefore the highest printable character tilde. This is
* equal to tilde minus zero nulls or 78 nulls. Because of the three
* byte to four byte encoding the repeat counting can only start with
* the first character of a three byte triplet.
*
* This C program was written specifically for the DEC-20 and as such
* will not easily be transported to another system. The main problem
* lies in the file I/O routines. It is necessary to make sure that
* untranslated eight bit bytes are input from the input file. The
* main change would be to make the OPEN statement reflect this for
* your particular system and brand of UNIX and C. The rest of the
* program should be transportable with little or no problems.
*
*/
#include <stdio.h> /* Standard UNIX i/o definitions */
#include <file.h>
X/* Symbol Definitions */
#define MAXPACK 80 /* Maximum packet size */
#define MYRPTQ '~' /* Repeat count prefix I will use */
#define DATALEN 78 /* Length of data buffer */
#define TRUE -1 /* Boolean constants */
#define FALSE 0
X/* Macros */
#define tochar(ch) ((ch) + '0')
X/* Global Variables */
int size, /* Size of present data */
maxsize, /* Max size for data field */
nc, /* Number of input chars */
oc, /* Number of output chars */
fd, /* File pointer of file to read/write */
ofd,
rpt, /* repeat count */
rptq, /* repeat quote */
rptflg, /* repeat processing flag */
eoflag, /* Set when file is empty. */
otot; /* What char number we are processing. */
char t, /* Current character */
one,
two,
three,
*filnam, /* Current file name */
*ofile,
packet[MAXPACK]; /* Packet buffer */
main(argc,argv) /* Main program */
int argc; /* Command line argument count */
char **argv; /* Pointers to args */
{
char sfile(); /* Send file routine & ret code */
if (--argc != 2) usage(); /* Make sure there's a command line. */
rptq = MYRPTQ; /* Repeat Quote */
rptflg = TRUE; /* Repeat Count Processing Flag */
filnam = *++argv; /* Get file to send */
ofile = *++argv; /* Output file to create */
sfile();
printf("Done, in: %d, out: %d, efficiency: %.2f%%\n",nc,oc,(100.0*nc)/oc);
}
X/*
S F I L E - Send a whole file
*/
char sfile() /* Send a file */
{
char *i;
fd = open(filnam,FATT_RDONLY|FATT_BINARY|FATT_DEFSIZE);
if (fd < 0) /* Report any errors */
{
printf("\n?Error opening file \"%s\"\n",filnam);
exit(1);
}
ofd = open(ofile,FATT_WRONLY|FATT_CREATE|FATT_BINARY);
if (ofd < 0)
{
printf("\n?error opening file \"%s\"\n",ofile);
exit(1);
}
oc = strlen(filnam); /* Get the string length. */
for (i=filnam; *i != '\0'; i++) /* Uppercase the file name. */
if (*i >= 'a' && *i <= 'z') *i ^= 040;
write(ofd,filnam,oc); /* Write the file name in the file. */
write(ofd,"\r\n",2);
maxsize = DATALEN - 5;
rpt = 0; /* Zero the repeat count. */
oc = nc = 0; /* Output & input character counts. */
otot = 1; /* Start with first char of triplet. */
while (getbuf() > 0) /* While not EOF, get a packet. */
{
while (size < DATALEN - 1) packet[size++] = ' ';
packet[size++] = '\r'; /* Explicit CRLF. */
packet[size++] = '\n';
packet[size] = '\0';
oc += size; /* Count output size. */
write(ofd,packet,size); /* Write the packet to the file. */
printf("%d: %s",size,packet); /* Print on the screen for testing. */
}
}
X/*
G E T B U F -- Do one packet.
*/
getbuf() /* Fill one packet buffer. */
{
if (eoflag != 0) return(-1); /* If at the end of file, stop. */
size = 0;
while((t = getch()) >= 0) /* t == -1 means EOF. */
{
nc++; /* Count the character. */
process(t); /* Process the character. */
if (size >= maxsize) /* If the packet is full, */
{
packet[size] = '\0'; /* terminate the string. */
return(size);
}
}
eoflag = -1; /* Say we hit the end of the file. */
process(0); /* Clean out any remaining chars. */
process(0);
process(' ');
packet[size] = '\0'; /* Return any partial final buffer. */
return(size);
}
X/* P R O C E S S -- Do one character. */
process(a)
char a;
{
if (otot == 1) /* Is this the first of three chars? */
{
if (a == 0) /* Is it a null? */
{
if (++rpt < 78) /* Below max nulls, just count. */
return;
else if (rpt == 78) /* Reached max number, must output. */
{
packet[size++] = rptq; /* Put in null repeat char and */
packet[size++] = tochar(rpt); /* number of nulls. */
packet[size] = '\0';
rpt = 0;
return;
}
}
else
{
if (rpt == 1) /* Just one null? */
{
one = 0; /* Say the first char was a null. */
two = a; /* This char is the second one. */
otot = 3; /* Look for the third char. */
rpt = 0; /* Restart null count. */
return;
}
if (rpt > 1) /* Some number of nulls? */
{
packet[size++] = rptq; /* Insert the repeat prefix */
packet[size++] = tochar(rpt); /* and count. */
packet[size] = '\0';
rpt = 0; /* Reset repeat counter. */
}
one = a; /* Set first character. */
otot = 2; /* Say we are at the second char. */
}
}
else if (otot == 2)
{
two = a; /* Set second character. */
otot = 3; /* Say we are at the third char. */
}
else
{
three = a;
otot = 1; /* Start over at one. */
pack(one,two,three); /* Pack in the three characters. */
}
}
X/* This routine does the actual three character to four character encoding.
* The concept is relatively straight forward. The first output character
* consists of the first (high order or most significant) six bits of the
* first input character. The second output character is made from the
* remaining two low order bits of the first input character and the first
* four high order bits of the second input character. The third output
* character is built from the last four low order bits of the second input
* character and the two high order bits of the third input character. The
* fourth and last output character consists of the six low order bit of
* the third input character. In this way the three eight bit input char-
* acters (for a total of 24 bits) are divided into four six bit output
* characters (also for a total of 24 bits). In order to make the four
* output characters printable an ASCII zero is then added to each of them.
*
*/
pack(x,y,z)
char x,y,z;
{
packet[size++] = tochar((x >> 2) & 077);
packet[size++] = tochar(((x & 003) << 4) | ((y >> 4) & 017));
packet[size++] = tochar(((y & 017) << 2) | ((z >> 6) & 003));
packet[size++] = tochar(z & 077);
packet[size] = '\0';
}
getch() /* Get next (or pushed) char. */
{
char a;
return((read(fd,&a,1) > 0) ? a : -1); /* (or -1 if EOF) */
}
usage() /* Give message if user makes */
{ /* a mistake in the command. */
fprintf(stderr,"usage: msmkboo inputfile outputfile\n");
exit(1);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msmkboo.c
/bin/echo -n ' '; /bin/ls -ld msmkboo.c
fi
/bin/echo 'Extracting mspctran.bas'
sed 's/^X//' <<'//go.sysin dd *' >mspctran.bas
1 'Use this BASIC program on the PC if you have the printable file
2 'MSKERMIT.BOO already on the PC to convert it to an executable
3 'file. This program takes about 30 minutes to run on a PC with
4 'floppy disks.
5 ' Bill Catchings, June 1984
6 ' Columbia University Center for Computing Activities
10 t$ = time$ ' Save the time.
20 defint a-z ' Integer to gain some speed.
30 n$ = chr$(0)
40 z = asc("0")
50 t = asc("~")-z
60 def fnuchr%(a$)=asc(a$)-z
70 open "MSKERMIT.BOO" for input as #1
100 input#1,f$ ' Is this the right file?
110 if len(f$) > 20 then goto 900
120 open f$ for output as #2
130 print "Outputting to "+f$
200 if eof(1) then goto 800 ' Exit nicely on end of file.
210 input#1,x$ ' Get a line.
220 y$ = "" ' Clear the output buffer.
230 goto 400
300 print#2,y$; ' Print output buffer to file.
310 goto 200 ' Get another line.
400 if len(x$) < 4 goto 300 ' Is the input buffer empty?
410 a = fnuchr%(x$)
420 if a = t then goto 700 ' Null repeat character?
430 q$=mid$(x$,2,3) ' Get the quadruplet to decode.
440 x$=mid$(x$,5)
450 b = fnuchr%(q$)
460 q$ = mid$(q$,2)
470 c = fnuchr%(q$)
480 q$ = mid$(q$,2)
490 d = fnuchr%(q$)
500 y$ = y$ + chr$(((a * 4) + (b \ 16)) and 255) ' Decode the quad.
510 y$ = y$ + chr$(((b * 16) + (c \ 4)) and 255)
520 y$ = y$ + chr$(((c * 64) + d) and 255)
530 goto 400 ' Get another quad.
700 x$ = mid$(x$,2) ' Expand the nulls.
710 r = fnuchr%(x$) ' Get the number of nulls.
715 print " Null: ",r
720 x$ = mid$(x$,2)
730 for i=1 to r ' Loop, adding nulls to string.
740 y$ = y$ + n$
750 next
760 print#2,y$; ' Output the nulls to the file.
770 y$ = "" ' Clear the output buffer.
780 goto 400
800 print "Processing complete, elapsed time: "+t$+" to "+time$
810 print "Output in "+f$
820 close #1,#2
830 goto 9999
900 print "?The version of the MSKERMIT.BOO file is incorrect"
910 goto 820
9999 end
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 mspctran.bas
/bin/echo -n ' '; /bin/ls -ld mspctran.bas
fi
/bin/echo 'Extracting msrbboo.bas'
sed 's/^X//' <<'//go.sysin dd *' >msrbboo.bas
1 DEFINT A-Z:ZRUBOUT$=CHR$(8)+" "+CHR$(8):ZESCAPE$=CHR$(27):'Sreen utility definitions B.E.
2 ZLEADIN$=ZESCAPE$+"[":ZCLEAR$=ZLEADIN$+"J":ZHOME$=ZLEADIN$+"0;0H"
3 ZDOUBLE1$=ZESCAPE$+"#3":ZDOUBLE2$=ZESCAPE$+"#4":WIDTH 255
4 ZBOLD$=ZLEADIN$+"1m":ZBLINK$=ZLEADIN$+"5m":ZSAVE$=ZESCAPE$+"7"
5 ZREVERSE$=ZLEADIN$+"7m":ZOFF$=ZLEADIN$+"0m":ZREST$=ZESCAPE$+"8"
6 ZGRAPHON$=ZESCAPE$+"(0":ZGRAPHOFF$=ZESCAPE$+"(B":ZBACKER$=ZLEADIN$+"0K"
7 ZKEYPAD$=ZESCAPE$+"=":ZBELL$=CHR$(7):ZCLRLIN$=ZLEADIN$+"2K"
8 DEF FNXY$(ZX,ZY)=ZLEADIN$+MID$(STR$(INT(ZX)),2)+";"+MID$(STR$(INT(ZY)),2)+"H":'Cursor Adressing function (ZX=Line[1..24],ZY=Column[1..80])
9 GOTO 25:'This to be modified to GOTO Start of program <===================
10 ZSTRING$="":ZORGL=ZLENGTH:PRINT ZSAVE$+ZREVERSE$+STRING$(ZORGL,95)+ZOFF$+STRING$(ZORGL,8);:'General Input-GOSUB (Input:ZLENGTH, OUTPUT:ZLENGTH,ZSTRING,ZNUMBER,ZRANDOM)
11 ZTEMP$=INKEY$:ZRANDOM=(ZRANDOM MOD 2000)+1:IF LEN(ZTEMP$)=0 THEN 11'Wait for Char
12 IF ASC(ZTEMP$)=127 OR ASC(ZTEMP$)=8 THEN 17 ELSE IF ASC(ZTEMP$)=21 THEN PRINT ZREST$+ZBACKER$;:ZLENGTH=ZORGL:GOTO 10 ELSE PRINT ZTEMP$;'RUBOUT
13 IF ASC(ZTEMP$)=3 THEN GOTO 9999 ELSE IF ZTEMP$ >= "a" THEN ZTEMP$=CHR$(ASC(ZTEMP$)-32)'Uppercase Modify GOTO xx to Control-C intercept <=====================
14 IF ASC(ZTEMP$)=13 THEN PRINT:GOTO 16'RETURN finishes
15 ZSTRING$=ZSTRING$+ZTEMP$:ZLENGTH=ZLENGTH-1:IF ZLENGTH >0 THEN 11
16 ZLENGTH=LEN(ZSTRING$):ZNUMBER=VAL(ZSTRING$): RETURN
17 IF LEN(ZSTRING$)>0 THEN ZLENGTH=ZLENGTH +1:ZSTRING$=LEFT$(ZSTRING$,(LEN(ZSTRING$)-1)):PRINT ZRUBOUT$;:GOTO 11 ELSE PRINT ZBELL$;: GOTO 11'Cleanup after RUBOUT
18 'End of VT100 definitions *****
19 'Use this BASIC program on the CP/M side of the Rainbow (with
20 'Microsoft MBasic-86) to translate the MSRB100.BOO file on
21 'your CP/M disk to binary .EXE format, then from the MS-DOS
22 'side use RDCPM to transfer the result to the MS-DOS file
23 'system. This program takes about 30 minutes to run on a Rainbow
24 'with floppy disks.
25 '- Bill Catchings, CU; modified for Rainbow by Bernie Eiben, DEC.
26 PRINT ZHOME$+ZCLEAR$;"Rainbow 4for3 Code Expander Version 1"
30 PRINT:PRINT: N$ = CHR$(0)
40 Z = ASC("0")
50 T = ASC("~")-Z
60 DEF FNUCHR%(A$)=ASC(A$)-Z
61 PRINT "FILE-NAME to Expand : ";:ZLENGTH=13:GOSUB 10:'Get Input
70 OPEN "I",1,ZSTRING$
100 INPUT#1,F$ ' Is this the right file?
110 IF LEN(F$) > 20 THEN GOTO 900
120 OPEN "O",2,F$ ' Ouput-name from file
130 PRINT "Outputting to "+F$
200 IF EOF(1) THEN GOTO 800 ' Exit nicely on end of file.
210 INPUT#1,X$ ' Get a line.
220 Y$ = "" ' Clear the output buffer.
230 GOTO 400
300 PRINT#2,Y$; ' Print output buffer to file.
310 GOTO 200 ' Get another line.
400 IF LEN(X$) < 4 GOTO 300 ' Is the input buffer empty?
410 A = FNUCHR%(X$)
420 IF A = T THEN GOTO 700 ' Null repeat character?
430 Q$=MID$(X$,2,3) ' Get the quadruplet to decode.
440 X$=MID$(X$,5)
450 B = FNUCHR%(Q$)
460 Q$ = MID$(Q$,2)
470 C = FNUCHR%(Q$)
480 Q$ = MID$(Q$,2)
490 D = FNUCHR%(Q$)
500 Y$ = Y$ + CHR$(((A * 4) + (B \ 16)) AND 255) ' Decode the quad.
510 Y$ = Y$ + CHR$(((B * 16) + (C \ 4)) AND 255)
520 Y$ = Y$ + CHR$(((C * 64) + D) AND 255)
530 GOTO 400 ' Get another quad.
700 X$ = MID$(X$,2) ' Expand the nulls.
710 R = FNUCHR%(X$) ' Get the number of nulls.
715 PRINT FNXY$(6,5)+ZCLRLIN$;" Null: ",R
720 X$ = MID$(X$,2)
730 FOR I=1 TO R ' Loop, adding nulls to string.
740 Y$ = Y$ + N$
750 NEXT
760 PRINT#2,Y$; ' Output the nulls to the file.
770 Y$ = "" ' Clear the output buffer.
780 GOTO 400
800 PRINT "Processing complete"
810 PRINT "Output in "+F$
820 CLOSE #1,#2
830 GOTO 9999
900 PRINT "?The FORMAT of the ",ZSTRING$," file is incorrect"
910 GOTO 820
9999 END
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msrbboo.bas
/bin/echo -n ' '; /bin/ls -ld msrbboo.bas
fi
/bin/echo 'Extracting msrbboo.hlp'
sed 's/^X//' <<'//go.sysin dd *' >msrbboo.hlp
Date: Thu 13 Sep 84 16:32:44-EDT
From: Frank da Cruz <SY.FDC@CU20B.ARPA>
Subject: Rainbow MS-DOS Kermit Bootstrapping
To: Info-Kermit@CU20B
Users of DEC Rainbow 100s have complained that there's no bootstrapping
procedure they can use for getting the new MS-DOS Kermit onto the Rainbow
over the communication line. The problem was that Basic was not available
for MS-DOS on the Rainbow (or else it was so new that no one had it yet),
so the Microsoft Basic program we provided for decoding the .BOO (4-for-3
encoded) binary file could not be used on the Rainbow.
Now, thanks to Bernie Eiben at DEC, we have a version of the Basic program
that will run on the CP/M-86 side of the Rainbow. It's a reworking of
MSPCTRAN.BAS, which assumes that you already have the .BOO file on your
CP/M disk. It builds an .EXE file, which you can then move to the MS-DOS
side of your Rainbow by booting MS-DOS and then using RDCPM to get the
file from the CP/M-format disk. How you get the .BOO file onto the CP/M
disk in the first place is another question. Either you use some file
capture utility -- commercial or otherwise -- or else you go through the
DDT bootstrap procedure given for CP/M-80 Kermit (since the Rainbow is
also a CP/M-80 system).
Bernie's program is in KER:MSRBBOO.BAS.
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msrbboo.hlp
/bin/echo -n ' '; /bin/ls -ld msrbboo.hlp
fi
/bin/echo 'Extracting msrbemacs.ini'
sed 's/^X//' <<'//go.sysin dd *' >msrbemacs.ini
; EMACS function key setup for Kermit-MS/Rainbow
;
; C-@ (set mark) on SELECT
set key select
\00
;
; M-h (select region) on CTRL-SELECT
set key scan 1313
\33h
;
; C-U 12 C-X C-I (rigidly indent region 12 spaces) on TAB
set key scan 9
\25\61\62\30\11
; C-X C-I (rigidly indent region) on SHIFT-TAB
set key scan 521
\30\11
;
; C-S (forward search) on FIND
set key find
\23
;
; C-R (reverse search) on CTRL-FIND
set key scan 1307
\22
;
; M-D (delete word) on REMOVE
set key remove
\33d
;
; M-K (delete sentence) on CTRL-REMOVE
set key scan 1311
\33k
;
; C-P (up line) on uparrow
set key scan 295
\20
;
; M-[ (up paragraph) on CTRL-uparrow
set key scan 1319
\33[
;
; C-X [ (up page) on SHIFT-uparrow
set key scan 807
\30[
;
; M-< (top of file) on CTRL-SHIFT-uparrow
set key scan 1831
\33<
;
; C-B (back character) on leftarrow
set key scan 301
\02
;
; C-A (beginning of line) on CTRL-leftarrow
set key scan 1325
\01
;
; M-A (back sentence) on SHIFT-leftarrow
set key scan 813
\33a
;
; C-N (next line) on downarrow
set key scan 297
\16
; M-] (down paragraph) on CTRL-downarrow
set key scan 1321
\33]
;
; C-X ] (down page) on SHIFT-downarrow
set key scan 809
\30]
;
; M-> (end of file) on CTRL-SHIFT-downarrow
set key scan 1833
\30>
;
; C-F (forward character) on rightarrow
set key scan 299
\06
;
; C-E (end of line) on CTRL-rightarrow
set key scan 1323
\05
;
; M-E (end of sentence) on SHIFT-rightarrow
set key scan 811
\33e
;
; C-X E (do keyboard macro) on DO
set key scan 257
\30e
;
; C-U C-X E (do keyboard macro 4x) on CTRL-DO
set key scan 1281
\25\30e
;
; C-U 8 C-X E (do keyboard macro 8x) on SHIFT-DO
set key scan 769
\25\70\30e
;
; C-U C-U C-X E (do keyboard macro 16x) on CTRL-SHIFT-DO
set key scan 1793
\25\25\30e
;
; ^_ on HELP
set key scan 256
\37
;
; C-X C-Z on EXIT
set key scan 271
\30\32
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msrbemacs.ini
/bin/echo -n ' '; /bin/ls -ld msrbemacs.ini
fi
/bin/echo 'Extracting msxapc.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxapc.asm
; Kermit system dependent module for NEC Advanced Personal Computer (APC)
; Ron Blanford, University of Washington, August 1984
public serini, serrst, clrbuf, outchr, coms, vts, dodel,
public ctlu, cmblnk, locate, lclini, prtchr, dobaud, clearl,
public dodisk, getbaud, beep,
public count, xofsnt, puthlp, putmod, clrmod, poscur
public sendbr, term, machnam, setktab, setkhlp, showkey
include msdefs.h
false equ 0
true equ 1
; port assignments for 8251 serial controllers
; Standard interface
mndata equ 30H ; Data port (read/write)
mnst1a equ 32H ; Status port (when read)
mncmda equ 32H ; Command port (when written)
mnst2a equ 34H ; Alternate status port (when read)
mnmska equ 34H ; Mask port (when written)
mntdca equ 36H ; Transmit disable port (write only)
; Optional (H14) interface
mndatb equ 31H ; Data port (read/write)
mnst1b equ 33H ; Status port (when read)
mncmdb equ 33H ; Command port (when written)
mnst2b equ 35H ; Alternate status port (when read)
mnmskb equ 35H ; Mask port (when written)
mntdcb equ 37H ; Transmit disable port (write only)
; Status bits from mnst1
txrdy equ 01H ; Bit for output ready.
rxrdy equ 02H ; Bit for input ready.
; Command values for mncmd
ccmd equ 37H ; RTS & DTR high, RX & TX enabled, reset ERR
cbrk equ 08H ; break enabled
cmode equ 40H ; enable mode reset
mmode equ 4EH ; 16x rate, 8 data, no parity, 1 stop
; Mask values for mnmsk
txmsk equ 01H ; disables transmit ready interrupt
rxmsk equ 02H ; disables receive ready interrupt
tbemsk equ 04H ; disables transmit buffer empty interrupt
; port assignments for 8253 timers
; Standard interface
tmdata equ 2BH ; data port
tmcmda equ 27H ; command port
; Optional (H14) interface
tmdatb equ 61H ; data port
tmcmdb equ 67H ; command port
; values for tmcmd which select timer channel and mode
tmsela equ 76H ; Channel 1, mode 3 (standard port)
tmselb equ 36H ; Channel 0, mode 3 (optional port)
; Timer information for current port selection
tmrinfo struc
tmdat dw 0 ; data port
tmcmd dw 0 ; command port
tmsel db 0 ; byte which selects channel and mode
tmrinfo ends
; port assignments for 8259 interrupt controllers
; Standard interface
intcmda equ 20H ; Command port (master controller)
intmska equ 22H ; Mask port
ictmsk equ 08H ; Timer interrupt mask (to master)
icsmska equ 02H ; Standard serial interrupt mask (to master)
icsvcta equ 11H ; Interrupt vector for standard interface
; Optional (H14) interface
; The interrupt request vector for the optional (H14) serial interface is
; jumper-selectable to any of vectors IR2, IR5, IR8, or IR12. NEC recommends
; that IR8 be used, so that has been selected as the default here. To use
; any of the other vectors, set the following conditionals appropriately.
; Only one of the following should be true:
IR2 equ false ; interrupt vector 2
IR5 equ false ; interrupt vector 5
IR8 equ true ; interrupt vector 8
IR12 equ false ; interrupt vector 12
IF IR2
intcmdb equ 20H ; Command port (master controller)
intmskb equ 22H ; Mask port
icsmskb equ 04H ; Interrupt mask
icsvctb equ 12H ; Interrupt table index
ENDIF
IF IR5
intcmdb equ 20H ; Command port (master controller)
intmskb equ 22H ; Mask port
icsmskb equ 20H ; Interrupt mask
icsvctb equ 15H ; Interrupt table index
ENDIF
IF IR8
intcmdb equ 28H ; Command port (slave controller)
intmskb equ 2AH ; Mask port
icsmskb equ 02H ; Interrupt mask
icsvctb equ 19H ; Interrupt table index
ENDIF
IF IR12
intcmdb equ 28H ; Command port (slave controller)
intmskb equ 2AH ; Mask port
icsmskb equ 20H ; Interrupt mask
icsvctb equ 1DH ; Interrupt table index
ENDIF
; generic end of interrupt for intcmd
icEOI equ 20H
; miscellaneous constants
ctrlP equ 10H ; Key that toggles printer echo
mntrgh equ bufsiz*3/4 ; High XON/XOFF trigger = 3/4 of buffer full.
; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
; or port2)
; port1, port2 - portinfo structures for the corresponding ports
; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
datas segment public 'datas'
extrn drives:byte,flags:byte, trans:byte
extrn portval:word, port1:byte, port2:byte
machnam db 'NEC APC$'
nyimsg db cr,lf,'Not yet implemented$'
badbd db cr,lf,'Unimplemented baud rate$'
lstpos dw 0 ; column position for printer echoing
crlf db cr,lf,'$'
delstr db BS,' ',BS,'$' ; Delete string.
clrlin db cr,'$' ; Clear line (just the cr part).
ceolseq db esc,'[K$' ; Clear to end of line
cpseq db esc,'=rc' ; rc replaced by row and column before display
clrseq db 01EH,01AH,'$' ; Home cursor and clear screen
; The following color values were selected to look well on both monochrome
; and color monitors. In particular, the normal color should be at normal
; intensity on the monochrome monitor (green, blue, or cyan), and the bold
; color should be at bold intensity (red, purple, yellow, or white).
nrmseq db esc,'[0m$' ; reset to normal video (green)
invseq db esc,'[7m$' ; start reverse video (green)
bldseq db esc,'[19m$' ; start bold video (purple)
ourarg termarg <>
modem mdminfo <mndata,mnst1a,mncmda,0,0,0,0>
timer tmrinfo <tmdata,tmcmda,tmsela>
ourflgs db 0 ; flags for telnet options
fprint equ 80H ; echo screen output to printer
oldsera dw ? ; old serial handler for standard port
oldsega dw ? ; segment of above
oldmska db ? ; old interrupt controller mask
portina db 0 ; Has comm port been initialized.
oldserb dw ? ; old serial handler for optional port
oldsegb dw ? ; segment of same.
oldmskb db ? ; old interrupt controller mask
portinb db 0 ; Has comm port been initialized.
xofsnt db 0 ; Say if we sent an XOFF.
xofrcv db 0 ; Say if we received an XOFF.
; variables for serial interrupt handler
source db bufsiz DUP (?) ; Buffer for data from port.
srcpnt dw 0 ; Pointer in buffer (DI).
count dw 0 ; Number of chars in int buffer.
savesi dw 0 ; Save SI register here.
dw 80 DUP (?) ; local stack for interrupt processing
mnstk dw ?
mnsp dw ? ; remote stack info
mnsseg dw ?
shkbuf db 300 dup (?) ; room to display key definition
shkmsg db ' Scan code: '
shkmln equ $-shkmsg
shkms1 db cr,lf,' Definition: '
shkm1ln equ $-shkms1
setktab db 2
mkeyw 'BACKSPACE',08H
mkeyw 'SCAN',-1
setkhlp db cr,lf,'BACKSPACE, or SCAN followed by decimal ASCII code$'
comptab db 7
mkeyw '1',1
mkeyw '2',0
mkeyw 'COM1',1
mkeyw 'COM2',0
mkeyw 'H14',0
mkeyw 'OPTIONAL',0
mkeyw 'STANDARD',1
bddat label word
dw 0D30H ; 45.5 baud
dw 0C00H ; 50 baud
dw 0800H ; 75 baud
dw 0574H ; 110 baud
dw 0476H ; 134.5 baud
dw 0400H ; 150 baud
dw 0200H ; 300 baud
dw 0100H ; 600 baud
dw 0080H ; 1200 baud
dw 0055H ; 1800 baud
dw 004DH ; 2000 baud
dw 0040H ; 2400 baud
dw 0020H ; 4800 baud
dw 0010H ; 9600 baud
dw 0008H ; 19200 baud
dw 0004H ; 38400 baud (not tested - may not work)
datas ends
code segment public
extrn comnd:near, dopar:near
assume cs:code,ds:datas
; local initialization routine, called by Kermit initialization.
LCLINI PROC NEAR
cld
mov flags.vtflg,0 ; turn off heath emulation
mov dx,offset nrmseq ; set to our normal background color
call tmsg
ret
LCLINI ENDP
; this is called by Kermit initialization. It checks the
; number of disks on the system, sets the drives variable
; appropriately. The only problem is that a value of two
; is returned for single drive systems to be consistent
; with the idea of the system having logical drives A and
; B. Returns normally.
DODISK PROC NEAR
mov ah,gcurdsk ; current disk value to AL.
int dos
mov dl,al ; put current disk in DL.
mov ah,seldsk ; select current disk.
int dos ; get number of drives in AL.
mov drives,al
ret
DODISK ENDP
; show the definition of a key. The terminal argument block (which contains
; the address and length of the definition tables) is passed in ax.
; Returns a string to print in AX, length of same in CX.
; Returns normally.
; On the APC there is no direct access to the keyboard; the best we
; can do is use direct console I/O to get a key value which has already
; been translated to some extent by the operating system.
SHOWKEY PROC NEAR
push es
push ax ; save the terminal argument block
mov bx,ds
mov es,bx ; address data segment
cld
showk1: mov ah,dconio ; get scan value
mov dx,0FFH
int dos
jz showk1
mov ah,0
push ax ; save scan code
mov di,offset shkbuf ; move 'Scan code' message to buffer
mov si,offset shkmsg
mov cx,shkmln
rep movsb
call nout ; add scan code to buffer
mov si,offset shkms1 ; move 'Definition' message to buffer
mov cx,shkm1ln
rep movsb
pop ax ; retrieve scan code
pop bx ; and terminal argument block
mov cx,[bx].klen ; length of translation table
jcxz showk3 ; no table, key not defined
push di
mov di,[bx].ktab ; get table address
repne scasw ; look for scan code
mov si,di
pop di
jne showk3 ; not defined
sub si,[bx].ktab ; compute entry offset in table
sub si,2
add si,[bx].krpl ; index to replacement
mov si,[si] ; get its address
mov cl,[si] ; get its length
mov ch,0
inc si
rep movsb ; transfer replacement to display buffer
showk3: mov ax,offset shkbuf ; return address of buffer in ax
mov cx,di ; and length in cx
sub cx,ax
pop es
ret
SHOWKEY ENDP
; copy numeric value from AX to ASCII buffer indicated by DI. DI is updated.
NOUT PROC NEAR
mov dx,0 ; zero high word
mov bx,10 ; divide
div bx
push dx ; save remainder digit
or ax,ax ; anything left?
jz nout1 ; no, start output phase
call nout
nout1: pop ax ; retrieve a digit
add al,'0' ; make it ASCII
stosb ; put it in buffer
ret
NOUT ENDP
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR PROC NEAR
call chkxon ; see if we have to xon the host.
cmp count,0
jnz prtch2
jmp rskp ; No data - check console.
prtch2: pushf ; save current interrupt value
cli ; disable interrupts while manipulating pointers
mov si,savesi
lodsb ; get a byte
cmp si,offset source + bufsiz ; bigger than buffer?
jb prtch1 ; no, keep going
mov si,offset source ; yes, wrap around
prtch1: dec count
mov savesi,si
mov dx,count ; return # of chars in buffer
popf ; restore original interrupt flag
ret
PRTCHR ENDP
; local routine to see if we have to transmit an xon
CHKXON PROC NEAR
push bx
mov bx,portval
cmp [bx].floflg,0 ; doing flow control?
je chkxo1 ; no, skip all this
cmp xofsnt,false ; have we sent an xoff?
je chkxo1 ; no, forget it
cmp count,mntrgh ; below trigger?
jae chkxo1 ; no, forget it
mov ax,[bx].flowc ; ah gets xon
call outchr ; send it
nop ; ignore failure
nop
nop
mov xofsnt,false ; remember we've sent an xon.
chkxo1: pop bx ; restore register
ret ; and return
CHKXON ENDP
; Put the char in AH to the serial port. This assumes the
; port has been initialized. Should honor xon/xoff. Skip returns on
; success, returns normally if the character cannot be written.
OUTCHR PROC NEAR
mov bp,portval
cmp ds:[bp].floflg,0 ; Are we doing flow control.
je outch2 ; No, just continue.
sub cx,cx ; clear counter
outch1: cmp xofrcv,true ; Are we being held?
jne outch2 ; No - it's OK to go on.
loop outch1 ; held, try for a while
mov xofrcv,false ; timed out, force it off and fall thru.
outch2: push dx ; Save register.
sub cx,cx
mov al,ah ; Parity routine works on AL.
call dopar ; Set parity appropriately.
mov ah,al ; Don't overwrite character with status.
mov dx,modem.mdstat ; port status register
outch3: in al,dx
test al,txrdy ; Transmitter ready?
jnz outch4 ; Yes
loop outch3
jmp outch5 ; Timeout
outch4: mov al,ah ; Now send it out
mov dx,modem.mddat
out dx,al
pop dx
jmp rskp
outch5: pop dx
ret
OUTCHR ENDP
; Send a break out the current serial port. Returns normally.
SENDBR PROC NEAR
mov dx,modem.mdcom ; send to command port
mov al,cbrk+ccmd ; add break to normal command
out dx,al
sub cx,cx ; wait a while
sndbr1: loop sndbr1
mov al,ccmd ; restore normal command
out dx,al
ret ; and return.
SENDBR ENDP
; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer. This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Returns normally.
CLRBUF PROC NEAR
pushf ; save current interrupt value
cli ; disable interrupts
mov ax,offset source ; reset pointers to beginning of buffer
mov srcpnt,ax
mov savesi,ax
mov count,0
popf ; restore original interrupt value
ret
CLRBUF ENDP
; Set the baud rate for the current port, based on the value in the
; portinfo structure. On entry, previous value of baud rate is saved in AX.
; Returns normally.
DOBAUD PROC NEAR
mov bp,portval
mov bx,ds:[bp].baud ;make sure new value is valid
shl bx,1
add bx,offset bddat
cmp word ptr [bx],0FFH
jne dobd0
mov ds:[bp].baud,ax ;replace bad rate with previous value
mov dx,offset badbd
jmp tmsg
dobd0: mov dx,timer.tmcmd ;timer command port
mov al,timer.tmsel ;select proper channel and mode
out dx,al
mov ax,[bx] ;get timer initializer for this rate
mov dx,timer.tmdat ;timer data port
out dx,al ;output low byte
mov al,ah
out dx,al ;output high byte
ret
DOBAUD ENDP
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port. Returns normally.
; This is used during initialization.
GETBAUD PROC NEAR
mov bx,portval ; no way to determine baud rate on APC
mov [bx].baud,B1200 ; so set default baud rate to 1200
ret
GETBAUD ENDP
; Set the mode for the current port. This is part of the serial
; initialization routine.
DOMODE PROC NEAR
mov dx,modem.mdcom ;send 3 zeros to command port to reset chip
mov al,0
out dx,al
mov al,0
out dx,al
mov al,0
out dx,al
mov al,cmode ;enable mode setting
out dx,al
push ax ;allow 8251 time to reset
pop ax
push ax
pop ax
mov al,mmode ;mode: 16x rate, 8 data, no parity, 1 stop
out dx,al
mov al,ccmd ;RTS & DTR high, RX & TX enabled, reset errors
out dx,al
ret
DOMODE ENDP
; set the current port.
COMS PROC NEAR
mov dx,offset comptab ;get port selection
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm ;get a confirmation
call comnd
jmp comx
nop
pop bx
mov flags.comflg,bl ;save port selection
cmp flags.comflg,1
jne coms2
mov ax,offset port1 ;set to run on port 1
mov portval,ax
call resetb ;reset port 2, if in use
call inita ;set up port 1
ret
coms2: mov ax,offset port2 ;set to run on port 2
mov portval,ax
call reseta ;reset port 1, if in use
call initb ;set up port 2
ret
comx: pop bx
ret
COMS ENDP
; initialization for using serial port. This routine performs
; any initialization necessary for using the serial port, including
; setting up interrupt routines, setting buffer pointers, etc.
; Doing this twice in a row should be harmless (this version checks
; a flag and returns if initialization has already been done).
; SERRST below should restore any interrupt vectors that this changes.
; Returns normally.
SERINI PROC NEAR
cmp flags.comflg,1
jne seri2
call resetb
call inita
ret
seri2: call reseta
call initb
ret
SERINI ENDP
; Reset the serial port. This is the opposite of serini. Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.
SERRST PROC NEAR
call reseta ;reset port 1
call resetb ;reset port 2
ret
SERRST ENDP
; Local routine to initialize the standard serial port
INITA PROC NEAR
cmp portina,1 ; Did we initialize port already? [21c]
je inita0 ; Yes, so just leave. [21c]
push es
cli ; Disable interrupts
mov ax,offset port1
mov portval,ax
xor ax,ax ; Address low memory
mov es,ax
mov ax,es:[4*icsvcta] ; save standard port interrupt vector
mov oldsera,ax
mov ax,es:[4*icsvcta+2]
mov oldsega,ax
mov ax,offset serint ; point to our routine
mov es:[4*icsvcta],ax ; point at our serial routine
mov es:[4*icsvcta+2],cs ; our segment
mov dx,intmska ; set up standard port...
in al,dx
mov oldmska,al ; save old master controller mask
; NEC recommends that the timer interrupt be disabled during interrupt-
; driven serial I/O, but this disables the clock display and keyboard
; repeat. I have not had any problems leaving it enabled, so I will
; leave it alone here. If problems develop, uncomment the following
; line to disable timer interrupts. -- RonB
; or al,ictmsk ; disable timer interrupt
and al,not icsmska ; enable serial interrupt at master controller
out dx,al
mov dx,mnmska ; enable serial interrupt at port
mov al,txmsk+tbemsk ; disable tx and tbe interrupts (enable rx)
out dx,al
mov dx,mntdca ; enable operation of serial port
mov al,0
out dx,al
mov modem.mddat,mndata
mov modem.mdstat,mnst1a
mov modem.mdcom,mncmda
mov timer.tmdat,tmdata
mov timer.tmcmd,tmcmda
mov timer.tmsel,tmsela
call domode
call dobaud
mov portina,1 ; Remember port has been initialized.
call clrbuf ; Clear input buffer.
sti ; Allow interrupts
pop es
inita0: ret
INITA ENDP
; Local routine to initialize the optional (H14) serial port
INITB PROC NEAR
cmp portinb,1 ; Did we initialize port already? [21c]
je initb0 ; Yes, so just leave. [21c]
push es
cli ; Disable interrupts
mov ax,offset port2
mov portval,ax
xor ax,ax ; Address low memory
mov es,ax
mov ax,es:[4*icsvctb] ; save optional port interrupt vector
mov oldserb,ax
mov ax,es:[4*icsvctb+2]
mov oldsegb,ax
mov ax,offset serint ; point to our routine
mov es:[4*icsvctb],ax ; point at our serial routine
mov es:[4*icsvctb+2],cs ; our segment
mov dx,intmskb ; set up optional port...
in al,dx
mov oldmskb,al ; save old master or slave controller mask
and al,not icsmskb ; enable serial interrupt at controller
out dx,al
mov dx,mnmskb ; enable serial interrupt at port
mov al,txmsk+tbemsk ; disable tx and tbe interrupts (enable rx)
out dx,al
mov dx,mntdcb ; enable operation of serial port
mov al,0
out dx,al
mov modem.mdstat,mnst1b
mov modem.mddat,mndatb
mov modem.mdcom,mncmdb
mov timer.tmdat,tmdatb
mov timer.tmcmd,tmcmdb
mov timer.tmsel,tmselb
call domode
call dobaud
mov portinb,1 ; Remember port has been initialized.
call clrbuf ; Clear input buffer.
sti ; Allow interrupts
pop es
initb0: ret
INITB ENDP
; Reset standard serial port
RESETA PROC NEAR
cmp portina,0 ; Did we reset port already?
je rsta0 ; Yes, so just leave.
push es
cli ; Disable interrupts
xor ax,ax ; Address low memory
mov es,ax
mov ax,oldsera ; Restore interrupt vector
mov es:[4*icsvcta],ax
mov ax,oldsega
mov es:[4*icsvcta+2],ax
mov dx,intmska ; restore old master controller mask
mov al,oldmska
out dx,al
mov dx,mnmska ; disable serial interrupts at port
mov al,txmsk+rxmsk+tbemsk
out dx,al
mov portina,0 ; Remember port has been reset
sti ; Allow interrupts
pop es
rsta0: ret
RESETA ENDP
; Reset optional (H14) serial port
RESETB PROC NEAR
cmp portinb,0 ; Did we reset port already?
je rstb0 ; Yes, so just leave.
push es
cli ; Disable interrupts
xor ax,ax ; Address low memory
mov es,ax
mov ax,oldserb ; Restore interrupt vector
mov es:[4*icsvctb],ax
mov ax,oldsegb
mov es:[4*icsvctb+2],ax
mov dx,intmskb ; restore old slave controller mask
mov al,oldmskb
out dx,al
mov dx,mnmskb ; disable serial interrupts at port
mov al,txmsk+rxmsk+tbemsk
out dx,al
mov portinb,0 ; Remember port has been reset
sti ; Allow interrupts
pop es
rstb0: ret
RESETB ENDP
; serial port interrupt routine. This is not accessible outside this
; module, handles serial port receiver interrupts.
SERINT PROC NEAR
push ds ; save these on remote stack
push ax
mov ax,seg datas ; get our own data segment
mov ds,ax
mov mnsp,sp ; save remote stack information
mov mnsseg,ss
mov sp,offset mnstk ; switch to local stack
mov ss,ax
push es ; and save remaining registers
push bp
push di
push si
push dx
push cx
push bx
mov es,ax
call mnproc ; process the interrupt
mov al,icEOI
cmp flags.comflg,1 ; If using standard port
je intr1
mov dx,intcmdb ; or H14 vectored to master
cmp dx,intcmda
je intr1 ; only signal End of Interrupt to master,
out dx,al ; otherwise signal to both slave and master.
intr1: mov dx,intcmda
out dx,al
pop bx ; restore registers from stack
pop cx
pop dx
pop si
pop di
pop bp
pop es
mov ax,mnsseg ; switch back to remote stack
mov ss,ax
mov ax,mnsp
mov sp,ax
pop ax
pop ds
iret
; handler for serial input
mnproc: cld
mov di,srcpnt ; get buffer pointer
mov dx,modem.mdstat ; is data available?
in al,dx
test al,rxrdy
jz mnpro7
mov dx,modem.mddat ; read data
in al,dx
or al,al
jz mnpro7 ; Ignore nulls.
cmp al,7FH ; Ignore rubouts, too.
jz mnpro7
mov ah,al
and ah,7fH ; only consider low-order 7 bits for flow ctl.
mov bp,portval
cmp ds:[bp].floflg,0 ; Doing flow control?
je mnpro4 ; Nope.
mov bx,ds:[bp].flowc ; Flow control char (BH = XON, BL = XOFF).
cmp ah,bl ; Is it an XOFF?
jne mnpro3 ; Nope, go on.
mov xofrcv,true ; Set the flag.
jmp short mnpro7
mnpro3: cmp ah,bh ; Get an XON?
jne mnpro4 ; No, go on.
mov xofrcv,false ; Clear our flag.
jmp mnpro7
mnpro4: stosb
cmp di,offset source + bufsiz
jb mnpro5 ; not past end...
mov di,offset source ; wrap buffer around
mnpro5: mov srcpnt,di ; update ptr
inc count
cmp ds:[bp].floflg,0 ; Doing flow control?
je mnpro7 ; No, just leave.
cmp xofsnt,true ; Have we sent an XOFF?
je mnpro7 ; Yes.
cmp count,mntrgh ; Past the high trigger point?
jbe mnpro7 ; No, we're within our limit.
mov ah,bl ; Get the XOFF.
call outchr ; Send it.
nop ; ignore failure.
nop
nop
mov xofsnt,true ; Remember we sent it.
mnpro7: ret
SERINT ENDP
; Dumb terminal emulator. Anyone wishing to enhance it is encouraged
; to do so.
TERM PROC NEAR
mov si,ax ; save argument block locally
mov di,offset ourarg
mov ax,ds
mov es,ax
mov cx,size termarg
rep movsb
term1: call prtchr ; Serial port input processor
jmp short term2 ; ...have a char
nop
jmp termk ; no char, continue
term2: and al,7FH ; only use ASCII in terminal mode
push ax
mov dl,al
mov ah,conout
int dos ; display char
pop ax
test ourarg.flgs,capt ; are we capturing output?
jz term3
push ax
call ourarg.captr
pop ax
term3: test ourflgs,fprint ; are we echoing to printer?
jz termk
call lstchr
termk: mov ah,dconio ; Keyboard input processor
mov dl,0FFH
int dos ; check console
jz term1 ; no char, continue
cmp al,ourarg.escc ; is it the escape char?
je termx
cmp al,ctrlP ; is it the print toggle?
jne term6
xor ourflgs,fprint
jmp term1
term6: call trnout ; translate key and send it out
jmp term1
termx: ret
; do appropriate translations on input key, and transmit
trnout: mov ah,0
test ourarg.flgs,havtt ; is there a translation table?
jz trnou2
mov cx,ourarg.klen ; get table length and origin
mov di,ourarg.ktab
repne scasw ; look for key
jne trnou2 ; if not found, just send it
sub di,ourarg.ktab ; reset to offset of replacement
sub di,2
add di,ourarg.krpl
mov si,[di]
mov cl,[si] ; get length of replacement
mov ch,0
jcxz trnou3 ; if length is zero, send nothing
inc si
trnou1: lodsb ; get replacement character
push si
push cx
call sndhst ; send it to port
pop cx
pop si
loop trnou1 ; continue until translation complete
ret
trnou2: call sndhst ; plain characters go out as they are
trnou3: ret
; send character in AL to port, with possible local echo
sndhst: push ax
mov ah,al
call outchr ; send char to port
nop ; ...don't care if it fails
nop
nop
pop ax
test ourarg.flgs,lclecho ; doing local echo?
jz sndhs2
mov dl,al
mov ah,conout
int dos ; if so, display char
sndhs2: ret
; send character to printer. The only special case is the tab, which must
; be expanded to spaces because MS-DOS doesn't.
lstchr: cmp al,tab
jne lstch2
mov ax,lstpos ; current column position
mov cx,8 ; # of spaces = 8 - (column % 8)
div cl
sub cl,ah
add lstpos,cx ; update the column position
mov al,' '
lstch1: call lstch4 ; print all the spaces
loop lstch1
ret
lstch2: cmp al,cr ; CR returns column count to zero
jne lstch3
mov lstpos,0
lstch3: cmp al,' ' ; only printable characters are counted
jb lstch4
cmp al,del
je lstch4
inc lstpos
lstch4: mov dl,al ; print the character in any case
mov ah,lstout
int dos
ret
TERM ENDP
; Set heath emulation on/off.
VTS PROC NEAR
mov dx,offset nyimsg
jmp tmsg
VTS ENDP
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR PROC NEAR
push si
cmp dh,25 ; out of range just assumes high value
jb poscu1
mov dh,24
poscu1: cmp dl,80
jb poscu2
mov dl,79
poscu2: add dx,2020H ; add offset for ADM cursor addressing
mov cpseq+2,dh
mov cpseq+3,dl
mov si,offset cpseq ; print sequence (ESC=rc)
mov cx,4
posc1: lodsb
mov dl,al
mov ah,conout
int dos
loop posc1
pop si
ret
POSCUR ENDP
; Locate; homes the cursor. Returns normally.
LOCATE PROC NEAR
mov dx,0 ; Go to top left corner of screen.
jmp poscur
LOCATE ENDP
; Delete a character from the terminal. This works by printing
; backspaces and spaces. Returns normally.
DODEL PROC NEAR
cmp al,del ; Del character needs extra backspace
jne dodel1
mov dl,bs
mov ah,conout
int dos
dodel1: mov dx,offset delstr ; Erase weird character.
jmp tmsg
DODEL ENDP
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
CTLU PROC NEAR
mov dx,offset clrlin ; this just goes to left margin...
call tmsg
jmp clearl ; now clear line
CTLU ENDP
; Clear to the end of the current line. Returns normally.
CLEARL PROC NEAR
mov dx,offset ceolseq ; clear sequence
jmp tmsg
CLEARL ENDP
; This routine blanks the screen. Returns normally.
CMBLNK PROC NEAR
mov dx,offset clrseq ; clear screen sequence
jmp tmsg
CMBLNK ENDP
; write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $. Returns normally.
PUTMOD PROC NEAR
push dx ; preserve message
mov dx,24*100H ; line 24
call poscur
mov dx,offset invseq ; put into inverse video
call tmsg
pop dx ; print the message
call tmsg
mov dx,offset nrmseq ; normal video
jmp tmsg
PUTMOD ENDP
; clear the mode line written by putmod. Returns normally.
CLRMOD PROC NEAR
mov dx,24*100H
call poscur
jmp clearl
CLRMOD ENDP
; Put a help message on the screen. This one uses bold video...
; pass the message in ax, terminated by a null. Returns normally.
PUTHLP PROC NEAR
push ax ; save pointer to message
mov dx,offset crlf
call tmsg
mov dx,offset bldseq ; set to bold video
call tmsg
pop si ; retrieve pointer to message
puth1: lodsb ; get a character
cmp al,0
je puth2 ; stop if terminator
mov dl,al ; otherwise display the character
mov ah,conout
int dos
jmp puth1
puth2: mov dx,offset nrmseq ; reset to normal video
call tmsg
mov dx,offset crlf
call tmsg
ret
PUTHLP ENDP
; Produce a short beep. Returns normally.
BEEP PROC NEAR
mov dl,bell
mov ah,conout
int dos
ret
BEEP ENDP
; Prints $-terminated message in dx, for local use only
TMSG PROC NEAR
mov ah,prstr
int dos
ret
TMSG ENDP
; 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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxapc.asm
/bin/echo -n ' '; /bin/ls -ld msxapc.asm
fi
/bin/echo 'Extracting msxdmb.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxdmb.asm
code segment public
code ends
datas segment public 'datas'
datas ends
stack segment stack 'stack'
stack ends
end
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxdmb.asm
/bin/echo -n ' '; /bin/ls -ld msxdmb.asm
fi
/bin/echo 'Extracting msxdmb.hlp'
sed 's/^X//' <<'//go.sysin dd *' >msxdmb.hlp
MSXDMB.ASM is a dummy file to make the segments come out in the right order
on the Rainbow version of Kermit-MS. It must be included with the other
modules, as the first one.
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxdmb.hlp
/bin/echo -n ' '; /bin/ls -ld msxdmb.hlp
fi
/bin/echo 'Extracting msxgen.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxgen.asm
; Generic MS DOS Kermit module
public serini, serrst, clrbuf, outchr, coms, vts, dodel,
public ctlu, cmblnk, locate, lclini, prtchr, dobaud, clearl,
public dodisk, getbaud, beep
public count, xofsnt, puthlp, putmod, clrmod, poscur
public sendbr, term, machnam, setktab, setkhlp, showkey
include msdefs.h
false equ 0
true equ 1
instat equ 6
rddev equ 3fH
open equ 3dH
; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
; or port2)
; port1, port2 - portinfo structures for the corresponding ports
; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
datas segment public 'datas'
extrn drives:byte,flags:byte, trans:byte
extrn portval:word, port1:byte, port2:byte
machnam db 'Generic MS-DOS 2.0$'
erms20 db cr,lf,'?Warning: System has no disk drives$' ; [21a]
erms40 db cr,lf,'?Warning: Unrecognized baud rate$'
erms41 db cr,lf,'?Warning: Cannot open com port$'
erms50 db cr,lf,'Error reading from device$'
hnd1 db cr,lf,'Enter a file handle. Check your DOS manual if you are '
db cr,lf,'not certain what value to supply (generally 3).$'
hnd2 db cr,lf,'Handle: $'
hnderr db cr,lf,'Warning: Handle not known. Any routine using the '
db cr,lf,'communications port will probably not work.$'
hndhlp db cr,lf,'A four digit file handle $'
badbd db cr,lf,'Unimplemented baud rate$'
noimp db cr,lf,'Command not implemented.$'
shkmsg db 'Not implemented.'
shklen equ $-shkmsg
setktab db 0
setkhlp db 0
crlf db cr,lf,'$'
delstr db BS,BS,' ',BS,BS,'$' ; Delete string. [21d]
clrlin db cr,'$' ; Clear line (just the cr part).
clreol db '^U',cr,lf,'$' ; Clear line.
telflg db 0 ; non-zero if we're a terminal.
xofsnt db 0 ; Say if we sent an XOFF.
xofrcv db 0 ; Say if we received an XOFF.
count dw 0 ; Number of chars in int buffer.
prthnd dw 0 ; Port handle.
prttab dw com2,com1
com1 db 'COM1',0
com2 db 'COM2',0
tmp db ?,'$'
temp dw 0
temp1 dw ? ; Temporary storage.
temp2 dw ? ; Temporary storage.
rdbuf db 20 dup(?) ; Buffer for input.
; Entries for choosing communications port. [19b]
comptab db 04H
db 01H,'1$'
dw 01H
db 01H,'2$'
dw 00H
db 04H,'COM1$'
dw 01H
db 04H,'COM2$'
dw 00H
ourarg termarg <>
datas ends
code segment public
extrn comnd:near, dopar:near, prserr:near, atoi:near, prompt:near
assume cs:code,ds:datas
; this is called by Kermit initialization. It checks the
; number of disks on the system, sets the drives variable
; appropriately. Returns normally.
DODISK PROC NEAR
mov ah,gcurdsk ; Current disk value to AL.
int dos
mov dl,al ; Put current disk in DL.
mov ah,seldsk ; Select current disk.
int dos ; Get number of drives in AL.
mov drives,al
ret
DODISK ENDP
; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer. This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Do nothing since we are not interrupt driven. Returns normally.
CLRBUF PROC NEAR
ret
CLRBUF ENDP
; Clear to the end of the current line. Returns normally.
CLEARL PROC NEAR
mov ah,prstr
mov dx,offset clreol
int dos
ret
CLEARL ENDP
; Put the char in AH to the serial port. This assumes the
; port has been initialized. Should honor xon/xoff. Skip returns on
; success, returns normally if the character cannot be written.
outchr: mov bp,portval
cmp ds:[bp].floflg,0 ; Are we doing flow control.
je outch2 ; No, just continue.
xor cx,cx ; clear counter
outch1: cmp xofrcv,true ; Are we being held?
jne outch2 ; No - it's OK to go on.
loop outch1 ; held, try for a while
mov xofrcv,false ; timed out, force it off and fall thru.
outch2: push dx ; Save register.
mov al,ah ; Parity routine works on AL.
call dopar ; Set parity appropriately.
mov dl,al
mov ah,punout ; Output char in DL to comm port.
int dos
pop dx
jmp rskp
; This routine blanks the screen. Returns normally.
CMBLNK PROC NEAR
mov ah,prstr
mov dx,offset crlf ; Can't do anything else.
int dos
ret
CMBLNK ENDP
; Homes the cursor. Returns normally.
LOCATE PROC NEAR
mov dx,0 ; Go to top left corner of screen.
jmp poscur
LOCATE ENDP
; Write a line at the bottom of the screen...
; the line is passed in dx, terminated by a $. Returns normally.
putmod proc near
push dx ; preserve message
mov dx,1800h ; now address line 24
call poscur
pop dx ; get message back
mov ah,prstr
int dos ; write it out
ret ; and return
putmod endp
; clear the mode line written by putmod. Returns normally.
clrmod proc near
mov dx,1800h
call poscur ; Go to bottom row.
call clearl ; Clear to end of line.
ret
clrmod endp
; Put a help message on the screen.
; Pass the message in ax, terminated by a null. Returns normally.
puthlp proc near
push ax ; preserve this
mov ah,prstr
mov dx,offset crlf
int dos
pop si ; point to string again
puthl3: lodsb ; get a byte
cmp al,0 ; end of string?
je puthl4 ; yes, stop
mov dl,al
mov ah,dconio
int dos ; else write to screen
jmp puthl3 ; and keep going
puthl4: mov ah,prstr
mov dx,offset crlf
int dos
ret
puthlp endp
; Set the baud rate for the current port, based on the value
; in the portinfo structure. Returns normally.
DOBAUD PROC NEAR
mov ah,prstr
mov dx,offset noimp ; Say it's not implemented.
int dos
mov bx,portval
mov [bx].baud,0FFFFH ; So it's not a recognized value.
ret ; Must be set before starting Kermit.
DOBAUD ENDP
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port. Returns normally.
; This is used during initialization.
GETBAUD PROC NEAR
ret ; Can't do this.
GETBAUD ENDP
; Use for DOS 2.0 and above. Check the port status. If no data, skip
; return. Else, read in a char and return.
PRTCHR PROC NEAR
push bx
push cx
push si
push bp
call chkxon
mov bx,prthnd
mov al,instat
mov ah,ioctl
int dos
or al,al
jz prtch4 ; not ready...
mov bx,prthnd
mov ah,rddev
mov cx,1
mov dx,offset temp
int dos
cmp al,5 ; Error condition.
je prt3x
cmp al,6 ; Error condition
je prt3x
mov al,byte ptr temp
mov bp,portval
cmp ds:[bp].parflg,PARNON ; no parity?
je prtch3 ; then don't strip
and al,7fh ; else turn off parity
prtch3: pop bp
pop si
pop cx
pop bx
ret
prt3x: mov ah,prstr
mov dx,offset erms50
int dos
prtch4: pop bp
pop si
pop cx
pop bx
jmp rskp ; no chars...
PRTCHR ENDP
; Local routine to see if we have to transmit an xon
chkxon proc near
push bx
mov bx,portval
cmp [bx].floflg,0 ; doing flow control?
je chkxo1 ; no, skip all this
cmp xofsnt,false ; have we sent an xoff?
je chkxo1 ; no, forget it
mov ax,[bx].flowc ; ah gets xon
call outchr ; send it
nop
nop
nop ; in case it skips
mov xofsnt,false ; remember we've sent the xon.
chkxo1: pop bx ; restore register
ret ; and return
chkxon endp
; Send a break out the current serial port. Returns normally.
SENDBR PROC NEAR
ret
SENDBR ENDP
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR PROC NEAR
ret
POSCUR ENDP
; Delete a character from the terminal. This works by printing
; backspaces and spaces. Returns normally.
DODEL PROC NEAR
mov ah,prstr
mov dx,offset delstr ; Erase weird character.
int dos
ret
DODEL ENDP
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
CTLU PROC NEAR
mov ah,prstr
mov dx,offset clrlin
int dos
call clearl
ret
CTLU ENDP
; Set the current port.
COMS PROC NEAR
mov dx,offset comptab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp comx ; Didn't get a confirm.
nop
pop bx
mov flags.comflg,bl ; Set the comm port flag.
cmp flags.comflg,1 ; Using Com 1?
jne coms0 ; Nope.
mov ax,offset port1
mov portval,ax
ret
coms0: mov ax,offset port2
mov portval,ax
ret
comx: pop bx
ret
COMS ENDP
; Set heath emulation on/off.
VTS PROC NEAR
jmp notimp
VTS ENDP
notimp: mov ah,prstr
mov dx,offset noimp
int dos
jmp prserr
; Initialize variables to values used by the generic MS DOS version.
lclini: mov flags.vtflg,0 ; Don't to terminal emulation.
call opnprt ; Get file handle for comm port.
ret
; Get a file handle for the communications port. Use DOS call to get the
; next available handle. If it fails, ask user what value to use (there
; should be a predefined handle for the port, generally 3). The open
; will fail if the system uses names other than "COM1" or "COM2".
opnprt: mov al,flags.comflg
mov ah,0
mov si,ax
shl si,1 ; double index
mov dx,prttab[si]
mov ah,open
mov al,2
int dos
jnc opnpr2
mov ah,prstr ; It didn't like the string.
mov dx,offset erms41
int dos
mov dx,offset hnd1
int dos
opnpr0: mov dx,offset hnd2 ; Ask user to supply the handle.
call prompt
mov ah,cmtxt
mov bx,offset rdbuf ; Where to put input.
mov dx,offset hndhlp ; In case user wants help.
call comnd
jmp opnpr3 ; Maybe user typed a ^C.
nop
mov si,offset rdbuf
call atoi ; Convert to real number
jmp opnpr0 ; Keep trying.
nop
mov prthnd,ax ; Value returned in AX
ret
opnpr2: mov prthnd,ax ; Call succeeded.
ret
opnpr3: cmp flags.cxzflg,'C' ; Did user type a ^C?
jne opnpr4 ; No, don't say anything.
mov ah,prstr ; Else, issue a warning.
mov dx,offset hnderr
int dos
opnpr4: ret ; Yes, fail.
showkey:
mov ax,offset shkmsg
mov cx,shklen
ret
; Initialization for using serial port. Returns normally.
SERINI PROC NEAR
cld ; Do increments in string operations
call clrbuf ; Clear input buffer.
ret ; We're done.
SERINI ENDP
; Reset the serial port. This is the opposite of serini. Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.
SERRST PROC NEAR
ret ; All done.
SERRST ENDP
; Produce a short beep. The PC DOS bell is long enough to cause a loss
; of data at the port. Returns normally.
BEEP PROC NEAR
mov dl,bell
mov ah,dconio
int dos
ret
BEEP ENDP
; Dumb terminal emulator. Doesn't work too well above 1200 baud (and
; even at 1200 baud you sometimes lose the first one or two characters
; on a line).
term proc near
mov si,ax ; this is source
mov di,offset ourarg ; place to store arguments
mov ax,ds
mov es,ax ; address destination segment
mov cx,size termarg
rep movsb ; copy into our arg blk
term1: call prtchr
jmp short term2 ; have a char...
nop
nop
jmp short term3 ; no char, go on
term2: push ax
and al,7fh ; mask off parity for terminal
mov dl,al
mov ah,conout
int dos ; go print it
pop ax
test ourarg.flgs,capt ; capturing output?
jz term3 ; no, forget it
call ourarg.captr ; else call the routine
term3: mov ah,dconio
mov dl,0ffh
int dos
jz term1 ; no character, go on
cmp al,ourarg.escc ; escape char?
je term4 ; yes, exit
push ax ; save char
mov ah,al
or ah,80H ; turn on hi bit so DOS doesn't interfere
call outchr ; output the character
nop
nop
nop
pop ax
test ourarg.flgs,lclecho ; echoing?
jz term1 ; no, continue loop
mov dl,al
mov ah,dconio
int dos
jmp term1 ; else echo and keep going
term4: ret
term endp
; 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//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxgen.asm
/bin/echo -n ' '; /bin/ls -ld msxgen.asm
fiknutson@ut-ngp.UUCP (Jim Knutson) (10/05/84)
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting msxhp150.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxhp150.asm
public serini, serrst, clrbuf, outchr, coms, vts, dodel, ctlu
public cmblnk, locate, prtchr, dobaud, clearl, lclini
public dodisk, getbaud, beep, setkhlp, setktab
public machnam, xofsnt, count, term, poscur
public clrmod, putmod, puthlp, sendbr, showkey
include msdefs.h
false equ 0
true equ 1
wrdev equ 40H
rddev equ 3fH
open equ 3dH
close equ 3eH
rdchan equ 2
e_send_break equ 6
e_ioctl equ 44h ; MSODS io control fct
datas segment public 'datas'
extrn drives:byte, flags:byte, trans:byte
extrn portval:word, port1:byte, port2:byte
machnam db 'HP-150$'
erms20 db cr,lf,'?Warning: System has no disk drives$' ; [21a]
erms40 db cr,lf,'?Warning: Unrecognized baud rate$'
erms41 db cr,lf,'?Warning: Cannot open com port$'
noimp db cr,lf,'Command not implemented.$'
setktab db 0
setkhlp db 0
shkmsg db 'Not implemented.'
shklen equ $-shkmsg
crlf db cr,lf,'$'
comphlp db cr,lf,'1 (COM1) 2 (COM2)$' ; [19b]
delstr db BS,BS,' ',BS,BS,'$' ; Delete string. [21d]
clrlin db cr,esc,'K$'
xofsnt db 0 ; Say if we sent an XOFF.
xofrcv db 0 ; Say if we received an XOFF.
invseq db esc,'&dB$' ; Reverse video.
nrmseq db esc,'&d@$' ; Normal mode.
ivlseq db 80 dup (' '),cr,'$' ; Make a line inverse video
tmp db ?,'$'
temp dw 0
temp1 dw ? ; Temporary storage.
temp2 dw ? ; Temporary storage.
; Entries for choosing communications port. [19b]
comptab db 04H
db 01H,'1$'
dw 01H
db 01H,'2$'
dw 00H
db 04H,'COM1$'
dw 01H
db 04H,'COM2$'
dw 00H
; variables for serial interrupt handler
source db bufsiz DUP(?) ; Buffer for data from port.
bufout dw 0 ; buffer removal ptr
count dw 0 ; Number of chars in int buffer.
bufin dw 0 ; buffer insertion ptr
telflg db 0 ; Are we acting as a terminal. [16] [17c]
clreol db esc,'K$'
prttab dw com2,com1
com1 db 'COM1',0
com2 db 'COM2',0
blank db esc,'H',esc,'J$'
movcur db esc,'&a'
colno db 20 dup (?)
ten db 10
prthnd dw 0
tempbuf dw 10 dup(?)
ourarg termarg <>
datas ends
code segment public
extrn comnd:near, dopar:near, prserr:near
assume cs:code,ds:datas
; See how many disk drives we have.
DODISK PROC NEAR
mov ah,gcurdsk ; Current disk value to AL.
int dos
mov dl,al ; Put current disk in DL.
mov ah,seldsk ; Select current disk.
int dos ; Get number of drives in AL.
mov drives,al
ret
DODISK ENDP
; Clear the input buffer before sending a packet. [20e]
CLRBUF PROC NEAR
cli
mov ax,offset source
mov bufin,ax
mov bufout,ax
mov count,0
sti
clrb1: call prtchr ; get a character
jmp clrb1 ; until there aren't any more
nop
ret
CLRBUF ENDP
; Common routine to clear to end-of-line. [19a]
CLEARL PROC NEAR
mov dx,offset clreol
mov ah,prstr
int dos
ret
CLEARL ENDP
dobaud proc near
jmp notimp
dobaud endp
; Send the break signal out data comm.
sendbr: mov al,e_send_break
jmp dc_ioctl
; Set some data comm ioctl option. AL has function code.
dc_ioctl proc near
mov ah,8h
mov tempbuf,ax
mov dx,offset tempbuf
mov ah,e_ioctl
mov al,3
mov bx,prthnd
mov cx,2
int 21h
ret
dc_ioctl endp
outchr: mov bp,portval
cmp ds:[bp].floflg,0 ; Are we doing flow control.
je outch2 ; No, just continue.
xor cx,cx ; clear counter
outch1: cmp xofrcv,true ; Are we being held?
jne outch2 ; No - it's OK to go on.
loop outch1 ; held, try for a while
mov xofrcv,false ; timed out, force it off and fall thru.
outch2: push dx ; Save register.
push cx
push bx
cmp prthnd,0 ; do we have a port handle?
jne outch3 ; yes, go on
push ax
call opnprt ; open the port
pop ax
outch3: mov byte ptr temp,ah ; save character
mov bx,prthnd
mov ah,wrdev
mov cx,1
mov dx,offset temp
int dos
pop bx
pop cx
pop dx
jmp rskp
opnprt: mov al,flags.comflg
mov ah,0
mov si,ax
shl si,1 ; double index
mov dx,prttab[si]
mov ah,open
mov al,2
int dos
jnc opnpr1
mov ah,prstr
mov dx,offset erms41
int dos
ret
opnpr1: mov prthnd,ax
ret
; This routine blanks the screen.
CMBLNK PROC NEAR ; This is stolen from the IBM example.
mov ah,prstr
mov dx,offset blank
int dos
ret
CMBLNK ENDP
LOCATE PROC NEAR
mov dx,0 ; Go to top left corner of screen.
jmp poscur ; callret...
LOCATE ENDP
GETBAUD PROC NEAR
ret
GETBAUD ENDP
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR PROC NEAR
push bx
push cx
push si
push bp
cmp count,0 ; no characters?
jne prtch2 ; no, go fill buffer
cmp prthnd,0 ; have a handle yet?
jne prtch1 ; yes, keep going
call opnprt
prtch1: mov bx,prthnd
mov al,rdchan
mov ah,ioctl
mov dx,offset source ; buffer to read into
mov cx,bufsiz ; length of buffer
int dos
mov count,ax ; reset count
or ax,ax
jz prtch4 ; still no chars
mov bufout,offset source ; this is output ptr
prtch2: dec count
mov dx,count ; return count in dx
mov si,bufout
lodsb ; get character
mov bufout,si ; update ptr
mov bp,portval
cmp ds:[bp].parflg,PARNON ; no parity?
je prtch3 ; then don't strip
and al,7fh ; else turn off parity
prtch3: pop bp
pop si
pop cx
pop bx
ret
prtch4: pop bp
pop si
pop cx
pop bx
jmp rskp ; no chars...
PRTCHR ENDP
; Position the cursor according to contents of DX.
POSCUR PROC NEAR
mov ax,ds
mov es,ax ; address data segment!!!
cld
mov di,offset colno
mov al,dl ; column
call nout
mov al,'c'
stosb
mov al,dh ; row
call nout
mov al,'Y'
stosb
mov al,'$'
stosb
mov dx,offset movcur
mov ah,prstr
int dos ; print the sequence
ret
POSCUR ENDP
NOUT PROC NEAR
cbw ; extend to word
div byte ptr ten ; divide by 10
or al,al ; any quotient?
jz nout1 ; no, forget this
push ax ; save current result
call nout ; output high order
pop ax ; restore
nout1: mov al,ah ; get digit
add al,'0' ; make printable
stosb
ret ; put in buffer and return
NOUT endp
; Write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $. Returns normally.
putmod proc near
push dx ; preserve message
mov dx,24 * 100H ; line 24
call poscur
mov dx,offset invseq ; put into inverse video
mov ah,prstr
int dos
pop dx
int dos
mov dx,offset nrmseq ; normal videw
int dos
ret ; and return
putmod endp
; Clear the mode line written by putmod. Returns normally.
clrmod proc near
mov dx,24 * 100H
call poscur
call clearl
ret
clrmod endp
; Put a help message one the screen in reverse video. Pass
; the message in AX, terminated by a null. Returns normally.
; The message is put wherever the cursor currently is located.
puthlp proc near
push ax
mov ah,prstr ; Leave some room before the message.
mov dx,offset crlf
int dos
pop si ; Put message address here.
puth0: mov ah,prstr
mov dx,offset invseq ; Put into reverse video.
int dos
mov ah,prstr
mov dx,offset ivlseq ; Make line inverse video
int dos
puth1: lodsb
cmp al,0 ; Terminated with a null.
je puth2
mov dl,al
mov ah,conout
int dos
cmp al,lf ; Line feed?
je puth0 ; Yes, clear the next line.
jmp puth1 ; Else, just keep on writing.
puth2: mov dx,offset crlf
mov ah,prstr
int dos
mov dx,offset nrmseq ; Normal video.
int dos
ret
puthlp endp
; Perform a delete.
DODEL PROC NEAR
mov ah,prstr
mov dx,offset delstr ; Erase weird character.
int dos
ret
DODEL ENDP
; Perform a Control-U.
CTLU PROC NEAR
mov ah,prstr
mov dx,offset clrlin
int dos
ret
CTLU ENDP
COMS PROC NEAR
mov dx,offset comptab
mov bx,offset comphlp
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp comx ; Didn't get a confirm.
nop
pop bx
mov flags.comflg,bl ; Set the comm port flag.
cmp flags.comflg,1 ; Using Com 1?
jne coms0 ; Nope.
mov ax,offset port1
mov portval,ax
ret
coms0: mov ax,offset port2
mov portval,ax
ret
comx: pop bx
ret
COMS ENDP
VTS PROC NEAR
jmp notimp
VTS ENDP
notimp: mov ah,prstr
mov dx,offset noimp
int dos
jmp prserr
lclini: ret
showkey:
mov ax,offset shkmsg
mov cx,shklen
ret
; Common initialization for using serial port.
SERINI PROC NEAR
call opnprt
call clrbuf ; Clear input buffer. [20e]
ret ; We're done. [21c]
SERINI ENDP
SERRST PROC NEAR
mov bx,prthnd
cmp bx,0 ; none there?
je serrs1 ; no, don't try to close.
mov ah,close
int dos ; close handle
mov prthnd,0
serrs1: ret ; All done. [21c]
SERRST ENDP
; Generate a short beep.
BEEP PROC NEAR
mov dl,bell
mov ah,conout
int dos
ret
BEEP ENDP
; 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
term proc near
mov si,ax ; this is source
mov di,offset ourarg ; place to store arguments
mov ax,ds
mov es,ax ; address destination segment
mov cx,size termarg
rep movsb ; copy into our arg blk
term1: call prtchr
jmp short term2 ; have a char...
nop
nop
jmp short term3 ; no char, go on
term2: push ax
mov dl,al
and dl,7fh ; mask off parity for terminal
mov ah,dconio
int dos ; write out the character
pop ax
test ourarg.flgs,capt ; capturing output?
jz term3 ; no, forget it
call ourarg.captr ; else call the routine
term3: mov ah,dconio
mov dl,0ffh
int dos
jz term1 ; no character, go on
cmp al,ourarg.escc ; escape char?
je term4 ; yes, exit
push ax ; save char
mov ah,al
or ah,80H ; turn on hi bit so DOS doesn't interfere
call outchr ; output the character
nop
nop
nop
pop ax
test ourarg.flgs,lclecho ; echoing?
jz term1 ; no, continue loop
mov dl,al
mov ah,dconio
int dos
jmp term1 ; else echo and keep going
term4: ret
term endp
code ends
end
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxhp150.asm
/bin/echo -n ' '; /bin/ls -ld msxhp150.asm
fi
/bin/echo 'Extracting msxibm.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxibm.asm
; Kermit system dependent module for IBM-PC
public serini, serrst, clrbuf, outchr, coms, vts, dodel,
public ctlu, cmblnk, locate, prtchr, dobaud, clearl,
public dodisk, getbaud, beep,
public count, xofsnt, puthlp, putmod, clrmod, poscur
public sendbr, machnam, setktab, setkhlp, lclini, showkey
include msdefs.h
false equ 0
true equ 1
mntrgh equ bufsiz*3/4 ; High point = 3/4 of buffer full.
; constants used by serial port handler
BRKBIT EQU 040H ; Send-break bit.
TIMER EQU 40H ; Use to issue short beep.
PORT_B EQU 61H ; Port B address.
MCONF EQU 11H ; Machine configuration.
KEYB EQU 16H
BIOS EQU 10H
MDMDAT1 EQU 03F8H ; Address of modem port (data). [19b]
MDMSTS1 EQU 03FDH ; Address of modem port status. [19b]
MDMCOM1 EQU 03FBH ; Address of modem port command. [19b]
MDMDAT2 EQU 02F8H ; Port 2 address. [19b]
MDMSTS2 EQU 02FDH ; Port 2 status. [19b]
MDMCOM2 EQU 02FBH ; Port 2 command. [19b]
MDMINP EQU 1 ; Input ready bit.
MDMINTV EQU 0030H ; Address of modem port interrupt vector.
MDINTV2 EQU 002CH ; Address for port 2. [19b]
MDMINTO EQU 0EFH ; Mask to enable interrupt for modem port.
MDINTO2 EQU 0F7H ; Enable interrupt level 3. [19b]
MDMINTC EQU 010H ; Bit to set to disable interrupts for modem.
MDINTC2 EQU 008H ; Disable IRQ3. [19b]
INTCONT EQU 0021H ; Address of 8259 interrupt controller ICW2-3.
INTCON1 EQU 0020H ; Address of 8259 ICW1.
EOICOM EQU 0064H ; End of interrupt.
EOICOM2 EQU 0063H ; End of interrupt for COM2. [19b]
; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
; or port2)
; port1, port2 - portinfo structures for the corresponding ports
; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
; setktab - keyword table for redefining keys (should contain a 0 if
; not implemented)
; setkhlp - help for setktab.
datas segment public 'datas'
extrn drives:byte,flags:byte, trans:byte
extrn portval:word, port1:byte, port2:byte
setktab db 12
mkeyw 'BACKSPACE',0eh
mkeyw 'F1',3bh
mkeyw 'F2',3ch
mkeyw 'F3',3dh
mkeyw 'F4',3eh
mkeyw 'F5',3fh
mkeyw 'F6',40h
mkeyw 'F7',41h
mkeyw 'F8',42h
mkeyw 'F9',43h
mkeyw 'F10',44h
mkeyw 'SCAN',-1
setkhlp db cr,lf,'Keyname: backspace, f1, ... f10, or "SCAN" follwed by '
db 'decimal scan code$'
brkval db 0 ; What to send for a break.
brkadr dw 0 ; Where to send it.
modem mdminfo <MDMDAT1,MDMSTS1,MDMCOM1,MDMINTO,MDMINTC,EOICOM,MDMINTV>
erms20 db cr,lf,'?Warning: System has no disk drives$' ; [21a]
erms40 db cr,lf,'?Warning: Unrecognized baud rate$'
badbd db cr,lf,'Unimplemented baud rate$'
machnam db 'IBM-PC$'
crlf db cr,lf,'$'
delstr db BS,' ',BS,'$' ; Delete string. [21d]
clrlin db cr,'$' ; Clear line (just the cr part).
savsci dw ? ; Save for serial port interrupt vector. [14]
savscs dw ? ; Ditto. [14]
savbr1 dw ? ; "Break" interrupt vector. [25]
savbr2 dw ? ; Ditto. [25]
portin db 0 ; Has comm port been initialized. [21c]
xofsnt db 0 ; Say if we sent an XOFF.
xofrcv db 0 ; Say if we received an XOFF.
tmp db ?,'$'
temp dw 0
temp1 dw ? ; Temporary storage.
temp2 dw ? ; Temporary storage.
ontab db 02H ; Two entries.
db 03H,'OFF$' ; Should be alphabetized. [19a]
dw 00H
db 02H,'ON$'
dw 01H
comptab db 04H
db 01H,'1$'
dw 01H
db 01H,'2$'
dw 00H
db 04H,'COM1$'
dw 01H
db 04H,'COM2$'
dw 00H
; this table is indexed by the baud rate definitions given in
; pcdefs. Unsupported baud rates should contain FF.
bddat label word
dw 0FFH ; 45.5 baud -- Not supported.
dw 900H ; 50 baud
dw 600H ; 75 baud
dw 417H ; 110 baud
dw 359H ; 134.5 baud
dw 300H ; 150 baud
dw 180H ; 300 baud
dw 0C0H ; 600 baud
dw 60H ; 1200 baud
dw 40H ; 1800 baud
dw 3AH ; 2000 baud
dw 30H ; 2400 baud
dw 18H ; 4800 baud
dw 0CH ; 9600 baud
dw 0FFH ; 19200 baud -- Not supported.
dw 0FFH ; 38400 baud -- Not supported.
; variables for serial interrupt handler
source db bufsiz DUP(?) ; Buffer for data from port.
srcpnt dw 0 ; Pointer in buffer (DI).
count dw 0 ; Number of chars in int buffer.
savesi dw 0 ; Save SI register here.
telflg db 0 ; Are we acting as a terminal.
mst dw 0 ; Modem status address.
mdat dw 0 ; Modem data address.
mdeoi db 0 ; End-of-Interrupt value.
rbtrn db 7fH ; rubout
shkbuf db 300 dup (?) ; room for definition
shkmsg db ' Scan code: '
shkmln equ $-shkmsg
shkms1 db cr,lf,' Definition: '
shkm1ln equ $-shkms1
datas ends
code segment public
extrn comnd:near, dopar:near, defkey:near, gss:near
assume cs:code,ds:datas
; local initialization
lclini proc near
mov ax,0eH ; scan code for arrow key
mov si,offset rbtrn ; translate to rubout
mov cx,1 ; one char translation
call defkey
mov brkval,BRKBIT ; What to send for a break.
mov ax,modem.mdcom ; Where to send it.
mov brkadr,ax
ret
lclini endp
; this is called by Kermit initialization. It checks the
; number of disks on the system, sets the drives variable
; appropriately. Returns normally.
DODISK PROC NEAR
int mconf ; Get equipment configuration.
mov ah,al ; Store AL value for a bit.
and al,01H ; First, look at bit 0.
jz dodsk0 ; No disk drives -- forget it.
mov al,ah ; Get back original value.
mov cl,6 ; Shift over bits 6 and 7.
shr al,cl ; To positions 0 and 1.
inc al ; Want 1 thru 4 (not 0 thru 3).
mov drives,al ; Remember how many.
ret
dodsk0: mov ah,prstr ; Print a warning message.
mov dx,offset erms20 ; I'm not sure if things will
int dos ; work with only a cassette.
mov drives,0 ; Say there aren't any drives.
ret
DODISK ENDP
; show the definition of a key. The terminal argument block (which contains
; the address and length of the definition tables) is passed in ax.
; Returns a string to print in AX, length of same in CX.
; Returns normally.
showkey proc near
push es
push ax ; save the ptr
mov bx,ds
mov es,bx ; address data segment
cld
showk1: xor ah,ah
int keyb ; read a char
push ax ; save the character
call gss ; get shift state
pop bx
mov ah,al ; shift state to ah
mov al,bh ; scan code to al
push ax ; remember scan code
mov di,offset shkbuf
mov si,offset shkmsg
mov cx,shkmln
rep movsb ; copy in initial message
call nout ; write out scan code
mov si,offset shkms1
mov cx,shkm1ln ; second message
rep movsb
pop ax ; get scan code back
pop bx ; and terminal arg block
mov cx,[bx].klen ; and length
jcxz showk2 ; no table, not defined
push di ; remember output ptr
mov di,[bx].ktab ; get key table
repne scasw ; search for a definition for this
mov si,di ; remember result ptr
pop di ; get output ptr back
jne showk2 ; not defined, forget it
sub si,[bx].ktab ; compute offset from beginning
sub si,2 ; minus 2 for pre-increment
add si,[bx].krpl ; get index into replacement table
mov si,[si] ; pick up replacement
mov cl,[si] ; get length
mov ch,0
inc si
rep movsb ; copy into buffer
showk2: mov ax,offset shkbuf ; this is buffer
mov cx,di
sub cx,ax ; length
pop es
ret ; and return
showkey endp
; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer. This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Returns normally.
CLRBUF PROC NEAR
cli
mov ax,offset source
mov srcpnt,ax
mov savesi,ax
mov count,0
sti
ret
CLRBUF ENDP
; Clear to the end of the current line. Returns normally.
CLEARL PROC NEAR
mov ah,3 ; Clear to end of line.
mov bh,0
int bios ; Get current cursor position
mov cx,dx
mov dl,79
mov ah,7
mov al,0
mov bh,7
int bios
ret
CLEARL ENDP
; Put the char in AH to the serial port. This assumes the
; port has been initialized. Should honor xon/xoff. Skip returns on
; success, returns normally if the character cannot be written.
outchr: mov bp,portval
cmp ds:[bp].floflg,0 ; Are we doing flow control.
je outch2 ; No, just continue.
xor cx,cx ; clear counter
outch1: cmp xofrcv,true ; Are we being held?
jne outch2 ; No - it's OK to go on.
loop outch1 ; held, try for a while
mov xofrcv,false ; timed out, force it off and fall thru.
outch2: push dx ; Save register.
sub cx,cx
mov al,ah ; Parity routine works on AL.
call dopar ; Set parity appropriately.
mov ah,al ; Don't overwrite character with status.
mov dx,modem.mdstat ; Get port status.
outch3: in al,dx
test al,20H ; Transmitter ready?
jnz outch4 ; Yes
loop outch3
jmp outch5 ; Timeout
outch4: mov al,ah ; Now send it out
mov dx,modem.mddat
out dx,al
pop dx
jmp rskp
outch5: pop dx
ret
; This routine blanks the screen. Returns normally.
CMBLNK PROC NEAR ; This is stolen from the IBM example.
mov cx,0
mov dx,184FH
mov bh,7
mov ax,600H
int bios
ret
CMBLNK ENDP
; Locate: homes the cursor. Returns normally.
LOCATE PROC NEAR
mov dx,0 ; Go to top left corner of screen.
jmp poscur
LOCATE ENDP
; write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $. Returns normally.
putmod proc near
push dx ; preserve message
mov cx,1800h
mov dx,184fh
mov ax,600h ; scroll to clear the line
mov bh,70h ; inverse video
int bios
mov dx,1800h ; now address line 24
call poscur
pop dx ; get message back
mov ah,prstr
int dos ; write it out
ret ; and return
putmod endp
; clear the mode line written by putmod. Returns normally.
clrmod proc near
mov cx,1800h
mov dx,184fh
mov ax,600h
mov bh,7h
int bios
ret
clrmod endp
; put a help message on the screen. This one uses reverse video...
; pass the message in ax, terminated by a null. Returns normally.
puthlp proc near
push ax ; preserve this
mov si,ax ; point to it
mov dh,1 ; init counter
puthl1: lodsb ; get a byte
cmp al,lf ; linefeed?
jne puthl2 ; no, keep going
inc dh ; count it
jmp puthl1 ; and keep looping
puthl2: cmp al,0 ; end of string?
jne puthl1 ; no, keep going
mov ax,600h ; scroll to clear window
xor cx,cx ; from top left
mov dl,4fh ; to bottom right of needed piece
mov bh,70h ; inverse video
int bios
call locate ; home cursor
pop si ; point to string again
puthl3: lodsb ; get a byte
cmp al,0 ; end of string?
je puthl4 ; yes, stop
mov ah,14
int bios ; else write to screen
jmp puthl3 ; and keep going
puthl4: mov dx,24 * 100H ; go to last line
jmp poscur ; position and return
puthlp endp
; Set the baud rate for the current port, based on the value
; in the portinfo structure. Returns normally.
DOBAUD PROC NEAR
mov bp,portval
mov temp1,ax ; Don't overwrite previous rate. [25]
mov ax,ds:[bp].baud ; Check if new rate is valid. [25]
mov tmp,2
mul tmp ; Get index into baud table.
mov bx,offset bddat ; Start of table.
add bx,ax
mov ax,[bx] ; The data to output to port.
cmp ax,0FFH ; Unimplemented baud rate.
jne dobd0
mov ax,temp1 ; Get back orginal value.
mov ds:[bp].baud,ax ; Leave baud rate as is.
mov ah,prstr
mov dx,offset badbd ; Give an error message.
int dos
ret
dobd0: mov temp1,ax ; Remember value to output. [25]
mov dx,modem.mdcom ; LCR -- Initialize baud rate. [19b]
in al,dx
mov bl,al
or ax,80H
out dx,al
mov dx,modem.mddat ; [19b]
mov ax,temp1
out dx,al
inc dx
mov al,ah
out dx,al
mov dx,modem.mdcom ; [19b]
mov al,bl
out dx,al
ret
DOBAUD ENDP
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port. Returns normally.
; This is used during initialization.
GETBAUD PROC NEAR
mov dx,modem.mdcom ; Get current Line Control Register value.
in al,dx
mov bl,al ; Save it.
or ax,80H ; Turn on to access baud rate generator.
out dx,al
mov dx,modem.mddat ; Divisor latch.
inc dx
in al,dx ; Get hi order byte.
mov ah,al ; Save here.
dec dx
in al,dx ; Get lo order byte.
push ax
mov dx,modem.mdcom
mov al,bl ; Restore old value.
out dx,al
pop ax
cmp ax,0FFFFH ; Who knows what this is.
je getb2
mov bx,offset bddat ; Find rate's offset into table.
mov cl,0 ; Keep track of index.
getb0: cmp ax,[bx]
je getb1
inc cl
cmp cl,baudsiz ; At the end of the list.
jge getb2
add bx,2
jmp getb0
getb1: mov ch,0
mov bp,portval
mov ds:[bp].baud,cx ; Set baud rate.
ret
getb2: mov ah,prstr
mov dx,offset erms40
int dos
ret
GETBAUD ENDP
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR PROC NEAR
call chkxon ; see if we need to xon
cmp count,0
jnz prtch2
jmp rskp ; No data - check console.
prtch2: mov si,savesi
lodsb ; get a byte
cmp si,offset source + bufsiz ; bigger than buffer?
jb prtch1 ; no, keep going
mov si,offset source ; yes, wrap around
prtch1: dec count
mov savesi,si
mov dx,count ; return # of chars in buffer
ret
PRTCHR ENDP
; local routine to see if we have to transmit an xon
chkxon proc near
push bx
mov bx,portval
cmp [bx].floflg,0 ; doing flow control?
je chkxo1 ; no, skip all this
cmp xofsnt,false ; have we sent an xoff?
je chkxo1 ; no, forget it
cmp count,mntrgh ; below trigger?
jae chkxo1 ; no, forget it
mov ax,[bx].flowc ; ah gets xon
call outchr ; send it
nop
nop
nop ; in case it skips
mov xofsnt,false ; remember we've sent the xon.
chkxo1: pop bx ; restore register
ret ; and return
chkxon endp
; Send a break out the current serial port. Returns normally.
SENDBR PROC NEAR
push cx
push dx
push ax
xor cx,cx ; Clear loop counter.
mov dx,brkadr ; Port address. [19b]
in al,dx ; Get current setting.
or al,brkval ; Set send-break bit(s).
out dx,al ; Start the break.
pause: loop pause ; Wait a while.
xor al,brkval ; Clear send-break bit(s).
out dx,al ; Stop the break.
pop ax
pop dx
pop cx
ret ; And return.
SENDBR ENDP
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR PROC NEAR
mov ah,2 ; Position cursor.
mov bh,0
int bios
ret
POSCUR ENDP
; Delete a character from the terminal. This works by printing
; backspaces and spaces. Returns normally.
DODEL PROC NEAR
mov ah,prstr
mov dx,offset delstr ; Erase weird character.
int dos
ret
DODEL ENDP
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
CTLU PROC NEAR
mov ah,prstr
mov dx,offset clrlin
int dos
call clearl
ret
CTLU ENDP
; set the current port.
COMS PROC NEAR
mov dx,offset comptab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp comx ; Didn't get a confirm.
nop
pop bx
mov flags.comflg,bl ; Set the comm port flag.
cmp flags.comflg,1 ; Using Com 1?
jne coms0 ; Nope.
mov ax,offset port1
mov portval,ax
mov modem.mddat,MDMDAT1 ; Set COM1 defaults.
mov modem.mdstat,MDMSTS1
mov modem.mdcom,MDMCOM1
mov modem.mddis,MDMINTC
mov modem.mden,MDMINTO
mov modem.mdmeoi,EOICOM
mov modem.mdintv,MDMINTV
mov brkadr,MDMCOM1
ret
coms0: mov ax,offset port2
mov portval,ax
mov modem.mddat,MDMDAT2 ; Set COM2 defaults.
mov modem.mdstat,MDMSTS2
mov modem.mdcom,MDMCOM2
mov modem.mddis,MDINTC2
mov modem.mden,MDINTO2
mov modem.mdmeoi,EOICOM2
mov modem.mdintv,MDINTV2
mov brkadr,MDMCOM2
ret
comx: pop bx
ret
COMS ENDP
; Set heath emulation on/off.
VTS PROC NEAR
mov dx,offset ontab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp vt0 ; Didn't get a confirm.
nop
pop bx
mov flags.vtflg,bl ; Set the VT52 emulation flag.
ret
vt0: pop bx
ret
VTS ENDP
; initialization for using serial port. This routine performs
; any initialization necessary for using the serial port, including
; setting up interrupt routines, setting buffer pointers, etc.
; Doing this twice in a row should be harmless (this version checks
; a flag and returns if initialization has already been done).
; SERRST below should restore any interrupt vectors that this changes.
; Returns normally.
SERINI PROC NEAR
push es
cmp portin,0 ; Did we initialize port already? [21c]
jne serin0 ; Yes, so just leave. [21c]
cli ; Disable interrupts
cld ; Do increments in string operations
xor ax,ax ; Address low memory
mov es,ax
mov bx,modem.mdintv ; Save serial card interrupt vector. [19b]
mov ax,es:[bx]
mov savsci,ax
mov ax,offset serint ; And point it to my routine
mov es:[bx],ax
add bx,2 ; Save CS register too. [19b]
mov ax,es:[bx]
mov savscs,ax
mov es:[bx],cs
mov portin,1 ; Remember port has been initialize.
call clrbuf ; Clear input buffer.
mov ax,modem.mdstat
mov mst,ax ; Use this address for status.
mov ax,modem.mddat
mov mdat,ax ; Use this address for data.
mov al,modem.mdmeoi
mov mdeoi,al ; Use to signify end-of-interrupt.
in al,21H ; Set up 8259 interrupt controller
and al,modem.mden ; Enable INT3 or INT4.
out 21H,al
mov dx,modem.mdcom ; Set up the serial card.
mov al,3
out dx,al
mov dl,0F9H
mov al,1 ; Set up interrupt enable register
out dx,al
mov dl,0FCH ; Enable interrupts from serial card
mov al,0BH
out dx,al
sti ; Allow interrupts
mov dl,0F8H
in al,dx
serin0: pop es
ret ; We're done.
SERINI ENDP
; Reset the serial port. This is the opposite of serini. Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.
SERRST PROC NEAR
push es ; preserve this
cmp portin,0 ; Reset already?
je srst1 ; Yes, just leave.
cli ; Disable interrupts
mov dx,03FCH ; Disable modem interrupts
cmp flags.comflg,1 ; Using port 1 ?
je srst0 ; Yes - continue.
mov dh,02 ; Set for port 2.
srst0: mov al,3
out dx,al
in al,21H ; Interrupt controller
or al,modem.mddis ; Inhibit IRQ3 or IRQ4.
out 21H,al
xor bx,bx ; Address low memory
mov es,bx
mov bx,modem.mdintv ; Restore the serial card int vector
mov ax,savsci
mov es:[bx],ax
add bx,2 ; Restore CS too.
mov ax,savscs
mov es:[bx],ax
mov portin,0 ; Reset flag.
sti
srst1: pop es
ret ; All done.
SERRST ENDP
; serial port interrupt routine. This is not accessible outside this
; module, handles serial port receiver interrupts.
SERINT PROC NEAR
push bx
push dx
push ax
push es
push di
push ds
push bp
push cx
cld
mov ax,seg datas
mov ds,ax ; address data segment
mov es,ax
mov di,srcpnt ; Registers for storing data.
mov dx,mst ; Asynch status port. [19b]
in al,dx
test al,mdminp ; Data available?
jz retint ; Nope.
mov dx,mdat ; [19b]
in al,dx
cmp telflg,0 ; File transfer or terminal mode? [17c]
jz srint0
and al,7FH ; Terminal mode (7 bits only).
srint0: or al,al
jz retint ; Ignore nulls.
mov ah,al
and ah,7fH ; strip parity temporarily
cmp ah,7FH ; Ignore rubouts, too.
jz retint
mov bp,portval
cmp ds:[bp].floflg,0 ; Doing flow control?
je srint2 ; Nope.
mov bx,ds:[bp].flowc ; Flow control char (BH = XON, BL = XOFF).
cmp al,bl ; Is it an XOFF?
jne srint1 ; Nope, go on.
mov xofrcv,true ; Set the flag.
jmp retint
srint1: cmp al,bh ; Get an XON?
jne srint2 ; No, go on.
mov xofrcv,false ; Clear our flag.
jmp retint
srint2: stosb
cmp di,offset source + bufsiz
jb srint3 ; not past end...
mov di,offset source ; wrap buffer around
srint3: inc count
cmp ds:[bp].floflg,0 ; Doing flow control?
je retint ; No, just leave.
cmp xofsnt,true ; Have we sent an XOFF?
je retint ; Yes.
cmp count,mntrgh ; Past the high trigger point?
jbe retint ; No, we're within our limit.
mov ah,bl ; Get the XOFF.
call outchr ; Send it.
nop
nop
nop ; ignore failure.
mov xofsnt,true ; Remember we sent it.
retint: mov srcpnt,di
sti
mov al,mdeoi ; [19b]
out intcon1,al ; Send End-of-Interrupt to 8259.
pop cx
pop bp
pop ds
pop di
pop es
pop ax
pop dx
pop bx
intret: iret
SERINT ENDP
; Produce a short beep. The PC DOS bell is long enough to cause a loss
; of data at the port. Returns normally.
BEEP PROC NEAR
mov al,10110110B ; Gen a short beep (long one losses data.)
out timer+3,al ; Code snarfed from Technical Reference.
mov ax,533H
out timer+2,al
mov al,ah
out timer+2,al
in al,port_b
mov ah,al
or al,03
out port_b,al
sub cx,cx
mov bl,1
beep0: loop beep0
dec bl
jnz beep0
mov al,ah
out port_b,al
ret
BEEP ENDP
; put the number in ax into the buffer pointed to by di. Di is updated
nout proc near
mov dx,0 ; high order is always 0.
mov bx,10
div bx ; divide to get digit
push dx ; save remainder digit
or ax,ax ; test quotient
jz nout1 ; zero, no more of number
call nout ; else call for rest of number
nout1: pop ax ; get digit back
add al,'0' ; make printable
stosb ; drop it off
ret ; and return
nout endp
; 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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxibm.asm
/bin/echo -n ' '; /bin/ls -ld msxibm.asm
fi
/bin/echo 'Extracting msxrb.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxrb.asm
; Kermit system dependent module for Rainbow
; Jeff Damens, July 1984
public serini, serrst, clrbuf, outchr, coms, vts, dodel,
public ctlu, cmblnk, locate, lclini, prtchr, dobaud, clearl,
public dodisk, getbaud, beep,
public count, xofsnt, puthlp, putmod, clrmod, poscur
public sendbr, term, machnam, setktab, setkhlp, showkey
include msdefs.h
; rainbow-dependent screen constants
scrseg equ 0ee00H ; screen segment
latofs equ 0ef4h ; ptrs to line beginnings, used by firmware
l1ptr equ latofs ; ptr to first line
llptr equ latofs+23*2 ; ptr to last line
csrlin equ 0f42h ; current cursor line.
; level 1 console definitions
fnkey equ 100H ; function key flag
shfkey equ 200H ; shift key
ctlkey equ 400H ; control key
cplk equ 800H
prvkey equ 23H
nxtkey equ 25H
brkkey equ 65H
prtkey equ 3
false equ 0
true equ 1
mntrgh equ bufsiz*3/4 ; High point = 3/4 of buffer full.
mnstata equ 042H ;Status/command port A
mnstatb equ 043H ;Status/command port B.
mndata equ 040H ;Data port.
mndatb equ 041H
mnctrl equ 002H ;Control port.
serchn equ 0A4H ; interrupt to use
serch1 equ 044H ; use this too for older rainbows.
txrdy EQU 04H ;Bit for output ready.
rxrdy EQU 01H ;Bit for input ready.
fastcon equ 29H ; fast console handler
firmwr equ 18H
swidth equ 132 ; screen width
slen equ 24 ; screen length
npgs equ 5 ; # of pages to remember
stbrk equ 15 ; start sending a break
enbrk equ 16 ; stop sending break.
; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
; or port2)
; port1, port2 - portinfo structures for the corresponding ports
; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
; circular buffer ptr
cbuf struc
pp dw ? ; place ptr in buffer
bend dw ? ; end of buffer
orig dw ? ; buffer origin
lcnt dw 0 ; # of lines in buffer.
cbuf ends
; answerback structure
ans struc
anspt dw ? ; current pointer in answerback
ansct db ? ; count of chars in answerback
ansseq dw ? ; pointer to whole answerback
anslen db ? ; original length
ansrtn dw ? ; routine to call.
ans ends
datas segment public 'datas'
extrn drives:byte,flags:byte, trans:byte
extrn portval:word, port1:byte, port2:byte
setktab db 22
mkeyw 'F4',fnkey+5h
mkeyw 'F5',fnkey+65h
mkeyw 'F6',fnkey+7h
mkeyw 'F7',fnkey+9h
mkeyw 'F8',fnkey+0Bh
mkeyw 'F9',fnkey+0Dh
mkeyw 'F10',fnkey+0Fh
mkeyw 'F11',esc
mkeyw 'F12',bs
mkeyw 'F13',lf
mkeyw 'F14',fnkey+11h
mkeyw 'F17',fnkey+13h
mkeyw 'F18',fnkey+15h
mkeyw 'F19',fnkey+17h
mkeyw 'F20',fnkey+19h
mkeyw 'FIND',fnkey+1bh
mkeyw 'INSERTHERE',fnkey+1dh
mkeyw 'REMOVE',fnkey+1fh
mkeyw 'SCAN',-1
mkeyw 'SELECT',fnkey+21h
ourflgs db 0 ; our flags
fpscr equ 80H ; flag definitions...
crlf db cr,lf
setkhlp db ' F4 ... F20 or SCAN$'
machnam db 'Rainbow$'
nyimsg db cr,lf,'Not yet implemented$'
delstr db BS,' ',BS,'$' ; Delete string.
clrlin db cr,'$' ; Clear line (just the cr part).
oldser dw ? ; old serial handler
oldseg dw ? ; segment of above
old1ser dw ? ; old serial handler, alternate address
old1seg dw ? ; segment of same.
portin db 0 ; Has comm port been initialized.
xofsnt db 0 ; Say if we sent an XOFF.
xofrcv db 0 ; Say if we received an XOFF.
iobuf db 5 dup (?) ; buffer for ioctl
phbuf db swidth dup (?)
gopos db esc,'['
rowp db 20 dup (?)
clrseq db esc,'[H',esc,'[J$'
ceolseq db esc,'[K$'
invseq db esc,'[7m$'
nrmseq db esc,'[0m$'
ivlatt db swidth dup (0fH) ; a line's worth of inverse attribute
; special keys.
spckey dw prvkey,nxtkey,brkkey,prtkey,prtkey+ctlkey,prvkey+ctlkey
dw nxtkey+ctlkey,brkkey+ctlkey
spclen equ ($-spckey)/2
; special key handlers. Must parallel spckey
spchnd dw prvscr,nxtscr,sendbr,prtscr,togprt,prvlin,nxtlin,sendbr
; arrow and PF keys
arrkey db 27H,29H,2bH,2dH,59H,5cH,5fH,62H
arrlen equ $-arrkey
; translations for arrow and PF keys, must parallel arrkey
arrtrn dw uptrn,dntrn,rgttrn,lfttrn
dw pf1trn,pf2trn,pf3trn,pf4trn
; keypad keys
keypad db 2fh,32h,35h,38h,3bh,3eh,41h,44h,47h,4ah,4dh,50h,53h,56h
keypln equ $-keypad
; keytrn and altktrn must parallel keypad
keytrn db '0123456789-,.',cr
altktrn db 'pqrstuvwxymlnM'
keyptr dw keytrn ; pointer to correct translation table
akeyflg db 0 ; non-zero if in alt keypad mode.
; arrow and PF key translations
uptrn db 3,esc,'[A'
dntrn db 3,esc,'[B'
rgttrn db 3,esc,'[C'
lfttrn db 3,esc,'[D'
pf1trn db 3,esc,'OP'
pf2trn db 3,esc,'OQ'
pf3trn db 3,esc,'OR'
pf4trn db 3,esc,'OS'
ourarg termarg <>
; variables for serial interrupt handler
source db bufsiz DUP(?) ; Buffer for data from port.
srcpnt dw 0 ; Pointer in buffer (DI).
count dw 0 ; Number of chars in int buffer.
savesi dw 0 ; Save SI register here.
telflg db 0 ; non-zero if we're a terminal. NRU.
respkt db 10 dup (?) ; ioctl packet
ivec dw tranb ; transmit empty B
dw tranb ; status change B
dw tranb ; receive b
dw tranb ; special receive b
dw stxa ; transmit empty a
dw sstata ; status change a
dw srcva ; receive a
dw srcva ; special receive a
; multi-screen stuff
bsize equ swidth*slen*npgs ; # of bytes needed to store screens
tbuf db bsize dup (?)
bbuf db bsize dup (?) ; top and bottom buffers
topbuf cbuf <tbuf,tbuf+bsize-1,tbuf,0>
botbuf cbuf <bbuf,bbuf+bsize-1,bbuf,0>
tlbuf db swidth dup (?) ; top line temp buffer
blbuf db swidth dup (?) ; bottom line temp buffer
rlbuf db swidth dup (?) ; line temp buffer
prbuf db swidth dup (?) ; print temp buffer
topdwn db esc,'[H',esc,'M$' ; go to top, scroll down
botup db esc,'[24;0H',esc,'D$' ; go to bottom, scroll up
curinq db esc,'[6n$' ; cursor inquiry
posbuf db 20 dup (?) ; place to store cursor position
gtobot db esc,'[24;0H$' ; go to bottom of screen.
ourscr db slen*swidth dup (?)
ourattr db slen*swidth dup (?) ; storage for screen and attributes
inited db 0 ; terminal handler not inited yet.
dosmsg db '?Must be run in version 2.05 or higher$'
anssq1 db esc,'[c'
ansln1 equ $-anssq1
anssq2 db esc,'Z'
ansln2 equ $-anssq2
eakseq db esc,'='
dakseq db esc,'>'
ansbk1 ans <anssq1,ansln1,anssq1,ansln1,sndans> ; two answerbacks
ansbk2 ans <anssq2,ansln2,anssq2,ansln2,sndans>
ansbk3 ans <eakseq,2,eakseq,2,enaaky> ; enable alt keypad
ansbk4 ans <dakseq,2,dakseq,2,deaaky> ; disable alt keypad
ansret db esc,'[?6c'
ansrln equ $-ansret
shkbuf db 300 dup (?) ; room for definition
shkmsg db ' Scan code: '
shkmln equ $-shkmsg
shkms1 db cr,lf,' Definition: '
shkm1ln equ $-shkms1
datas ends
code segment public
extrn comnd:near, dopar:near
assume cs:code,ds:datas
; local initialization routine, called by Kermit initialization.
lclini proc near
; make sure this is DOS version 2.05 or higher...
mov ah,dosver
int dos
xchg al,ah ; put major version in ah, minor in al
cmp ax,205H ; is it 2.05?
jae lclin1 ; yes, go on
mov dx,offset dosmsg
call tmsg
mov ax,4c00H ; exit(0)
int dos
lclin1: mov flags.vtflg,0 ; turn off heath emulation
ret
lclini endp
; this is called by Kermit initialization. It checks the
; number of disks on the system, sets the drives variable
; appropriately. The only problem is that a value of two
; is returned for single drive systems to be consistent
; with the idea of the system having logical drives A and
; B. Returns normally.
DODISK PROC NEAR
mov ah,gcurdsk ; Current disk value to AL.
int dos
mov dl,al ; Put current disk in DL.
mov ah,seldsk ; Select current disk.
int dos ; Get number of drives in AL.
mov drives,al
ret
DODISK ENDP
; show the definition of a key. The terminal argument block (which contains
; the address and length of the definition tables) is passed in ax.
; Returns a string to print in AX, length of same in CX.
; Returns normally.
showkey proc near
push es
push ax ; save the ptr
cld
showk1: mov di,6 ; get level one char
int firmwr
cmp cl,0ffH
jne showk1 ; wait until char available
mov bx,ds
mov es,bx ; address data segment
and ax,not cplk ; no caps lock
push ax ; remember scan code
mov di,offset shkbuf
mov si,offset shkmsg
mov cx,shkmln
rep movsb ; copy in initial message
call nout ; write out scan code
mov si,offset shkms1
mov cx,shkm1ln ; second message
rep movsb
pop ax ; get scan code back
pop bx ; and terminal arg block
mov cx,[bx].klen ; and length
jcxz showk2 ; no table, not defined
push di ; remember output ptr
mov di,[bx].ktab ; get key table
repne scasw ; search for a definition for this
mov si,di ; remember result ptr
pop di ; get output ptr back
jne showk2 ; not defined, forget it
sub si,[bx].ktab ; compute offset from beginning
sub si,2 ; minus 2 for pre-increment
add si,[bx].krpl ; get index into replacement table
mov si,[si] ; pick up replacement
mov cl,[si] ; get length
mov ch,0
inc si
rep movsb ; copy into buffer
showk2: mov ax,offset shkbuf ; this is buffer
mov cx,di
sub cx,ax ; length
pop es
ret ; and return
showkey endp
; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer. This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Returns normally.
CLRBUF PROC NEAR
cli
mov ax,offset source
mov srcpnt,ax
mov savesi,ax
mov count,0
sti
ret
CLRBUF ENDP
; Clear to the end of the current line. Returns normally.
CLEARL PROC NEAR
mov dx,offset ceolseq ; clear sequence
jmp tmsg
CLEARL ENDP
; Put the char in AH to the serial port. This assumes the
; port has been initialized. Should honor xon/xoff. Skip returns on
; success, returns normally if the character cannot be written.
outchr: mov bp,portval
cmp ds:[bp].floflg,0 ; Are we doing flow control.
je outch2 ; No, just continue.
xor cx,cx ; clear counter
outch1: cmp xofrcv,true ; Are we being held?
jne outch2 ; No - it's OK to go on.
loop outch1 ; held, try for a while
mov xofrcv,false ; timed out, force it off and fall thru.
outch2: push dx ; Save register.
sub cx,cx
mov al,ah ; Parity routine works on AL.
call dopar ; Set parity appropriately.
mov ah,al ; Don't overwrite character with status.
mov dx,mnstata ; port status register
outch3: in al,dx
test al,txrdy ; Transmitter ready?
jnz outch4 ; Yes
loop outch3
jmp outch5 ; Timeout
outch4: mov al,ah ; Now send it out
mov dx,mndata
out dx,al
pop dx
jmp rskp
outch5: pop dx
ret
; This routine blanks the screen. Returns normally.
CMBLNK PROC NEAR
mov dx,offset clrseq ; clear screen sequence
jmp tmsg
CMBLNK ENDP
; Locate; homes the cursor. Returns normally.
LOCATE PROC NEAR
mov dx,0 ; Go to top left corner of screen.
jmp poscur
LOCATE ENDP
; write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $. Returns normally.
putmod proc near
push dx ; preserve message
mov dx,24 * 100H ; line 24
call poscur
mov dx,offset invseq ; put into inverse video
call tmsg
pop dx
call tmsg ; print the message
mov dx,offset nrmseq ; normal videw
call tmsg
ret ; and return
putmod endp
; clear the mode line written by putmod. Returns normally.
clrmod proc near
mov dx,24 * 100H
call poscur
call clearl
ret
clrmod endp
; Put a help message on the screen. This one uses reverse video...
; pass the message in ax, terminated by a null. Returns normally.
puthlp proc near
push ax
mov dx,slen * 100H ; go to bottom line
call poscur
pop ax
push es
mov bx,ds
mov es,bx ; address data segment
mov si,ax ; convenient place for this
mov bx,101H ; current line/position
puthl1: mov di,offset phbuf ; this is destination
xor cx,cx ; # of chars in the line
puthl2: lodsb ; get a byte
cmp al,cr ; carriage return?
je puthl2 ; yes, ignore it
cmp al,lf ; linefeed?
je puthl3 ; yes, break the loop
cmp al,0
je puthl3 ; ditto for null
dec cx ; else count the character
stosb ; deposit into the buffer
jmp puthl2 ; and keep going
puthl3: add cx,80 ; this is desired length of the whole
mov al,' '
rep stosb ; fill the line
push bx
push si
push es ; firmware likes to eat this one
mov ax,0 ; send chars and attributes
mov cx,80 ; this is # of chars to send
mov dx,offset ivlatt ; this are attributes to send
mov si,offset phbuf ; the actual message
mov di,14H ; send direct to screen
mov bp,ds ; need data segment as well
int firmwr ; go send it
pop es
pop si
pop bx ; restore everything
inc bx ; next line
cmp byte ptr [si-1],0 ; were we ended by a 0 last time?
jne puthl1 ; no, keep looping
pop es ; else restore this
ret ; and return
puthlp endp
; Set the baud rate for the current port, based on the value
; in the portinfo structure. Returns normally.
; no baud rate.
DOBAUD PROC NEAR
mov dx,offset nyimsg
call tmsg
mov bx,portval
mov [bx].baud,-1 ; keep baud rate unknown.
ret
DOBAUD ENDP
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port. Returns normally.
; This is used during initialization.
GETBAUD PROC NEAR
ret ; no baud rate for now.
GETBAUD ENDP
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR PROC NEAR
call chkxon ; see if we have to xon the host.
cmp count,0
jnz prtch2
jmp rskp ; No data - check console.
prtch2: mov si,savesi
lodsb ; get a byte
cmp si,offset source + bufsiz ; bigger than buffer?
jb prtch1 ; no, keep going
mov si,offset source ; yes, wrap around
prtch1: dec count
mov savesi,si
mov dx,count ; return # of chars in buffer
ret
PRTCHR ENDP
; local routine to see if we have to transmit an xon
chkxon proc near
push bx
mov bx,portval
cmp [bx].floflg,0 ; doing flow control?
je chkxo1 ; no, skip all this
cmp xofsnt,false ; have we sent an xoff?
je chkxo1 ; no, forget it
cmp count,mntrgh ; below trigger?
jae chkxo1 ; no, forget it
mov ax,[bx].flowc ; ah gets xon
call outchr ; send it
nop
nop
nop ; in case it skips
mov xofsnt,false ; remember we've sent an xon.
chkxo1: pop bx ; restore register
ret ; and return
chkxon endp
; Send a break out the current serial port. Returns normally.
SENDBR PROC NEAR
push bx
push cx
push dx
push ax
mov ah,ioctl
mov al,3 ; write to control channel.
mov bx,3 ; aux port handle
mov dx,offset iobuf
mov iobuf,stbrk ; start sending a break
int dos
xor cx,cx ; clear loop counter
pause: loop pause ; Wait a while.
mov ah,ioctl
mov al,3
mov bx,3
mov dx,offset iobuf
mov iobuf,enbrk ; stop sending the break
int dos
pop ax
pop dx
pop cx
pop bx
ret ; And return.
SENDBR ENDP
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR PROC NEAR
add dx,101H ; start at 1,1
push es
push dx
cld
mov ax,ds
mov es,ax ; address right segment
mov di,offset rowp
mov al,dh ; row comes first
mov ah,0
call nout
mov al,';'
stosb ; separated by a semi
pop dx
mov al,dl
mov ah,0
call nout
mov al,'H'
stosb ; end w/H
mov byte ptr [di],'$' ; and dollar sign
mov dx,offset gopos
call tmsg
pop es
ret
POSCUR ENDP
; Delete a character from the terminal. This works by printing
; backspaces and spaces. Returns normally.
DODEL PROC NEAR
mov dx,offset delstr ; Erase weird character.
jmp tmsg
DODEL ENDP
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
CTLU PROC NEAR
mov dx,offset clrlin ; this just goes to left margin...
call tmsg
jmp clearl ; now clear line
CTLU ENDP
; set the current port.
COMS PROC NEAR
mov dx,offset nyimsg
jmp tmsg
COMS ENDP
; Set heath emulation on/off.
VTS PROC NEAR
mov dx,offset nyimsg
jmp tmsg
VTS ENDP
; initialization for using serial port. This routine performs
; any initialization necessary for using the serial port, including
; setting up interrupt routines, setting buffer pointers, etc.
; Doing this twice in a row should be harmless (this version checks
; a flag and returns if initialization has already been done).
; SERRST below should restore any interrupt vectors that this changes.
; Returns normally.
SERINI PROC NEAR
push es
cmp portin,0 ; Did we initialize port already? [21c]
jne serin0 ; Yes, so just leave. [21c]
cli ; Disable interrupts
cld ; Do increments in string operations
xor ax,ax ; Address low memory
mov es,ax
mov ax,es:[4*serchn] ; get old serial handler
mov oldser,ax ; save.
mov ax,es:[4*serchn+2] ; get segment
mov oldseg,ax ; save segment as well
mov ax,es:[4*serch1] ; this is alternate for older rainbows
mov old1ser,ax
mov ax,es:[4*serch1+2]
mov old1seg,ax ; pretty silly, huh?
mov ax,offset serint ; point to our routine
mov word ptr es:[4*serchn],ax ; point at our serial routine
mov word ptr es:[4*serch1],ax ; have to set both of these
mov es:[4*serchn+2],cs ; our segment
mov es:[4*serch1+2],cs
mov al,030h ;[DTR] enable RTS and DTR
out mnctrl,al ;[DTR]
mov portin,1 ; Remember port has been initialized.
call clrbuf ; Clear input buffer.
sti ; Allow interrupts
serin0: pop es
ret ; We're done.
SERINI ENDP
; this is used to by serini
prtset proc near
lodsb ; get a byte
or al,al
jz prtse1 ; end of table, stop here
out dx,al ; else send it out
jmp prtset ; and keep looping
prtse1: ret ; end of routine
prtset endp
; Reset the serial port. This is the opposite of serini. Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.
SERRST PROC NEAR
push es ; preserve this
cmp portin,0 ; Reset already?
je srst1 ; Yes, just leave.
cli ; Disable interrupts
xor ax,ax
mov es,ax ; address segment 0
mov ax,oldser
mov es:[4*serchn],ax
mov ax,oldseg
mov es:[4*serchn+2],ax
mov ax,old1ser
mov es:[4*serch1],ax
mov ax,old1seg
mov es:[4*serch1+2],ax ; restore old handlers
mov portin,0 ; Reset flag.
srst1: pop es
ret ; All done.
SERRST ENDP
; serial port interrupt routine. This is not accessible outside this
; module, handles serial port receiver interrupts.
serint PROC NEAR
push bx
push dx
push ax
push es
push di
push ds
push bp
push cx
cld
mov ax,seg datas
mov ds,ax ; address data segment
mov es,ax
mov di,srcpnt ; Registers for storing data.
mov dx,mnstatb ; Asynch status port.
mov al,0 ; innocuous value
out dx,al ; send out to get into a known state...
mov al,2 ; now address register 2
out dx,al
in al,dx ; read interrupt cause
cmp al,7 ; in range?
ja serin7 ; no, just dismiss (what about reset error?)
mov bl,al
shl bl,1 ; double for word index
mov bh,0
call ivec[bx] ; call appropriate handler
serin7: mov dx,mnstata ; reload port address
mov al,38H
out dx,al ; tell the port we finished with the interrupt
pop cx
pop bp
pop ds
pop di
pop es
pop ax
pop dx
pop bx
intret: iret
; handler for serial receive, port A
srcva: mov dx,mnstata
mov al,0
out dx,al ; put into known state...
in al,dx
test al,rxrdy ; Data available?
jnz srcva1 ; yes, go read it
jmp srcva7
srcva1: mov al,30H ; reset any errors
out dx,al
mov dx,mndata
in al,dx ; read the character
cmp telflg,0 ; File transfer or terminal mode?
jz srcva2
and al,7FH ; Terminal mode (7 bits only).
srcva2: or al,al
jz srcva7 ; Ignore nulls.
cmp al,7FH ; Ignore rubouts, too.
jz srcva7
mov ah,al
and ah,7fH ; only consider low-order 7 bits for flow ctl.
mov bp,portval
cmp ds:[bp].floflg,0 ; Doing flow control?
je srcva4 ; Nope.
mov bx,ds:[bp].flowc ; Flow control char (BH = XON, BL = XOFF).
cmp ah,bl ; Is it an XOFF?
jne srcva3 ; Nope, go on.
mov xofrcv,true ; Set the flag.
jmp short srcva7
srcva3: cmp ah,bh ; Get an XON?
jne srcva4 ; No, go on.
mov xofrcv,false ; Clear our flag.
jmp srcva7
srcva4: stosb
cmp di,offset source + bufsiz
jb srcva5 ; not past end...
mov di,offset source ; wrap buffer around
srcva5: mov srcpnt,di ; update ptr
inc count
cmp ds:[bp].floflg,0 ; Doing flow control?
je srcva7 ; No, just leave.
cmp xofsnt,true ; Have we sent an XOFF?
je srcva7 ; Yes.
cmp count,mntrgh ; Past the high trigger point?
jbe srcva7 ; No, we're within our limit.
mov ah,bl ; Get the XOFF.
call outchr ; Send it.
nop
nop
nop ; ignore failure.
mov xofsnt,true ; Remember we sent it.
srcva7: ret
; The interrupt is for the 'B' port - transfer control to
; the original handler and hope for the best.
tranb: pushf ; put flags on stack to simulate interrupt
call dword ptr [old1ser] ; call old handler
ret ; and return
stxa: mov dx,mnstata
mov al,28H ; reset transmit interrupt
out dx,al
ret
sstata: mov dx,mnstata
mov al,10H ; reset status interrupt
out dx,al
ret
SERINT ENDP
; Produce a short beep. The PC DOS bell is long enough to cause a loss
; of data at the port. Returns normally.
BEEP PROC NEAR
mov dl,bell
mov ah,conout
int dos
ret
BEEP ENDP
; put the number in ax into the buffer pointed to by di. Di is updated
nout proc near
mov dx,0 ; high order is always 0.
mov bx,10
div bx ; divide to get digit
push dx ; save remainder digit
or ax,ax ; test quotient
jz nout1 ; zero, no more of number
call nout ; else call for rest of number
nout1: pop ax ; get digit back
add al,'0' ; make printable
stosb ; drop it off
ret ; and return
nout endp
term proc near
mov si,ax ; this is source
mov di,offset ourarg ; place to store arguments
mov ax,ds
mov es,ax ; address destination segment
mov cx,size termarg
cld
rep movsb ; copy into our arg blk
cmp inited,0 ; inited yet?
jz term1 ; no, keep going
test ourarg.flgs,scrsam ; do they want us to leave it alone?
jnz term1 ; yes, skip redisplay.
call rstscr ; restore screen
term1: mov inited,1 ; remember inited
term2: call prtchr
jmp short term3 ; have a char...
nop
nop
jmp short term6 ; no char, go on
term3: and al,7fh ; turn off parity for terminal
mov bx,offset ansbk1 ; check 1st answerback
call ansbak ; check for answerback
mov bx,offset ansbk2 ; maybe second answerback
call ansbak
mov bx,offset ansbk3
call ansbak
mov bx,offset ansbk4
call ansbak
cmp al,lf ; linefeed?
jne term4 ; no, keep going
call scrprep ; need to save top line
mov al,lf ; get char back
term4: push ax
int fastcon ; go print it
pop ax
test ourarg.flgs,capt ; capturing output?
jz term5 ; no, forget it
push ax
call ourarg.captr ; else call the routine
pop ax
term5: test ourflgs,fpscr ; print screen toggled on?
jz term6 ; no, keep going
mov dl,al
mov ah,lstout ; printer output
int dos
term6: mov di,6 ; get level 1 character
push es
int firmwr
pop es ; don't let firmware steal registers.
cmp cl,0ffh ; character available?
je term7 ; no, do something else
cmp cl,1 ; maybe level 2 sequence around
jne term2 ; no, forget it
mov di,2 ; get level 2 character
push es
int firmwr
pop es
cmp cl,0ffh ; did we really get one?
jne term2 ; no, something strange happening.
jmp term6 ; else skip and keep trying.
term7: test ax,fnkey ; function-type key?
jnz term8 ; yes, can't be escape character
cmp al,ourarg.escc ; escape char?
je term9 ; yes, exit
term8: call trnout ; perform necessary translations, output char
jmp term2 ; and loop around
term9: call savscr ; save screen
ret ; and return
term endp
; enter with current terminal character in al, answerback ptr in bx.
; calls answerback routine if necessary.
; This can be used to make the emulator recognize any sequence.
ansbak proc near
push ax ; preserve this
mov si,[bx].anspt ; get current pointer
cmp al,[si] ; is it correct?
jne ansba1 ; no, reset pointers and go on
inc [bx].anspt ; increment pointer
dec [bx].ansct ; decrement counter
jnz ansba2 ; not done, go on
push bx
call [bx].ansrtn ; send answerback
pop bx
ansba1: mov ax,[bx].ansseq ; get original sequence
mov [bx].anspt,ax
mov al,[bx].anslen ; and length
mov [bx].ansct,al
ansba2: pop ax
ret
ansbak endp
; send the answerback message.
sndans proc near
mov si,offset ansret ; this is what we say
mov cx,ansrln ; length of same
sndan1: lodsb ; get a byte
mov ah,al
push si
push cx
call outchr
nop
nop
nop
pop cx
pop si
loop sndan1
ret
sndans endp
; enable alternate keypad mode
enaaky proc near
mov akeyflg,1 ; remember alternate mode
mov keyptr,offset altktrn ; set correct translate table
ret
enaaky endp
; disable alternate keypad mode
deaaky proc near
mov akeyflg,0
mov keyptr,offset keytrn
ret
deaaky endp
; enter with char and flags in ax. Does any necessary character translations,
; then outputs character
trnout proc near
and ax,not cplk ; forget about caps lock key
test ourarg.flgs,havtt ; any translate table?
jz trnou2 ; no, just output normally
mov cx,ourarg.klen
mov di,ourarg.ktab ; get redefined keys
repne scasw ; look for this one
jne trnou2 ; not found, try something else
sub di,ourarg.ktab
sub di,2 ; get index
add di,ourarg.krpl ; get translation address
mov si,[di] ; this is translation
mov cl,[si]
inc si ; pick up length, increment past it
mov ch,0
jcxz trnou6 ; no translation, just return
trnou1: lodsb ; get a char
push si
push cx
call sndhst ; send the character
pop cx
pop si
loop trnou1 ; loop thru rest of translation
ret ; and return
trnou2: test ax,fnkey ; function key?
jz trnou5 ; no, keep going
and ax,not fnkey ; turn off function bit.
mov di,offset spckey ; our special keys
mov cx,spclen ; length of special key table
repne scasw ; look for it in our table
jne trnou3 ; not found, maybe arrow key...
sub di,offset spckey+2 ; get index
call spchnd[di] ; call appropriate handler
ret ; and return
trnou3: mov di,offset arrkey ; look for an arrow-type key...
mov cx,arrlen ; length of arrow key table
repne scasb ; is it an arrow key?
jne trnou4 ; no, forget it
sub di,offset arrkey+1 ; get index into table
shl di,1 ; double for word index
mov si,arrtrn[di] ; get translation
mov cl,[si]
inc si
mov ch,0
jmp trnou1 ; go send translation
trnou4: mov di,offset keypad ; look for a keypad key.
mov cx,keypln
repne scasb ; is it in keypad?
jne trnou6 ; no, forget it
sub di,offset keypad+1
add di,keyptr ; index into correct translation table
mov al,[di] ; get translation
cmp akeyflg,0 ; in alternate keypad mode?
je trnou5 ; no, just send the char
push ax ; else save the character
mov al,esc
call sndhst
mov al,'O'
call sndhst ; send prefix
pop ax ; get the character back and fall thru...
trnou5: call sndhst ; send the character
trnou6: ret
trnout endp
; handle the print screen key
prtscr proc near
push ds ; save data segment
mov ax,scrseg
mov ds,ax ; address screen segment
mov cx,slen ; # of lines on screen
mov bx,0 ; current line #
prtsc1: push cx ; save counter
push bx ; and line ptr
mov si,ds:[latofs+bx] ; get ptr to line
mov cx,swidth ; max # of chars/line
mov di,offset prbuf ; print buffer
prtsc2: lodsb ; get a byte
or al,al ; is it a null?
jne prtsc3 ; no, go on
mov al,' ' ; yes, replace by space
prtsc3: stosb ; drop it off
cmp al,' ' ; is it a space?
je prtsc4 ; yes, go on
mov dx,cx ; else remember count at last non-space
prtsc4: cmp al,0ffH ; end of line?
loopne prtsc2 ; continue if not end
mov cx,dx ; count at last non-space, plus 1
neg cx
add cx,swidth+1 ; figure out # of chars to print
mov dx,offset prbuf
push ds ; save this temporarily
mov ax,es
mov ds,ax ; address data segment to print
jcxz prtsc5 ; 0 length, keep going
mov bx,4 ; standard printer device
mov ah,writef2 ; write call
int dos ; write to the printer
prtsc5: mov ah,writef2
mov bx,4
mov dx,offset crlf
mov cx,2
int dos ; follow line with a crlf
pop ds
pop bx
pop cx ; restore counters
add bx,2 ; point to next line
loop prtsc1 ; and keep going
pop ds ; restore registers
ret ; and return
prtscr endp
; toggle print flag...
togprt proc near
xor ourflgs,fpscr ; toggle flag
ret ; and return
togprt endp
; Send a character to the host, handle local echo
sndhst proc near
push ax ; save the character
mov ah,al
call outchr
nop
nop
nop
pop ax
test ourarg.flgs,lclecho ; echoing?
jz sndhs2 ; no, exit
cmp al,lf ; scrolling? ***
jne sndhs1 ; no, go on
call scrprep
mov al,lf
sndhs1: int fastcon
sndhs2: ret ; and return
sndhst endp
; print a message to the screen. Returns normally.
tmsg proc near
mov ah,prstr
int dos
ret
tmsg endp
; save the screen for later
savscr proc near
push ds
mov ax,scrseg
mov ds,ax
mov cx,slen ; # of lines to do
mov bx,0 ; current line #
mov di,offset ourscr ; place to save screen
mov dx,offset ourattr ; and to save attributes
savsc1: push cx ; save current count
mov si,ds:[latofs+bx] ; get line ptr
mov cx,swidth ; # of chars/line
rep movsb ; copy it out
mov si,ds:[latofs+bx]
add si,1000H ; this is where attributes start
xchg dx,di ; this holds attribute ptr
mov cx,swidth ; # of attrs to move
rep movsb
xchg dx,di
pop cx ; restore counter
add bx,2 ; increment line ptr
loop savsc1 ; save all lines and attributes
pop ds
call savpos ; might as well save cursor pos
ret
savscr endp
; restore the screen saved by savscr
rstscr proc near
call cmblnk ; start by clearing screen
mov si,offset ourscr ; point to saved screen
mov dx,offset ourattr ; and attributes
mov cx,slen ; # of lines/screen
mov bx,101H ; start at top left corner
rstsc1: push bx
push cx
push si ; save ptrs
push dx
mov ax,si ; this is source
call prlina ; print the line
pop dx
pop si
pop cx
pop bx
add si,swidth ; point to next line
add dx,swidth ; and next attributes
inc bx ; address next line
loop rstsc1 ; keep restore lines
call rstpos ; don't forget position
ret
rstscr endp
; circular buffer management for screen.
; for these to work correctly, the buffer size MUST be a multiple
; of the screen width.
; put a line into the circular buffer. Pass the buffer structure
; in bx, the pointer to the line in ax.
putcirc proc near
push si
push di
push cx
push dx
mov di,[bx].pp ; pick up buffer ptr
add di,swidth ; increment to next avail slot
cmp di,[bx].bend ; past end?
jb putci1 ; no, leave alone
mov di,[bx].orig ; else start at beginning
putci1: mov [bx].pp,di ; update ptr
mov si,ax ; this is source
mov cx,swidth
rep movsb ; copy into buffer
cmp [bx].lcnt,npgs*slen ; can we increment it?
jae putci2 ; no, keep going
inc [bx].lcnt ; else count this line
putci2: pop dx
pop cx
pop di
pop si ; restore registers
ret
putcirc endp
; get a line from the circular buffer, removing it from the buffer.
; returns with carry on if the buffer is empty.
; pass the buffer structure in bx, the buffer to copy the line into
; in ax.
getcirc proc near
push si
push di
push cx
push dx
cmp [bx].lcnt,0 ; any lines in buffer?
jne getci1 ; yes, ok to take one out.
stc ; else set carry
jmp short getcir3 ; and return
getci1: mov si,[bx].pp ; this is source
mov di,ax ; this is dest
mov cx,swidth ; # of chars to copy
rep movsb
mov si,[bx].pp ; get ptr again
sub si,swidth ; move back
cmp si,[bx].orig ; compare to origin
jae getcir2 ; still in range, continue
mov si,[bx].bend ; else use end of buffer
sub si,swidth-1 ; minus length of a piece
getcir2:mov [bx].pp,si ; update ptr
dec [bx].lcnt ; decrement # of lines in buffer
clc ; make sure no carry
getcir3:pop dx
pop cx
pop di
pop si
ret
getcirc endp
; prepares for scrolling by saving the top line in topbuf.
scrprep proc near
push ds ; preserve data segment
mov ax,scrseg
mov ds,ax ; address screen segment
cmp byte ptr [ds:csrlin],slen ; are we at the bottom?
pop ds ; restore in case we're returning...
jne scrpr1 ; no, don't save it
; alternate entry that doesn't check if we're on the bottom row.
savtop: push es
push ds
mov ax,ds
mov es,ax
mov ax,scrseg
mov ds,ax ; address screen segment
mov si,ds:word ptr [l1ptr] ; get ptr to top line
mov di,offset tlbuf ; this is where it goes
mov cx,swidth ; # of bytes to copy
rep movsb ; get the top line
pop ds
pop es ; restore segments
mov bx,offset topbuf ; top buffer ptr
mov ax,offset tlbuf ; this is where line is now
call putcirc ; put into circular buffer
scrpr1: ret ; and return
scrprep endp
; get the screen's bottom line into the buffer in ax.
getbot proc near
push es
push ds
push ax
mov ax,ds
mov es,ax
mov ax,scrseg
mov ds,ax
mov si,ds:word ptr [llptr] ; get ptr to bottom line
pop di ; destination is on stack
mov cx,swidth ; # of bytes to copy
rep movsb ; get the top line
pop ds ; restore segments
pop es
ret
getbot endp
; handle the previous screen button...
prvscr proc near
mov ax,offset tlbuf
mov bx,offset topbuf
call getcirc
jc prvsc3 ; no lines, forget it
call savpos ; save cursor position
mov ax,offset botbuf ; place to put screen
mov bx,slen ; else just use last line on screen
mov dx,-1 ; move backwards
call rolscr ; save current screen
call cmblnk ; clear screen
mov cx,slen ; # of lines per screenfull
prvsc1: mov bl,cl ; this is current line
mov bh,1 ; this is column
mov ax,offset tlbuf ; where to get the line from
push cx ; save count
call prlin ; put the line on the screen
mov ax,offset tlbuf
mov bx,offset topbuf
call getcirc ; get another line
pop cx
jc prvsc2 ; no more, exit loop
loop prvsc1 ; loop for all lines
prvsc2: call rstpos ; restore screen position
prvsc3: ret ; and return
prvscr endp
; handle the next screen button...
nxtscr proc near
mov ax,offset tlbuf
mov bx,offset botbuf
call getcirc ; get a line from the bottom
jc nxtsc3 ; no lines, forget it
call savpos ; save cursor pos
mov ax,offset topbuf ; place to put screen
mov bx,1 ; start with first line
mov dx,1 ; move backwards
call rolscr ; save current screen
call cmblnk ; clear screen
mov cx,slen ; # of lines per screenfull
nxtsc1: mov bl,slen+1
sub bl,cl ; this is current line
mov bh,1 ; this is column
mov ax,offset tlbuf ; where to get the line from
push cx ; save count
call prlin ; put the line on the screen
mov ax,offset tlbuf ; where to put the next line
mov bx,offset botbuf
call getcirc ; try to get another
pop cx
jc nxtsc2 ; no more, break loop
loop nxtsc1 ; loop for all lines
nxtsc2: call rstpos ; restore cursor position
nxtsc3: ret ; and return
nxtscr endp
; save a screen by rolling them into a circular buffer.
; enter with ax/ circular buffer ptr, bx/ first line to get
; dx/ increment
rolscr proc near
shl dx,1 ; double increment for word ptr
dec bx ; ptr starts at 0
shl bx,1 ; convert to word ptr
mov cx,slen ; # of lines to save
rolsc1: push cx
push dx
push bx
push ax
push ds
mov ax,scrseg
mov ds,ax ; address screen
mov si,ds:[latofs+bx] ; get current line
mov di,offset rlbuf ; place to put it
mov cx,swidth ; # of bytes to move
rep movsb ; get the lne
pop ds ; restore segment
pop bx ; this is desired circ buffer ptr
mov ax,offset rlbuf ; this is where the line is
call putcirc ; save in circular buffer
mov ax,bx ; put buffer ptr back where it belongs
pop bx ; get line pos back
pop dx ; and increment
pop cx ; don't forget counter
add bx,dx ; move to next line
loop rolsc1 ; loop thru all lines
ret ; and return
rolscr endp
; move screen down a line, get one previous line back
prvlin proc near ; get the previous line back
mov ax,offset tlbuf ; place to put line temporarily
mov bx,offset topbuf ; where to get lines from
call getcirc ; try to get a line
jc prvli1 ; no more, just return
mov ax,offset blbuf ; place for bottom line
call getbot ; fetch bottom line
mov ax,offset blbuf
mov bx,offset botbuf
call putcirc ; save in circular buffer
call savpos ; save cursor position
mov dx,offset topdwn ; home, then reverse index
call tmsg
mov ax,offset tlbuf ; point to data
mov bx,0101H ; print line at top of screen
call prlin ; print the line
call rstpos ; restore cursor position
prvli1: ret ; and return
prvlin endp
; move screen up a line, get one bottom line back
nxtlin proc near
mov ax,offset blbuf ; place to put line temporarily
mov bx,offset botbuf ; where to get lines from
call getcirc ; try to get a line
jc nxtli1 ; no more, just return
call savtop ; save one line off of top
call savpos ; save cursor position
mov dx,offset botup ; go to bottom, then scroll up a line
call tmsg
mov ax,offset blbuf ; point to data
mov bx,0100H + slen ; print at bottom line
call prlin ; print the line
call rstpos ; restore cursor position
nxtli1: ret ; and return
nxtlin endp
; save cursor position
savpos proc near
mov dx,offset curinq ; where is the cursor?
call tmsg
mov posbuf,esc ; put an escape in the buffer first
mov di,offset posbuf+1
savpo1: mov ah,8 ; read, no echo
int dos
cmp al,'R' ; end of report?
je savpo2 ; yes
stosb ; no, save it
jmp savpo1 ; and go on
savpo2: mov al,'H' ; this ends the sequence when we send it
stosb
mov byte ptr [di],'$' ; need this to print it later
ret ; and return
savpos endp
; restore the position saved by savpos
rstpos proc near
mov dx,offset posbuf
call tmsg ; just print this
ret ; and return
rstpos endp
; print a ff-terminated line at most swidth long... Pass the line in ax.
; cursor position should be in bx.
; prlina writes attributes as well, which should be passed in dx.
prlin proc near
mov bp,2 ; print characters only
jmp short prli1
prlina: xor bp,bp ; 0 means print attributes as well.
prli1: push es ; this trashes es!!!
mov si,ax ; better place for ptr
mov di,ax ; need it here for scan
mov cx,swidth ; max # of chars in line
mov al,0ffh ; this marks the end of the line
repne scasb ; look for the end
jne prli2 ; not found
inc cx ; account for pre-decrement
prli2: neg cx
add cx,swidth ; figure out length of line
jcxz prli3 ; 0-length line, skip it.
mov ax,2 ; writing characters
mov bp,ds ; wants segment here
mov di,14H ; fast write to screen
int firmwr ; pos is in bx, char ptr in si
prli3: pop es ; restore register
ret ; and return
prlin endp
; 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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxrb.asm
/bin/echo -n ' '; /bin/ls -ld msxrb.asm
fi
/bin/echo 'Extracting msxsys.doc'
sed 's/^X//' <<'//go.sysin dd *' >msxsys.doc
SPECIFICATION FOR KERMIT SYSTEM-DEPENDENT MODULES
by Jeff Damens, Columbia University
All the system-independent global data structures used in Kermit-MS are defined
in the file MSDEFS.H.
The routine MSXxxx.ASM contains system-dependent support for system xxx, except
for terminal emulation, which is in MSXxxx.ASM, described below.
The routines in the MSX module may change any registers but the stack pointer
and segment registers, unless otherwise noted. A routine that returns via a
RET instruction is said to return normally; a routine that skip returns is one
that returns to three bytes past the normal return address.
Global variables that must be defined in the system-dependent module:
XXOFSNT byte. This should be set to a non-zero value if we are doing
flow control and have sent an XOFF character to the remote
host, zero otherwise.
MACHNAM byte. A $-terminated string identifying the machine this
version of Kermit is for; it is printed when Kermit starts up.
SETKTAB byte. A keyword table associating terminal key names to 16-bit
scan code values, used in the set key command. If the kermit
version can accept arbitrary decimal values as scan codes, the
word "SCAN" should appear in the table with a scan value of -1.
If key redefinition is not implemented, the first byte of the
table should be a zero.
SETKHLP byte. A $-terminated string to be printed when ? is typed in
the SET KEY command. This is usually simply a list of the key
names in SETKTAB. SETKHLP must be defined even if key
redefinition is not implemented, to satisfy the linker; if key
redefinition is not implemented, SETKHLP will never be
displayed.
COUNT word. The number of characters in the serial input buffer, if
known. This is how Kermit knows to send an XON if the serial
handler has sent an XOFF. If the number of characters in the
buffer isn't known, COUNT should be 0.
These are the required entry points for the system dependent dependent module
MSXxxx.ASM.
SERINI
Parameters None.
Returns Normally, no return value.
Description Perform any initialization that must be done before the serial
port can be used, including setting baud rate, interrupt
vectors, etc. Parity and baud rate should be set according to
the values in the PORTINFO structure. The external variable
PORTVAL points to the PORTINFO structure for the current port.
Calling SERINI more than once without an intervening call to
SERRST should have no effect.
SERRST
Parameters None.
Returns Normally, no return value.
Description Undoes any initialization done by SERINI, including resetting
the serial port, restoring any interrupt vectors changed by
SERINI, etc. Calling this more than once without an
intervening call to SERINI should be harmless.
CLRBUF
Parameters None.
Returns Normally, no return value.
Description Remove and discard from the serial port's input buffer any
characters sent by the remote host that have not yet been read
by Kermit, and set COUNT to 0. This is used before a file
transfer to flush NAK's that accumulate in the buffer when the
remote host is in server mode.
OUTCHR
Parameters A character in AH.
Returns Skip returns if the character has been transmitted; returns
normally if the character can not be transmitted because of a
hardware error.
Description Sends the character in AH out the currently selected serial
port. OUTCHR can assume that SERINI will have been called
previously. OUTCHR should call the external routine DOPAR to
set the parity of the character if the communications hardware
doesn't automatically set parity. Flow control should be
honored; the external variable PORTVAL contains a pointer to a
PORTINFO structure (as defined in MSDEFS.H) containing the
current flow control definitions.
COMS
Parameters None.
Returns Normally if a parse error is encountered, skip returns
otherwise.
Description Called by the SET PORT command. On a machine with multiple
serial ports, COMS should parse for the name or number of a
serial port and make that the port used by succeeding calls to
SERINI, PRTCHR, OUTCHR, and SERRST. It should set the external
variable PORTVAL to point to one of the external port
structures PORT1 or PORT2, and set COMFLG in the FLAGS
structure to 1 for port one, 0 for port 2. For implementations
that use only one serial port, COMS should print a message to
that effect and skip return.
VTS
Parameters None.
Returns Normally if a parse error is encountered, skip returns
otherwise.
Description Parses for an ON or OFF, sets HEATH-19 emulation while in
terminal emulation appropriately. The VTFLG field of the FLAGS
structure should be set non-zero if HEATH-29 emulation is on,
zero otherwise. If HEATH-19 emulation is not done, VTS should
print a message and skip return.
DODEL
Parameters None.
Returns Normally, no return value.
Description Erases the character immediately to the left of the cursor from
the screen, then backs up the cursor.
CTLU
Parameters None.
Returns Normally, no return value.
Description Move the cursor to the left margin, then clear the line.
CMBLNK
Parameters None.
Returns Normally, no return value.
Description Clears the screen and homes the cursor.
LOCATE
Parameters None.
Returns Normally, no return value.
Description Homes the cursor.
LCLINI
Parameters None.
Returns Normally, no return value.
Description Performs any system-dependent initialization required by this
implementation.
PRTCHR
Parameters None.
Returns Normally, with the next character from the currently selected
serial port in AL. Skip returns if no character is available.
Description Reads the next character from the current serial port. PRTCHR
can assume SERINI has been called previously, and should handle
flow control correctly.
DOBAUD
Parameters None.
Returns Normally, no return value.
Description Sets the baud rate for the current port. The baud rate should
be obtained from the BAUD field of the PORTINFO structure,
pointed to by the external variable PORTVAL.
CLEARL
Parameters None.
Returns Normally, no return value.
Description Clears from the cursor to the end of the current line.
DODISK
Parameters None.
Returns Normally, no return value.
Description Sets the external variable DRIVES to the number of disk drives
attached to the machine.
GETBAUD
Parameters None.
Returns Normally, no return value.
Description Store current baud rate of the currently selected port in the
BAUD field of the current PORTINFO structure, which is pointed
to by PORTVAL. If the baud rate is to default to a particular
value, this routine can store that value into the BAUD field
instead.
BEEP
Parameters None.
Returns Normally, no return value.
Description Rings the terminal bell.
PUTHLP
Parameters A pointer to a string in AX.
Returns Normally, no return value.
Description Writes the null-terminated string given in AX to the terminal.
This is used to display help and status messages. The IBM and
Rainbow versions write the string in a reverse video box.
PUTMOD
Parameters A pointer to a string in AX.
Returns Normally, no return value.
Description Writes the null-terminated string given in AX to the last line
of the screen, in inverse video if possible.
CLRMOD
Parameters None.
Returns Normally, no return value.
Description Clears the line written by PUTMOD.
POSCUR
Parameters Row in DH, column in DL.
Returns Normally, no return value.
Description Positions the cursor to the row and column given in DX. Rows
and columns both originate at 0 (not 1!).
SENDBR
Parameters None.
Returns Normally, no return value.
Description Send a break to the current serial port.
SHOWKEY
Parameters Pointer to a terminal argument block in AX (see TERM below).
Returns Normally, with a string pointer in AX and the length of the
string in CX.
Description Called by the SHOW KEY command. Reads a key from the terminal
and returns a string containing implementation-dependent
information about the key. In the usual case, the string
contains the key's (machine-dependent) scan code, and the key's
definition (if any) from the terminal argument block. The
length of the returned string should be returned in CX. The
string may contain any characters; unprintable characters will
be quoted when the string is printed. If the implementation
does not support key redefinition, SHOWKEY may return a static
string saying so.
TERM
Parameters Pointer to terminal argument block in AX.
Returns Normally, no return value.
Description Do terminal emulation, based on argument block described
below...
The terminal emulator is supplied in the file MSYxxx.ASM. The terminal
argument block passed to the terminal emulator has the following fields:
FLGS Byte containing flags. Flags are:
SCRSAM (80H) If on, the terminal emulator shouldn't
re-display the screen when entered.
CAPT (40H) Capture output. If on, the routine passed in
field CAPTR is called with each character sent
to the screen.
EMHEATH (20H) Emulate a Heath-19 terminal if on.
HAVTT (10H) A key redefinition table is present.
TRNCTL (08H) Print control character X as ^X (useful for
debugging).
MODOFF (04H) Do not display emulator mode line if on.
LCLECHO (01H) Echo keyboard characters on the screen in
addition to sending them to the port.
PRT Port to use for terminal emulation, used only in mode line.
This is just a copy of COMFLG in FLAGS.
COLS Number of columns on screen.
ROWS Number of rows on screen.
CAPTR Routine to call to with each character sent to the screen if
CAPT flag is on. Characters are passed in AL.
BELLD Bell divisor (used only on IBM).
KLEN Number of keys in key redefinition table, if HAVTT flag is on.
KTAB Address of key redefinition table. The key redefinition table
is a table of KLEN 16-bit scan codes. Each (machine dependent)
scan code represents a key that is redefined.
KRPL Address of key replacement table. The key replacement table
parallels the key redefinition table given in KTAB. Entries in
the replacement table are 16-bit pointers to redefinitions.
Each redefinition has a one-byte length, followed by the
definition.
ESCC Escape character (single byte). When this character is typed
to the emulator, it should return.
BAUDB byte. Bits describing the baud rate so it can be printed on
the mode line. This is a copy of the BAUD field in the
PORTINFO structure. Currently used only on the IBM. See
MSDEFS.H for possible values.
PARITY byte. Current parity to print on the mode line. This is a
copy of PARFLG in the PORTINFO structure. Currently used only
on the IBM. See MSDEFS.H for possible values.
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxsys.doc
/bin/echo -n ' '; /bin/ls -ld msxsys.doc
fiknutson@ut-ngp.UUCP (Jim Knutson) (10/05/84)
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting msxwng.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxwng.asm
public serini, serrst, clrbuf, outchr, coms, vts, dodel, ctlu
public cmblnk, locate, lclini, prtchr, dobaud, clearl
public dodisk, getbaud, beep, term, puthlp
public count, poscur, machnam, sendbr, putmod, clrmod
public setktab, setkhlp, xofsnt, showkey
include msdefs.h
false equ 0
true equ 1
ctrla equ 1 ; Control-A.
auxin equ 3
auxout equ 4
auxfil equ 3 ; file number of aux file.
iordy equ 6 ; input ready function
write equ 40h
wbios equ 88h
settrp equ 02h
clrtrp equ 03h
chrrdy equ 01h
txrdy equ 02h
rcvdat equ 1080h
rcvstat equ 1082h
rcvmod equ 1084h
rcvcmd equ 1086h
trdat equ 1088h
trmod equ 108ch
wrcmd equ 108eh
; mode bits
mod1 equ 4dh ; clock rate, 8 bits, 1 stop bit
mod2 equ 30h ; internal clock
; command register bits
txen equ 01h
dtr equ 02h
rxen equ 04h
brk equ 08h
clrerr equ 10h
rts equ 20h
datas segment public 'datas'
extrn drives:byte, flags:byte, trans:byte
extrn portval:word, port1:byte, port2:byte, swchar:byte
portin db 0
crlf db cr,lf,'$'
machnam db 'FIELD TEST Wang$'
noimp db cr,lf,'Command not implemented.$'
shkmsg db 'Not implemented.'
shklen equ $-shkmsg
xofsnt db 0 ; Say if we sent an XOFF.
xofrcv db 0 ; Say if we received an XOFF.
setktab db 0
setkhlp db 0
invseq db esc,'[7m$' ; Reverse video on.
nrmseq db esc,'[0m$' ; Reverse video off.
ivlseq db 79 dup (' '),cr,'$' ; Make a line inverse video
comphlp db cr,lf,'1 (COM1) 2 (COM2)$'
delstr db BS,' ',BS,'$' ; Delete string.
clrlin db cr,esc,'[K$'
tmp db ?,'$'
temp dw 0
temp1 dw ? ; Temporary storage.
temp2 dw ? ; Temporary storage.
; Entries for choosing communications port. [19b]
comptab db 04H
db 01H,'1$'
dw 01H
db 01H,'2$'
dw 00H
db 04H,'COM1$'
dw 01H
db 04H,'COM2$'
dw 00H
; variables for serial interrupt handler
source db bufsiz DUP(?) ; Buffer for data from port.
bufout dw 0 ; buffer removal ptr
count dw 0 ; Number of chars in int buffer.
bufin dw 0 ; buffer insertion ptr
telflg db 0 ; Are we acting as a terminal. [16] [17c]
clreol db esc,'[0K$'
blank db esc,'[H',esc,'[J$'
movcur db esc,'['
colno db 20 dup (?)
ten db 10
prthnd dw 0
ourarg termarg <>
; must parallel baud rate defs in pcdefs.
baudtab db 0ffh ; 45.5 baud (not supported)
db 0 ; 50
db 1 ; 75
db 2 ; 110
db 3 ; 134.5
db 4 ; 150
db 5 ; 300
db 6 ; 600
db 7 ; 1200
db 8 ; 1800
db 9 ; 2000
db 10 ; 2400
db 12 ; 4800
db 14 ; 9600
db 15 ; 19.2k
db 0ffh ; 38.4k (ha)
nbaud equ $-baudtab
qid dw ?
prtcnt dw ?
trqid dw ?
tmqid dw ?
brflg db ?
datas ends
code segment public
extrn comnd:near, dopar:near, prserr:near
assume cs:code,ds:datas
DODISK PROC NEAR
mov ah,gcurdsk ; Current disk value to AL.
int dos
mov dl,al ; Put current disk in DL.
mov ah,seldsk ; Select current disk.
int dos ; Get number of drives in AL.
mov drives,al
ret
DODISK ENDP
; Clear the input buffer before sending a packet. [20e]
CLRBUF PROC NEAR
mov ah,ioctl
mov bx,auxfil
mov al,iordy
int dos
cmp al,0ffh
jne clrb1 ; not ready, keep going
mov ah,auxin
int dos
jmp clrbuf ; read char and keep going.
clrb1: mov count,0
mov ax,offset source
mov bufin,ax
mov bufout,ax
ret
CLRBUF ENDP
; Common routine to clear to end-of-line. [19a]
CLEARL PROC NEAR
mov dx,offset clreol
mov ah,prstr
int dos
ret
CLEARL ENDP
; This routine should set the baud rate for the current port but it
; is actually done in SERINI.
dobaud proc near
ret
dobaud endp
; Send a break out the current serial port. Returns normally.
sendbr: push dx
push ax
push cx
push ds ; preserve data segment
mov ax,cs
mov ds,ax ; handler is in code segment
mov al,settrp
mov bx,txrdy ; interrupt on transmitter empty
mov cx,0 ; interrupt immediately
mov dx,offset sendb1 ; handler routine
int wbios
pop ds
mov trqid,bx
push ds
mov ax,cs
mov ds,ax
mov al,settrp
mov bx,0 ; 10 ms timer
mov cx,21 ; after 21 times - approx 200 ms.
mov dx,offset sendb2 ; timer interrupt
int wbios
pop ds
mov tmqid,bx
mov brflg,1
mov dx,rcvcmd
in al,dx ; Read command register.
or al,brk+txen ; Set send-break bit.
mov dx,wrcmd ; Write command register.
out dx,al
pause: cmp brflg,0
jne pause ; while non-zero, keep going
mov al,clrtrp ; clear the trap
mov bx,trqid
int wbios
mov al,clrtrp
mov bx,tmqid
int wbios
pop cx
pop ax
pop dx
ret
sendb1 proc far
ret
sendb1 endp
sendb2 proc far
push ax
push ds
mov ax,seg datas
mov ds,ax
mov brflg,0
mov dx,rcvcmd
in al,dx
and al,not (txen + brk)
mov dx,wrcmd
out dx,al
pop ds
pop ax
ret
sendb2 endp
; Write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $. Returns normally.
putmod proc near
push dx ; preserve message
mov dx,24 * 100H ; line 24
call poscur
mov dx,offset invseq ; put into inverse video
mov ah,prstr
int dos
pop dx
int dos
mov dx,offset nrmseq ; normal videw
int dos
ret ; and return
putmod endp
; Clear the mode line written by putmod. Returns normally.
clrmod proc near
mov dx,24 * 100H
call poscur
call clearl
ret
clrmod endp
; Put a help message one the screen in reverse video. Pass
; the message in AX, terminated by a null. Returns normally.
; The message is put wherever the cursor currently is located.
puthlp proc near
push ax
mov ah,prstr ; Leave some room before the message.
mov dx,offset crlf
int dos
mov dx,offset invseq ; Put into reverse video.
int dos
pop si ; Put message address here.
puth0: mov ah,prstr
mov dx,offset ivlseq ; Make line inverse video
int dos
puth1: lodsb
cmp al,0 ; Terminated with a null.
je puth2
mov dl,al
mov ah,conout
int dos
cmp al,lf ; Line feed?
je puth0 ; Yes, clear the next line.
jmp puth1 ; Else, just keep on writing.
puth2: mov dx,offset nrmseq ; Normal video.
mov ah,prstr
int dos
mov dx,offset crlf
int dos
ret
puthlp endp
outchr: push dx ; Save register.
mov al,ah
call dopar
mov dl,al
mov ah,auxout
int dos
pop dx
jmp rskp
; This routine blanks the screen.
CMBLNK PROC NEAR
mov ah,prstr
mov dx,offset blank
int dos
ret
CMBLNK ENDP
LOCATE PROC NEAR
mov dx,0 ; Go to top left corner of screen.
jmp poscur ; callret...
LOCATE ENDP
GETBAUD PROC NEAR
cld
mov dx,rcvmod
in al,dx
in al,dx ; get second mode word
and al,0fh ; isolate baud rate
mov cx,nbaud
mov di,offset baudtab
mov bx,ds
mov es,bx ; address correct segment
mov bx,portval
repne scasb ; look for baud rate
jne getb1 ; mystery baud rate...
sub di,offset baudtab + 1
mov [bx].baud,di ; store baud rate in comm area
ret ; and return
getb1: mov [bx].baud,-1 ; unknown baud rate
ret
GETBAUD ENDP
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR PROC NEAR
prtchx: cmp count,0
je prtch4 ; empty buffer, forget it.
mov si,bufout
lodsb
cmp si,offset source + bufsiz
jb prtch1
mov si,offset source
prtch1: mov bufout,si
dec count
push bx
mov bx,portval
cmp [bx].parflg,PARNON ; no parity?
je prtch3 ; then don't strip
and al,7fh ; else turn off parity
prtch3: mov dx,count ; chars left in buffer
pop bx
ret
prtch4: jmp rskp ; no chars...
PRTCHR ENDP
; Position the cursor according to contents of DX.
POSCUR PROC NEAR
mov ax,ds
mov es,ax ; address data segment!!!
cld
mov di,offset colno
mov al,dh ; row
inc al
call nout
mov al,';'
stosb
mov al,dl ; col
inc al
call nout
mov al,'H'
stosb
mov al,'$'
stosb
mov dx,offset movcur
mov ah,prstr
int dos ; print the sequence
ret
POSCUR ENDP
NOUT PROC NEAR
cbw ; extend to word
div byte ptr ten ; divide by 10
or al,al ; any quotient?
jz nout1 ; no, forget this
push ax ; save current result
call nout ; output high order
pop ax ; restore
nout1: mov al,ah ; get digit
add al,'0' ; make printable
stosb
ret ; put in buffer and return
NOUT endp
; Perform a delete.
DODEL PROC NEAR
mov ah,prstr
mov dx,offset delstr ; Erase weird character.
int dos
ret
DODEL ENDP
; Perform a Control-U.
CTLU PROC NEAR
mov ah,prstr
mov dx,offset clrlin
int dos
ret
CTLU ENDP
COMS PROC NEAR
mov dx,offset comptab
mov bx,offset comphlp
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp comx ; Didn't get a confirm.
nop
pop bx
mov flags.comflg,bl ; Set the comm port flag.
cmp flags.comflg,1 ; Using Com 1?
jne coms0 ; Nope.
mov ax,offset port1
mov portval,ax
ret
coms0: mov ax,offset port2
mov portval,ax
ret
comx: pop bx
ret
COMS ENDP
VTS PROC NEAR
jmp notimp
VTS ENDP
notimp: mov ah,prstr
mov dx,offset noimp
int dos
jmp prserr
lclini: mov trans.escchr,ctrla ; Use Control-A as escape char.
mov swchar,'/'
ret
showkey:
mov ax,offset shkmsg
mov cx,shklen
ret
; Common initialization for using serial port.
SERINI PROC NEAR
cmp portin,0 ; already inited?
jne serin1 ; yes, skip it
mov portin,1 ; remember inited
mov dx,rcvcmd
in al,dx ; read cmd register to reset mode ptr.
mov dx,trmod
mov al,mod1
out dx,al
push bx
mov bx,portval
mov si,[bx].baud
pop bx
mov al,baudtab[si]
or al,mod2
out dx,al
mov dx,wrcmd
mov al,txen+dtr+rxen+clrerr+rts
out dx,al ; enable transmit and receive
call clrbuf ; empty buffer
mov al,settrp
mov bx,chrrdy ; interrupt on character ready
mov cx,0 ; interrupt immediately
mov dx,offset serint ; handler routine
mov prtcnt,0 ; no characters in yet
push ds
mov si,cs
mov ds,si
int wbios
pop ds
or al,al
jne serin1
mov qid,bx ; preserve trap identification
serin1: ret ; We're done. [21c]
SERINI ENDP
SERRST PROC NEAR
cmp portin,0 ; already de-inited?
je serrs1 ; yes, skip this
mov portin,0
mov al,clrtrp
mov bx,qid
int wbios
serrs1: ret
SERRST ENDP
; serial interrupt handler
serint proc far
push ds
push ax
push dx
push di
mov ax,seg datas
mov ds,ax
mov di,bufin
mov dx,rcvdat
in al,dx
mov [di],al
inc di
cmp di,offset source + bufsiz
jb sernt1
mov di,offset source
sernt1: mov bufin,di
inc count
pop di
pop dx
pop ax
pop ds
ret
serint endp
; Generate a short beep.
BEEP PROC NEAR
mov dl,bell
mov ah,conout
int dos
ret
BEEP ENDP
; 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
term proc near
mov si,ax ; this is source
mov di,offset ourarg ; place to store arguments
mov ax,ds
mov es,ax ; address destination segment
mov cx,size termarg
rep movsb ; copy into our arg blk
term1: call prtchr
jmp short term2 ; have a char...
nop
nop
jmp short term3 ; no char, go on
term2: and al,7fh
push ax
mov dl,al
mov ah,dconio
int dos ; write out the character
pop ax
test ourarg.flgs,capt ; capturing output?
jz term3 ; no, forget it
call ourarg.captr ; else call the routine
term3: mov ah,dconio
mov dl,0ffh
int dos
or al,al
jz term1 ; no character, go on
cmp al,ourarg.escc ; escape char?
je term4 ; yes, exit
push ax ; save char
mov ah,al
call outchr ; output the character
nop
nop
nop
pop ax
test ourarg.flgs,lclecho ; echoing?
jz term1 ; no, continue loop
mov dl,al
mov ah,dconio
int dos
jmp term1 ; else echo and keep going
term4: ret
term endp
code ends
end
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxwng.asm
/bin/echo -n ' '; /bin/ls -ld msxwng.asm
fi
/bin/echo 'Extracting msxz100.asm'
sed 's/^X//' <<'//go.sysin dd *' >msxz100.asm
; Kermit system dependent module for Heath/Zenith Z100
public serini, serrst, clrbuf, outchr, coms, vts, dodel,
public ctlu, cmblnk, locate, prtchr, dobaud, clearl,
public dodisk, getbaud, beep,
public count, xofsnt, puthlp, putmod, clrmod, poscur
public sendbr, machnam, setktab, setkhlp, lclini, showkey
include msdefs.h
false equ 0
true equ 1
mntrgh equ bufsiz*3/4 ; High point = 3/4 of buffer full.
; constants used by serial port handler
BRKBIT EQU 048H ; Send-break bit.
MDMCOM1 EQU 00EFH ; Address of modem port command. [19b]
; external variables used:
; drives - # of disk drives on system
; flags - global flags as per flginfo structure defined in pcdefs
; trans - global transmission parameters, trinfo struct defined in pcdefs
; portval - pointer to current portinfo structure (currently either port1
; or port2)
; port1, port2 - portinfo structures for the corresponding ports
; global variables defined in this module:
; xofsnt, xofrcv - tell whether we saw or sent an xoff.
; setktab - keyword table for redefining keys (should contain a 0 if
; not implemented)
; setkhlp - help for setktab.
BIOS_SEG SEGMENT AT 40H ; Define segment where BIOS really is
ORG 6*3
BIOS_AUXOUT LABEL FAR ; AUX output routine
ORG 26*3
BIOS_AUXFUNC LABEL FAR ; AUX: function
ORG 27*3
BIOS_CONFUNC LABEL FAR ; CON: function
BIOS_SEG ENDS
; Function codes for BIOS_xxxFUNC
CHR_WRITE EQU 0 ; Write character
CHR_READ EQU 1 ; Read character
CHR_STATUS EQU 2 ; Get status
CHR_SFGS EQU 0 ; Get status subfunction
CHR_SFGC EQU 1 ; Get config subfunction
CHR_CONTROL EQU 3 ; Control function
CHR_CFSU EQU 0 ; Set new configuration parameters
CHR_CFCI EQU 1 ; Clear input buffer
datas segment public 'datas'
extrn drives:byte, flags:byte, trans:byte
extrn portval:word, port1:byte, port2:byte
setktab db 13
mkeyw 'F0',96h
mkeyw 'F1',97h
mkeyw 'F2',98h
mkeyw 'F3',99h
mkeyw 'F4',9ah
mkeyw 'F5',9bh
mkeyw 'F6',9ch
mkeyw 'F7',9dh
mkeyw 'F8',9eh
mkeyw 'F9',9fh
mkeyw 'F10',0a0h
mkeyw 'F11',0a1h
mkeyw 'SCAN',-1
setkhlp db cr,lf,'Keyname: f0, ... f11, "HELP" or "SCAN" follwed by '
db 'decimal scan code$'
brkval db 0 ; What to send for a break.
brkadr dw 0 ; Where to send it.
badbd db cr,lf,'Unimplemented baud rate$'
noimp db cr,lf,'Not implemented$'
machnam db 'Heath-Zenith Z-100$'
crlf db cr,lf,'$'
delstr db BS,' ',BS,'$' ; Delete string. [21d]
home db ESC,'H$'
eeolstr db ESC,'K$' ; Erase to end of line
clrstr db ESC,'E$' ; Erase entire display
enamod db ESC,'x1$' ; Enable 25th line
dismod db ESC,'y1$' ; Disable 25th line
enascan db ESC,'y?$' ; Enable scan codes
disscan db ESC,'x?$' ; Disable scan codes
begrev db ESC,'p$' ; Enter reverse video
endrev db ESC,'q$' ; Exit reverse video
lin25 db ESC,'Y8 $' ; Column 1 row 25
savcur db ESC,'j$' ; Save current cursor position
precur db ESC,'k$' ; Restore cursor to previous position
clrlin db cr,'$' ; Clear line (just the cr part).
xofsnt db 0 ; Say if we sent an XOFF.
xofrcv db 0 ; Say if we received an XOFF.
tmp db ?,'$'
temp1 dw ? ; Temporary storage.
ontab db 02H ; Two entries.
db 03H,'OFF$' ; Should be alphabetized. [19a]
dw 00H
db 02H,'ON$'
dw 01H
; this table is indexed by the baud rate definitions given in
; pcdefs. Unsupported baud rates should contain FF.
bddat label word
dw 0 ; 45.5 baud
dw 1 ; 50 baud
dw 2 ; 75 baud
dw 3 ; 110 baud
dw 4 ; 134.5 baud
dw 5 ; 150 baud
dw 6 ; 300 baud
dw 7 ; 600 baud
dw 8 ; 1200 baud
dw 9 ; 1800 baud
dw 10 ; 2000 baud
dw 11 ; 2400 baud
dw 12 ; 4800 baud
dw 13 ; 9600 baud
dw 14 ; 19200 baud
dw 15 ; 38400 baud
; storage for port configuration
cfginfo struc
cfclass db 0
cfattr db 0
cfport dw 0
cfbaud db 0
cfhshk db 0
cfbctl db 0
cfecnt db 0
cfncnt db 0
cfnchr db 0
cfres db 6 dup(?)
cfsize db 0
cfginfo ends
auxconf cfginfo <>
; variables for serial interrupt handler
count dw 0 ; Number of chars in int buffer.
ourarg termarg <>
shkbuf db 300 dup (?) ; room for definition
shkmsg db ' Scan code: '
shkmln equ $-shkmsg
shkms1 db cr,lf,' Definition: '
shkm1ln equ $-shkms1
datas ends
code segment public
extrn comnd:near, dopar:near, defkey:near
assume cs:code,ds:datas
; local initialization
lclini proc near
mov brkval,BRKBIT ; What to send for a break.
mov brkadr,MDMCOM1
mov flags.vtflg,0 ; Turn off true Heath mode (allows key macros)
ret
lclini endp
; this is called by Kermit initialization. It checks the
; number of disks on the system, sets the drives variable
; appropriately. Returns normally.
DODISK PROC NEAR
mov ah,gcurdsk ; Current disk value to AL.
int dos
mov dl,al ; Put current disk in DL.
mov ah,seldsk ; Select current disk.
int dos
mov drives,al
ret
DODISK ENDP
; show the definition of a key. The terminal argument block (which contains
; the address and length of the definition tables) is passed in ax.
; Returns a string to print in AX, length of same in CX.
; Returns normally.
showkey proc near
push es
push ax ; save the ptr
mov bx,ds
mov es,bx ; address data segment
cld
showk1: mov ah,prstr
mov dx,offset enascan ; enable scan codes
int dos
mov ah,0ch ; char input with buffer flush
mov al,7
int dos
; mov ah,chr_control
; mov al,chr_cfci ; clear input
; call bios_confunc
; mov ah,chr_read
; call bios_confunc ; read a char
push ax
mov ah,prstr
mov dx,offset disscan ; disable scan codes
int dos
pop ax
; push ax ; save the character
; call gss ; get shift state
; pop bx
mov ah,0 ; shift state to ah
; mov al,bh ; scan code to al
push ax ; remember scan code
mov di,offset shkbuf
mov si,offset shkmsg
mov cx,shkmln
rep movsb ; copy in initial message
call nout ; write out scan code
mov si,offset shkms1
mov cx,shkm1ln ; second message
rep movsb
pop ax ; get scan code back
pop bx ; and terminal arg block
mov cx,[bx].klen ; and length
jcxz showk2 ; no table, not defined
push di ; remember output ptr
mov di,[bx].ktab ; get key table
repne scasw ; search for a definition for this
mov si,di ; remember result ptr
pop di ; get output ptr back
jne showk2 ; not defined, forget it
sub si,[bx].ktab ; compute offset from beginning
sub si,2 ; minus 2 for pre-increment
add si,[bx].krpl ; get index into replacement table
mov si,[si] ; pick up replacement
mov cl,[si] ; get length
mov ch,0
inc si
rep movsb ; copy into buffer
showk2: mov ax,offset shkbuf ; this is buffer
mov cx,di
sub cx,ax ; length
pop es
ret ; and return
showkey endp
; Clear the input buffer. This throws away all the characters in the
; serial interrupt buffer. This is particularly important when
; talking to servers, since NAKs can accumulate in the buffer.
; Returns normally.
CLRBUF PROC NEAR
cli
mov ah,chr_control
mov al,chr_cfci
call bios_auxfunc
mov count,0
sti
ret
CLRBUF ENDP
; Clear to the end of the current line. Returns normally.
CLEARL PROC NEAR
mov ah,prstr
mov dx,offset eeolstr ; Erase to end of line
int dos
ret
CLEARL ENDP
; Put the char in AH to the serial port. This assumes the
; port has been initialized. Should honor xon/xoff. Skip returns on
; success, returns normally if the character cannot be written.
outchr: mov bp,portval
cmp ds:[bp].floflg,0 ; Are we doing flow control.
je outch2 ; No, just continue.
xor cx,cx ; clear counter
outch1: cmp xofrcv,true ; Are we being held?
jne outch2 ; No - it's OK to go on.
loop outch1 ; held, try for a while
mov xofrcv,false ; timed out, force it off and fall thru.
outch2: push dx ; Save register.
mov al,ah ; Parity routine works on AL.
call dopar ; Set parity appropriately.
call bios_auxout
pop dx
jmp rskp
; This routine blanks the screen. Returns normally.
CMBLNK PROC NEAR
mov ah,prstr
mov dx,offset clrstr
int dos
ret
CMBLNK ENDP
; Locate: homes the cursor. Returns normally.
LOCATE PROC NEAR
mov ah,prstr
mov dx,offset home ; Go to top left corner of screen.
int dos
LOCATE ENDP
; write a line in inverse video at the bottom of the screen...
; the line is passed in dx, terminated by a $. Returns normally.
putmod proc near
push dx ; preserve message
mov ah,prstr
mov dx,offset savcur
int dos
mov dx,offset enamod
int dos
mov dx,offset lin25
int dos
mov dx,offset begrev
int dos
pop dx ; get message back
int dos ; write it out
mov dx,offset endrev
int dos
mov dx,offset precur
int dos
ret ; and return
putmod endp
; clear the mode line written by putmod. Returns normally.
clrmod proc near
mov ah,prstr
mov dx,offset dismod
int dos
ret
clrmod endp
BEEP PROC NEAR
mov dl,07 ; ASCII BEL
mov ah,dconio
int dos ; Ring it
ret
BEEP ENDP
; put a help message on the screen. This one uses reverse video...
; pass the message in ax, terminated by a null. Returns normally.
puthlp proc near
push ax ; preserve this
mov ah,prstr
mov dx,offset crlf
int dos
pop si ; point to string again
puthl3: lodsb ; get a byte
cmp al,0 ; end of string?
je puthl4 ; yes, stop
mov dl,al
mov ah,dconio
int dos
jmp puthl3 ; and keep going
puthl4: mov ah,prstr
mov dx,offset crlf
int dos
ret
puthlp endp
; Set the baud rate for the current port, based on the value
; in the portinfo structure. Returns normally.
DOBAUD PROC NEAR
mov bp,portval
mov temp1,ax ; Don't overwrite previous rate. [25]
mov ax,ds:[bp].baud ; Check if new rate is valid. [25]
mov tmp,2
mul tmp ; Get index into baud table.
mov bx,offset bddat ; Start of table.
add bx,ax
mov ax,[bx] ; The data to output to port.
cmp ax,0FFH ; Unimplemented baud rate.
jne dobd0
mov ax,temp1 ; Get back orginal value.
mov ds:[bp].baud,ax ; Leave baud rate as is.
mov ah,prstr
mov dx,offset badbd ; Give an error message.
int dos
ret
dobd0: push ax ; Save it
mov bx,ds ; Set up pointer to config info
mov es,bx ; . . .
mov bx,offset auxconf ; . . .
mov ah,chr_status
mov al,chr_sfgc ; get current config info
call bios_auxfunc
pop ax ; get baud back
mov auxconf.cfbaud,al
mov ah,chr_control ; Function is control
mov al,chr_cfsu ; Subfunction is set new config
call bios_auxfunc ; Set the configuration
ret
DOBAUD ENDP
; Get the current baud rate from the serial card and set it
; in the portinfo structure for the current port. Returns normally.
; This is used during initialization.
GETBAUD PROC NEAR
mov bx,ds
mov es,bx
mov bx,offset auxconf
mov ah,chr_status
mov al,chr_sfgc ; Status function get config info
call bios_auxfunc
mov ch,0
mov cl,auxconf.cfbaud
mov bp,portval
mov ds:[bp].baud,cx
ret
GETBAUD ENDP
; skip returns if no character available at port,
; otherwise returns with char in al, # of chars in buffer in dx.
PRTCHR PROC NEAR
call chkxon ; see if we need to xon
push bx
mov ah,chr_status
mov al,chr_sfgs ; Status function get status
call bios_auxfunc
cmp bl,0
jnz prtch2
pop bx
jmp rskp ; No data - check console.
prtch2: mov dh,0
mov dl,bl ; Place # of chars in dx
mov ah,chr_read
call bios_auxfunc
dec dl ; Decrement number of chars
mov count,dx ; Save count for posterity
pop bx
ret
PRTCHR ENDP
; local routine to see if we have to transmit an xon
chkxon proc near
push bx
mov bx,portval
cmp [bx].floflg,0 ; doing flow control?
je chkxo1 ; no, skip all this
cmp xofsnt,false ; have we sent an xoff?
je chkxo1 ; no, forget it
cmp count,mntrgh ; below trigger?
jae chkxo1 ; no, forget it
mov ax,[bx].flowc ; ah gets xon
call outchr ; send it
nop
nop
nop ; in case it skips
mov xofsnt,false ; remember we've sent the xon.
chkxo1: pop bx ; restore register
ret ; and return
chkxon endp
; Send a break out the current serial port. Returns normally.
SENDBR PROC NEAR
push cx
push dx
push ax
xor cx,cx ; Clear loop counter.
mov dx,brkadr ; Port address. [19b]
in al,dx ; Get current setting.
or al,brkval ; Set send-break bit(s).
out dx,al ; Start the break.
pause: loop pause ; Wait a while.
xor al,brkval ; Clear send-break bit(s).
out dx,al ; Stop the break.
pop ax
pop dx
pop cx
ret ; And return.
SENDBR ENDP
; Position the cursor according to contents of DX:
; DH contains row, DL contains column. Returns normally.
POSCUR PROC NEAR
push dx
mov ah,CONOUT
mov dl,ESC
int dos
mov dl,'Y'
int dos
pop dx
push dx
mov dl,dh
add dl,' '
int dos
pop dx
add dl,' '
int dos
ret
POSCUR ENDP
; Delete a character from the terminal. This works by printing
; backspaces and spaces. Returns normally.
DODEL PROC NEAR
mov ah,prstr
mov dx,offset delstr ; Erase weird character.
int dos
ret
DODEL ENDP
; Move the cursor to the left margin, then clear to end of line.
; Returns normally.
CTLU PROC NEAR
mov ah,prstr
mov dx,offset clrlin
int dos
call clearl
ret
CTLU ENDP
; set the current port.
COMS PROC NEAR
jmp notimp
COMS ENDP
; Set heath emulation on/off.
VTS PROC NEAR
mov dx,offset ontab
mov bx,0
mov ah,cmkey
call comnd
jmp r
push bx
mov ah,cmcfm
call comnd ; Get a confirm.
jmp vt0 ; didn't get a confirm.
nop
pop bx
mov flags.vtflg,bl ; Set the Heath emulation flag
ret
vt0: pop bx
ret
VTS ENDP
notimp: mov ah,prstr
mov dx,offset noimp
int dos
jmp rskp
; initialization for using serial port. This routine performs
; any initialization necessary for using the serial port, including
; setting up interrupt routines, setting buffer pointers, etc.
; Doing this twice in a row should be harmless (this version checks
; a flag and returns if initialization has already been done).
; SERRST below should restore any interrupt vectors that this changes.
; Returns normally.
SERINI PROC NEAR
ret ; We're done.
SERINI ENDP
; Reset the serial port. This is the opposite of serini. Calling
; this twice without intervening calls to serini should be harmless.
; Returns normally.
SERRST PROC NEAR
ret ; All done.
SERRST ENDP
; put the number in ax into the buffer pointed to by di. Di is updated
nout proc near
mov dx,0 ; high order is always 0.
mov bx,10
div bx ; divide to get digit
push dx ; save remainder digit
or ax,ax ; test quotient
jz nout1 ; zero, no more of number
call nout ; else call for rest of number
nout1: pop ax ; get digit back
add al,'0' ; make printable
stosb ; drop it off
ret ; and return
nout endp
; 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
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msxz100.asm
/bin/echo -n ' '; /bin/ls -ld msxz100.asm
fi
/bin/echo 'Extracting msyibm.asm'
sed 's/^X//' <<'//go.sysin dd *' >msyibm.asm
title term
public term, gss ; entry points
include msdefs.h
; some character definitions
chesc equ 27
bel equ 7
print_out equ 05h ; dos function to print to printer
pbout equ 02h ; dos function to print a character
prscan equ 72h ; print-screen scan code...
upscan equ 49h ; up page
dnscan equ 51h ; down page
ctlup equ 84h ; ctl-up page
ctldn equ 76h ; ctl-down page
homscn equ 47h ; home screen
endscn equ 4fh ; end of screen
screen equ 10h ; bios screen call
kb equ 16h ; keyboard interrupt
alt_shift equ 8H ; alt shift key down
ctl_shift equ 4H ; ctl key down
left_shift equ 2H ; left shift key down
right_shift equ 1H ; right shift key down
timer equ 40h ; timer port
bel_prt equ 61h ; speaker control
crt_status equ 3dah ; crt status port
disp_enb equ 8 ; display enable bit
uparr equ 48h ; scan codes for arrow keys
dnarr equ 50h
lftarr equ 4bh
rgtarr equ 4dh
modfrm struc ; format of mode line
db 'Esc chr: '
m_echr db 2 dup (?)
db ', Port: '
m_prt db 1 dup (?)
db ', Speed: '
m_baud db 4 dup (?)
db ', Parity: '
m_par db 4 dup (?)
db ', Echo: '
m_echo db 3 dup (?)
db ', Type '
m_hlp db 2 dup (?)
db '? for Help'
modfrm ends
datas segment public 'datas'
waste db 100h dup (?) ;*** need this junk because assembler
;*** generates non-relocatable offsets
;*** for things like
;*** "sub di,offset foo"
;*** if offset foo < 100H
; stuff for screen routines
flags db ? ; status flags...
flags1 db 0 ; internal flags.
prtscr equ 80h ; print screen pressed
lnwrap equ 40h ; line wrap enabled.
inited equ 08h ; been here before...
cursor dw ?
esc_ch db ?
argadr dw ? ; address of arg blk
ckeys db 0,prscan,dnscan,upscan,endscn,homscn,ctlup,ctldn
db uparr,dnarr,lftarr,rgtarr
lckeys equ $-ckeys
; ckacts must parallel ckeys above...
ckacts dw trnbrk,trnprs,upwpg,dnwpg,endwnd,homwnd,dnwind,upwind
dw trnupw,trndnw,trnlfw,trnrgw
uptrn db esc,'A'
dntrn db esc,'B'
rgtrn db esc,'C'
lftrn db esc,'D'
spctab db chesc,cr,lf,bs,tab,bel
lspctab equ $-spctab
spcjmp dw outesc,outcr,outlf,outbs,outtab,outbel ; must match spctab
esctab db 'YABCDEFGHIJKLM'
db 'NOZ@[pq<vw'
lesctab equ $-esctab
; escjmp must parallel esctab above
escjmp dw movcur,curup,curdwn,currt,outbs,clrscr,outign,outign,curhom
dw revind,clreow,clreol,inslin,dellin,delchr,noins
dw vtident,entins,doansi
dw invvid,nrmvid,outign,dowrap,nowrap
vtidstr db chesc,'/K'
lvtidst equ $-vtidstr
coord dw ?
insmod db ?
wcoord dw ?
ttstate dw outtt0
curattr db ? ; current attribute
ansarg db ? ; ansi argument value
igncnt db ? ; # of chars to ignore
beldiv dw 2dch ; 550 hz?
crt_mode db ?
crt_cols db ?
crt_lins db ?
low_rgt dw ? ; lower right corner of window
; key redefinitions
ktrntab dw ? ; address of translation table
krpltab dw ? ; address of replacement table
tmptab db 0eh,3bh ; scan code for bs, f1
ktlen dw ?
modbuf modfrm <> ; mode line buffer
; routine to call for captured output
captrtn dw ?
; some static data for mode line
unkbaud db 'Unk ' ; must be 4 chars...
baudn db '45.5'
db ' 50'
db ' 75'
db ' 110'
db ' 135'
db ' 150'
db ' 300'
db ' 600'
db '1200'
db '1800'
db '2000'
db '2400'
db '4800'
db '9600'
baudnsiz equ 14 ; # of baud rates known (tbl size / 4)
parnams db 'Even'
db 'Mark'
db 'None'
db 'Odd ' ; must be 4 chars
db 'Spc '
offmsg db 'Off'
onmsg db 'On '
lclmsg db 'Lcl'
remmsg db 'Rem'
; storage for multi-window stuff
swidth equ 80
slen equ 24
npgs equ 5 ; # of pages on each side
bsize equ swidth*slen*npgs*2
scrsav dw swidth*slen dup (0700H) ; a blank screen
; circular buffer. To work properly, the buffer size should be an exact
; multiple of swidth*2
cbuf struc
pp dw ? ; place ptr in buffer
bend dw ? ; end of buffer
orig dw ? ; buffer origin
lcnt dw 0 ; # of lines in buffer.
cbuf ends
topbuf db bsize dup (?)
botbuf db bsize dup (?) ; top and bottom windows
tlbuf db swidth*2 dup (?)
blbuf db swidth*2 dup (?)
twnd cbuf <topbuf,topbuf+bsize-1,topbuf,0>
bwnd cbuf <botbuf,botbuf+bsize-1,botbuf,0>
portno db ?
prton db 'Printer: on'
prtnlen equ $-prton
prtoff db 'Printer: off'
prtflen equ $-prtoff
datas ends
code segment public ; code segment
extrn prtchr:near,outchr:near,sendbr:near
assume cs:code,ds:datas,es:datas
scrini proc near ; init screen stuff
mov ah,15 ; read video state...
int screen
mov crt_mode,al ; save crt mode
cmp ah,crt_cols ; is real # of cols < passed?
jge scrin1 ; no
mov crt_cols,ah ; yes, save # of cols
scrin1: mov dl,crt_cols ; # of cols again
mov dh,crt_lins ; and # of rows
dec dl
dec dh
mov low_rgt,dx ; save away window address
mov insmod,0 ; not in insert mode
mov dx,cursor ; assume old cursor
test flags1,inited ; have we been here before?
jnz scrin4 ; yes, use old cursor
mov curattr,07 ; else set nice screen attribute
mov ttstate,offset outtt0 ; normal screen state
mov ah,3 ; figure out where cursor is
xor bh,bh ; page 0
int screen ; read cursor position
cmp dh,crt_lins ; past logical end of screen?
jb scrin2 ; no, keep going
mov dh,byte ptr low_rgt+1 ; yes, just use lower right corner
scrin2: cmp dl,crt_cols ; maybe past right margin
jb scrin3 ; no, use the way it is
mov dl,byte ptr low_rgt
scrin3: mov cursor,dx ; init cursor
scrin4: mov ah,2
xor bh,bh
int screen ; set cursor in case it moved
ret
scrini endp
argini proc near ; read passed arguments
mov bx,argadr ; base of argument block
mov al,[bx].flgs ; get flags
and al,capt+emheath+havtt+trnctl+lclecho+modoff
mov flags,al ; mask for allowable and save
and flags1,not (prtscr) ; these are allowable
; (others remain).
mov al,[bx].prt
cmp al,portno ; using same port?
je argin1 ; yes, go on
and flags1,not inited ; else re-init stuff
argin1: mov portno,al ; update port number
mov al,[bx].cols
mov crt_cols,al
mov al,[bx].rows
mov crt_lins,al ; init # of rows and cols
mov ax,[bx].captr
mov captrtn,ax ; buffer capture routine
mov ax,[bx].belld
mov beldiv,ax ; bell divisor
mov ax,[bx].klen
mov ktlen,ax ; length of key redef tbl
mov ax,[bx].ktab
mov ktrntab,ax ; save key translation table
mov ax,[bx].krpl
mov krpltab,ax
mov al,[bx].escc
mov esc_ch,al
ret ; that's it
argini endp
modlin proc near ; turn on mode line
mov al,esc_ch
mov modbuf.m_echr,' ' ; first char is initial space
mov modbuf.m_hlp,' ' ; goes here too.
cmp al,32 ; printable?
jnb modl1 ; yes, keep going
add al,40h ; made printable
mov modbuf.m_echr,'^' ; note control char
mov modbuf.m_hlp,'^'
modl1: mov modbuf.m_echr+1,al ; fill in character
mov modbuf.m_hlp+1,al
mov bx,argadr ; get argument block
mov al,[bx].baudb ; get baud bits
mov si,offset unkbaud ; assume unknown baud
cmp al,baudnsiz ; too big?
jnb modl2 ; yes, use default
mov cl,2 ; each is 4 bytes long
shl al,cl
mov ah,0
add ax,offset baudn
mov si,ax
modl2: mov cx,size m_baud ; length of baud space
mov di,offset modbuf.m_baud
rep movsb ; copy in baud rate
mov al,[bx].parity ; get parity code
mov cl,2 ; each is 4 bytes long...
shl al,cl
mov ah,0
add ax,offset parnams ; names of parity settings
mov si,ax
mov cx,4 ; each is 4 long
mov di,offset modbuf.m_par
rep movsb
mov si,offset lclmsg ; assume remote echoing
test flags,lclecho ; echoing?
jz modl4 ; no, keep going
mov si,offset remmsg
modl4: mov cx,3 ; size of on/off
mov di,offset modbuf.m_echo
rep movsb
mov al,'1'
cmp portno,1 ; port 1?
je modl5 ; yes, keep going
mov al,'2'
modl5: mov modbuf.m_prt,al ; fill in port number
mov cx,size modfrm ; this is size of mode line
mov si,offset modbuf ; mode line image
; alternate entry to write an alternate mode line
modwrt: push cx
push si ; save mode line and size
mov dx,24 * 100h ; 25th line for mode line
push word ptr curattr ; save current attributes
mov curattr,70h ; want inverse video
call clreol ; clear to end of line...
pop word ptr curattr ; restore attributes
mov dx,24 * 100h
mov bh,0
mov ah,2 ; set cursor position
int screen
pop si
pop cx ; restore these
modl6: lodsb ; get a byte
mov ah,14 ; write to terminal
mov bh,0 ; page 0
int screen
loop modl6 ; write out entire mode line
mov dx,cursor
mov ah,2
mov bh,0
int screen ; put cursor back where it belongs
ret ; and return
modlin endp
clrmod proc near ; clear mode line
mov ax,600h ; blank window
mov cx,24 * 100h ; beginning of window
mov dx,24 * 100h + 79 ; end of window
mov bh,07 ; nice attribute
int screen ; clear mode line
ret ; and return
clrmod endp
term proc near ; terminal emulator entry point
mov argadr,ax ; save argument ptr
push es ; save caller's extra segment address
mov ax,seg datas
mov es,ax
call argini ; init options from arg address
call scrini ; init screen stuff
test flags1,inited ; have we run yet?
jz term1 ; no, forget this part
call restscr ; restore screen
term1: or flags1,inited ; remember we've run already.
call clrmod ; empty mode line
test flags,modoff ; is mode line disabled?
jnz lp ; yes, skip it
call modlin ; turn on mode line
lp: call portchr ; char at port?
jnc chkinp ; no, keep going
call outtty ; print on terminal
chkinp: mov ah,1
int kb
jz lp ; nothing available...
xor ah,ah
int kb ; get the char from the buffer
push ax ; save character temporarily
call gss ; get shift state into al
mov bl,al ; save shift state
pop ax
cmp al,esc_ch ; escape character?
je quit ; yes, stop here
call trnout ; translate if nec., output to prt
jmp chkinp ; and keep going
quit: call clrmod ; erase mode line
call savescr ; save screen
mov al,flags
mov bx,argadr
mov [bx].flgs,al ; update flags in arg block
pop es ; restore segment register
ret ; and return to caller
term endp
; get shift state into al. We only care about shift, ctl, and alt keys.
; right shift is collapsed into left shift.
gss proc near
mov ah,2
int kb ; get current shift state
mov bl,al ; copy for a moment
and bl,right_shift ; mask out all but right shift
shl bl,1 ; move right shift to left shift pos
or al,bl ; collapse shift bits
and al,(left_shift + alt_shift + ctl_shift)
ret
gss endp
; save the screen so we can restore it
; maybe save cursor also.
savescr proc near
push ds
mov si,0
mov di,offset scrsav ; place to put screen
mov cx,80*24 ; # of words on screen
call scrseg
push ax ; save screen segment
call scrwait ; wait for screen to be ready
pop ds ; address screen
rep movsw ; save the screen
pop ds ; restore this
ret ; and return
savescr endp
; restore screen from scrsav buffer
restscr proc near
push es
mov si,offset scrsav ; source
mov di,0
mov cx,80*24
call scrseg
mov es,ax
call scrwait
rep movsw ; restore it
pop es
ret
restscr endp
; send the character in al out to the serial port
; handle echoing also...
outprt proc near
test flags,lclecho ; echoing?
jz outpr1 ; no, forget it
push ax ; save char
call outtty ; print it
pop ax ; restore
outpr1: mov ah,al ; this is where outchr expects it
call outchr ; output to the port
nop
nop
nop ; skip returns...
ret
outprt endp
; returns with carry on if a character is available
portchr proc near
call prtchr ; character at port?
jmp short portc1 ; yes, go handle
nop ; skip return is stupid...
clc ; no carry -> no character
ret ; and return...
portc1: and al,7fh ; we don't worry about parity here
stc ; have a character
ret ; and return
portchr endp
; translate the scan code in ah according to the translate table
; given in ktrntab/krpltab, output to port. If no translation,
; use ascii char in al. (should probably include shift state
; somewhere). Shift state is in bl.
trnout proc near
cmp ah,4eh ;*** plus key thing?
je trnmod ; yes, go toggle mode line
trnou1: test flags,havtt ; translate table given?
jz trnou3 ; no, just output character
push ax ; save original value
mov al,ah ; put scan code into ah
mov ah,bl ; shift state into top half.
mov di,ktrntab ; pick up translate tbl
mov cx,ktlen ; length of tbl
repne scasw ; look for our key
pop ax ; recover character
jne trnou3 ; not found, forget it
sub di,ktrntab ; get index into tbl
sub di,2 ; (minus 2 for pre-increment)
mov bx,krpltab ; get replacement table
mov si,[bx][di] ; and addr of replacement
mov cl,[si] ; get first byte (length)
xor ch,ch ; clear high-order byte
inc si ; point to translation string
trnou2: lodsb ; get a byte
push si
push cx ; save important registers
call outprt ; send to port
pop cx
pop si
loop trnou2 ; send all chars
ret ; and return
trnou3: cmp al,0 ; is it a special code?
jne trnou4 ; no, don't do this
mov al,ah ; get scan code
mov cx,lckeys ; length of table
mov di,offset ckeys ; table address
repne scasb
mov al,0 ; ascii code was 0...
jne trnou4 ; not found, keep going
sub di,offset ckeys+1 ; get table offset
shl di,1 ; shift for word offset
jmp ckacts[di] ; jump to appropriate routine
trnou4: call outprt ; just output single char
ret ; and return
trnmod: test flags,modoff ; mode line already off?
jnz trnm1 ; yes, go turn on
call clrmod ; no, clear mode line here
or flags,modoff ; turn on flag
ret ; and return
trnm1: call modlin ; turn on mode line
and flags,not modoff ; clear flag
ret ; and return
trnbrk: mov ah,dconio
mov dl,0ffH
int dos ; read the bogus ^C DOS gets.
call sendbr
ret
trnprs: xor flags1,prtscr ; flip the flag
and flags,not modoff ; turn on mode line
mov si,offset prton
mov cx,prtnlen
test flags1,prtscr ; did it go on?
jnz trnpr1 ; yes, say so
mov si,offset prtoff
mov cx,prtflen
trnpr1: call modwrt ; write into mode line
ret ; and return
; common entry for arrow keys
trnarr: mov cx,2 ; length is always 2
jmp trnou2 ; go send definition
trnupw: mov si,offset uptrn
jmp trnarr
trndnw: mov si,offset dntrn
jmp trnarr
trnlfw: mov si,offset lftrn
jmp trnarr
trnrgw: mov si,offset rgtrn
jmp trnarr
trnout endp
; move viewing window up (screen moves down).
; alternate entry upwin2 doesn't beep if invalid.
upwind proc near
mov ax,offset tlbuf ; place to put line temporarily
mov bx,offset twnd ; where to get lines from
call getcirc ; try to get a line
jnc upwin3 ; have a line, go show it
call outbel ; else ring bel
ret ; and return
upwin2: mov ax,offset tlbuf
mov bx,offset twnd
call getcirc
jnc upwin3
ret ; this just rets if no line avail.
upwin3: mov ax,offset blbuf ; place for bottom line
call getbot ; fetch bottom line
mov ax,offset blbuf
mov bx,offset bwnd
call putcirc ; save in circular buffer
mov ax,701h ; scroll down one line
xor cx,cx ; from top
mov dx,low_rgt ; to bottom
mov bh,curattr
int screen ; scroll it down
mov di,0 ; offset for destination
mov si,offset tlbuf ; where to get line from
mov cx,swidth ; length of line
push es
call scrseg
push ax
call scrwait
pop es
rep movsw ; copy the line in
pop es ; restore this
ret ; and return
upwind endp
; move viewing window down a line (screen scrolls up)
; entry dwin2 does same w/out checking to see if scroll is legal
dnwind proc near
mov ax,offset blbuf ; place to put line temporarily
mov bx,offset bwnd ; where to get lines from
call getcirc ; try to get a line
jnc dnwin3 ; have a line, go show it
call outbel ; else ring bel
ret ; and return
dnwin2: mov ax,offset blbuf
mov bx,offset bwnd
call getcirc
jnc dnwin3
ret ; this just rets if no line avail.
dnwin3: call scrprep ; save top line
mov ax,601h ; scroll up one line
xor cx,cx ; from top
mov dx,low_rgt ; to bottom
mov bh,curattr
int screen ; scroll it down
mov dx,low_rgt
mov dl,0 ; get addr of last line
call scrloc
mov di,ax ; this is offset in dest
mov si,offset blbuf ; where to get line from
mov cx,swidth ; length of line
push es
call scrseg
push ax
call scrwait
pop es
rep movsw ; copy the line in
pop es ; restore this
ret ; and return
dnwind endp
; move viewing window down as much as possible...
endwnd proc near
mov cx,1000 ; large number of lines
jmp dnwp1 ; and enter dwnpg
endwnd endp
; scroll viewing window down (contents move up) crt_lins times...
dnwpg proc near
mov cl,crt_lins
mov ch,0
dnwp1: push cx ; save this
call dnwin2
pop cx
loop dnwp1
ret ; and return
dnwpg endp
; home viewing window
homwnd proc near
mov cx,1000 ; large # of lines
jmp upwp1 ; join upwpg
homwnd endp
; scroll viewing window up (screen moves down) a page
upwpg proc near
mov cl,crt_lins
mov ch,0
upwp1: push cx
call upwin2
pop cx
loop upwp1
ret ; and return
upwpg endp
; get the bottom line into the buffer pointed to by ax.
getbot proc near
push ds
mov di,ax ; save dest
mov cx,swidth
mov dx,low_rgt
mov dl,0
call scrloc
mov si,ax
call scrseg
push ax
call scrwait
pop ds
rep movsw
pop ds
ret
getbot endp
; put a line into the circular buffer. Pass the buffer structure
; in bx, the pointer to the line in ax.
putcirc proc near
push si
push di
push cx
push dx
mov di,[bx].pp ; pick up buffer ptr
add di,2*swidth ; increment to next avail slot
cmp di,[bx].bend ; past end?
jb putci1 ; no, leave alone
mov di,[bx].orig ; else start at beginning
putci1: mov [bx].pp,di ; update ptr
mov si,ax ; this is source
mov cx,swidth
rep movsw ; copy into buffer
cmp [bx].lcnt,npgs*slen ; can we increment it?
jae putci2 ; no, keep going
inc [bx].lcnt ; else count this line
putci2: pop dx
pop cx
pop di
pop si ; restore registers
ret
putcirc endp
; get a line from the circular buffer, removing it from the buffer.
; returns with carry on if the buffer is empty.
; pass the buffer structure in bx, the buffer to copy the line into
; in ax.
getcirc proc near
push si
push di
push cx
push dx
cmp [bx].lcnt,0 ; any lines in buffer?
jne getci1 ; yes, ok to take one out.
stc ; else set carry
jmp short getcir3 ; and return
getci1: mov si,[bx].pp ; this is source
mov di,ax ; this is dest
mov cx,swidth ; # of chars to copy
rep movsw
mov si,[bx].pp ; get ptr again
sub si,2*swidth ; move back
cmp si,[bx].orig ; compare to origin
jae getcir2 ; still in range, continue
mov si,[bx].bend ; else use end of buffer
sub si,2*swidth-1 ; minus length of a piece
getcir2:mov [bx].pp,si ; update ptr
dec [bx].lcnt ; decrement # of lines in buffer
clc ; make sure no carry
getcir3:pop dx
pop cx
pop di
pop si
ret
getcirc endp
; call before scrolling to save top line...
scrprep proc near
push ds
mov si,0 ; offset of top line
mov cx,swidth ; length of line
mov di,offset tlbuf ; place to put line temporarily
call scrseg
push ax
call scrwait
pop ds
rep movsw ; copy the line
pop ds ; restore this
mov ax,offset tlbuf
mov bx,offset twnd ; this is where it goes
call putcirc ; put into buffer
ret ; and return
scrprep endp
; put the character in al to the screen
outtty proc near
test flags,capt ; capturing output?
jz outnoc ; no, forget this part
push ax ; save char
call captrtn ; give it captured character
pop ax ; restore character and keep going
outnoc: test flags1,prtscr ; should we be printing?
jz outnop ; no, keep going
push ax
mov ah,print_out
mov dl,al ; put character here for dos...
int dos
pop ax
outnop: test flags,emheath ; emulating heath?
jnz outnop1 ; yup, go do something smart
mov dl,al
mov ah,pbout
int dos ; else let dos print char
ret ; and return
outnop1:mov dx,cursor ; these may need cursor...
jmp ttstate ; jump according to current state
outtt0:
cmp al,32 ; special character?
jb outtt1 ; yes, handle specially...
cmp insmod,0 ; in insert mode?
je outnrm ; no, output normal
push ax ; save character
call inschr ; insert a character
pop ax
outnrm: xor bh,bh ; current page
mov cx,1 ; only one char
mov bl,curattr ; with current attribute
mov ah,9
int screen ; put onto screen
mov dx,cursor ; get cursor pos
currt: inc dl ; bump col
cmp dl,crt_cols ; see if in range
jb setcur ; in range, go set cursor
test flags1,lnwrap ; in wrap mode?
jz outign ; no, just return w/out updating cursor
xor dl,dl
inc dh ; handle wrap
setcur: cmp dh,crt_lins
jb setc1 ; not off end, keep going
push dx ; save row/col
call scrprep ; save top line in window buf
mov ax,0601h ; scroll up one line
xor cx,cx ; from 0,0
mov dx,low_rgt ; to 24,80
mov bh,curattr ; nice attribute
int screen ; do the scroll
pop dx
mov dh,crt_lins ; go to bottom line again...
dec dh
setc1: xor bh,bh ; page is 0
mov cursor,dx ; save cursor pos
mov ah,2
int screen ; set cursor
outign: ret ; and return
; special character (in al)
outtt1: mov di,offset spctab ; special char table
mov cx,lspctab ; length of tbl
repne scasb ; look for char in tbl
jz outtt2 ; found, go do something with it
test flags,trnctl ; are we allowed to print carets?
jz outign ; no, just ignore it.
push ax ; save char
mov al,'^'
call outtty ; print caret
pop ax
add al,'A'-1 ; make printable
jmp outtty ; print, then return
outtt2: mov dx,cursor ; might need cursor pos
sub di,offset spctab+1 ; get index of char
shl di,1 ; double for word offset
jmp spcjmp[di] ; and go handle
; special char routines. cursor is in dx, char in al
outlf: inc dh ; bump row
jmp setcur
outcr: xor dl,dl ; set col to 0
jmp setcur
outbs: or dl,dl
jle setcur ; col 0, can't back up
dec dl ; back up col
jmp setcur ; and use if reasonable
outtab: mov dl,byte ptr cursor ; get initial column
outta1: mov dh,dl ; save column ptr
push dx
mov al,' ' ; output a space
call outtty ; convenient, huh?
pop dx
mov dl,byte ptr cursor
cmp dh,dl ; is it moving?
je outta2 ; no, forget this
test dl,7 ; is it a multiple of 8?
jnz outta1 ; no, keep going
outta2: ret ; else return
; stolen from bios
outbel: mov al,10110110b ; timer initialization
out timer+3,al
mov ax,beldiv ; bel divisor
out timer+2,al
mov al,ah
out timer+2,al ; output divisor
in al,bel_prt
mov ah,al ; remember original value
or al,3 ; turn speaker on
out bel_prt,al
mov cx,8888h
outbe1: loop outbe1 ; wait a while
mov al,ah
out bel_prt,al ; turn bell off
ret ; and return
outesc: mov ttstate,offset escseq ; expect escape sequence.
ret ; and return
; escape-char handling routines
escseq: mov ttstate,offset outtt0 ; put state back to normal
mov di,offset esctab ; escape char tbl
mov cx,lesctab ; length of tbl
repne scasb ; look for it in tbl
jz escsq1 ; found, go use it
jmp outtty ; not there, just print it
escsq1: sub di,offset esctab+1 ; get offset into tbl
shl di,1 ; convert to word offset
jmp escjmp[di] ; and go dispatch on it
; escape dispatch routines
revind: cmp dh,0
jle revin1
dec dh ; back up a row
jmp setcur ; and go set cursor
revin1: push dx ; save cursor pos
mov ax,701h ; scroll down one line
xor cx,cx ; from top
mov dx,low_rgt ; to bottom
mov bh,curattr
int screen ; scroll it down
pop dx ; restore cursor.
mov dh,0 ; set row back to 0
jmp setcur
curup: cmp dh,0 ; w/in range?
jle curu1 ; no, skip this
dec dh ; else back up
curu1: jmp setcur ; and go set position
curdwn: inc dh
jmp setcur ; increment row (setcur can scroll!)
; currt is above
clrscr: call curhom ; go home cursor
jmp clreow ; then clear to end of window
curhom: xor dx,dx ; move to 0,0
jmp setcur
clreow: cmp dl,0 ; at beginning of line?
jz clrw1 ; yes, skip this part...
push dx ; remember cursor pos
call clreol ; clear to end of this line
pop dx
inc dh ; bump row
xor dl,dl ; start from col 0
clrw1: cmp dh,crt_lins ; last line on screen
jnb clrw2 ; if not in range, forget it
mov ax,700h ; clear whole window
mov cx,dx ; this is beginning
mov dx,low_rgt
; mov dx,174fh ; this is lower right corner
mov bh,curattr ; default attribute
int screen ; go clear it
clrw2: ret ; and return
clreol: push es
mov cl,crt_cols ; last col + 1
sub cl,dl ; this is # of chars to move
xor ch,ch
jcxz clrl1
call scrloc ; compute screen location (to ax)
mov di,ax
call scrseg
mov es,ax ; address screen segment
call scrwait ; wait for retrace
mov ah,curattr ; current attribute
mov al,' ' ; fill char
rep stosw ; fill line with spaces
clrl1: pop es
ret ; and return
inslin: mov al,1 ; scroll one line
; alternate entry if inserting more then one line
inslin1:mov ch,dh ; start at current row
xor cl,cl ; column 0
mov dx,low_rgt
; mov dx,174fh ; to bottom of screen
mov ah,7h ; scroll down.
mov bh,curattr ; attribute
int screen
ret
dellin: mov al,1 ; scroll 1 line
; alternate entry if deleting more than one line
dellin1:mov ch,dh ; start at current row
xor cl,cl ; column 0
mov dx,low_rgt
; mov dx,174fh ; to bottom of screen
mov ah,6h ; scroll up.
mov bh,curattr ; attribute
int screen
ret
delchr: push ds
push es
pushf ; these may get changed...
mov cl,crt_cols
dec cl
sub cl,dl ; from what we're fiddling)
xor ch,ch
jcxz delch1 ; none to move, forget it
call scrloc ; compute location
mov di,ax
mov si,ax
add si,2 ; source is next position over
call scrseg ; pick up screen segment
push ax ; put screen segment onto stack
mov es,ax ; and in destination segment
call scrwait ; wait for retrace
pop ds ; address screen segment
rep movsw ; delete it
mov byte ptr [di],' ' ; kill char at end of line
delch1: popf
pop es
pop ds
ret
inschr: push ds
push es ; save these as well
pushf ; might as well save flags...
mov dx,cursor ; this is place to do it
mov cl,crt_cols
dec cl
; mov cl,79 ; this is last col to move, +1 for length
sub cl,dl ; compute distance to end
xor ch,ch ; clear top half of offset
jcxz insch1 ; nothing to move...
mov dl,crt_cols
sub dl,2 ; last col to move
; mov dl,78 ; this is address of last col to move
call scrloc ; compute pos
mov si,ax
mov di,ax
add di,2 ; destination is one byte over...
std ; remember to move us backwards
call scrseg ; find screen segment
mov es,ax
push ax ; save screen seg on stack
call scrwait ; wait until save to write
pop ds ; address screen segment
rep movsw ; move each char and attribute
insch1: popf
pop es
pop ds
ret ; and return
noins: mov insmod,0 ; turn off insert mode
ret ; and return
movcur: mov wcoord,2 ; want two coordinates...
mov ttstate,offset getcoord
ret ; and return
vtident: mov si,offset vtidstr
mov cx,lvtidst
vtid1: lodsb ; get a byte from the string
push si ; have to save from outprt
push cx
call outprt ; send to serial port
pop cx
pop si
loop vtid1 ; go thru all chars
ret ; and return
entins: mov insmod,0ffh ; enter insert mode...
ret ; and return
doansi: mov ansarg,0 ; ansi argument is 0 (default)
mov ttstate,offset getaarg ; state is get ansi argument
ret
getaarg:cmp al,'0'
jb getaa1 ; in range for digit?
cmp al,'9'
ja getaa1
sub al,'0' ; convert to binary
mov dl,al ; tuck away
mov al,ansarg
mov dh,10
mul dh ; shift sum
add al,dl ; add in this digit (what about ovfl?)
mov ansarg,al
ret ; and return
getaa1: cmp al,'?' ; the dreaded question mark?
jne getaa2
mov ttstate,offset ignn ; we ignore these...
mov igncnt,2 ; this is how many chars come after him
ret
getaa2: mov ttstate,offset outtt0 ; reset state
mov dx,cursor ; this needs cursor position
mov bl,ansarg
xchg al,bl ; put argument in nice place
cmp bl,'L' ; insert line?
jne getaa3
jmp inslin1 ; and go do it
getaa3: cmp bl,'M' ; maybe delete line?
jne getaa4
jmp dellin1
getaa4: ret ; ignore.
invvid: mov curattr,70h ; attribute for inverse video
ret
nrmvid: mov curattr,07h ; attribute for normal video
ret
dowrap: or flags1,lnwrap ; turn on wrap mode
ret ; and return
nowrap: and flags1,not lnwrap ; turn off wrap mode
ret ; and return
; get a coordinate.
getcoord:
sub al,32 ; coordinates offset by 32
mov si,wcoord
dec si
mov byte ptr coord[si],al ; fill in appropriate coordinate
mov wcoord,si ; update flag
jnz getco1 ; more needed, can't do anything yet
mov ttstate,offset outtt0 ; reset state
mov dx,coord ; get coordinates
jmp setcur ; and go jump there
getco1: ret
; ignore following igncnt characters
ignn: dec igncnt ; decrement count
jnz ignn1
mov ttstate,offset outtt0 ; put state back to normal if done
ignn1: ret
outtty endp
; computes screen location to ax, given row and col in dx.
; trashes ax,bx
scrloc proc near
mov al,dh ; get row
mov bl,crt_cols ;** row size
mul bl ; multiply by row size
xor dh,dh ; clear col
add ax,dx ; this is current position
sal ax,1 ; double for attributes
ret
scrloc endp
; puts current screen segment in ax
scrseg proc near
mov ax,0b000h ; assume bw for now
cmp crt_mode,7 ; 7 is bw (***)
je scrse1
mov ax,0b800h ; color card
scrse1: ret
scrseg endp
; wait for retrace so can write to screen memory
scrwait proc near
cmp crt_mode,7 ; bw mode?
je scrwa3 ; yes, no waiting
push dx
mov dx,crt_status
scrwa1: in al,dx
test al,disp_enb ; display enable?
jnz scrwa1 ; yes, keep waiting
scrwa2: in al,dx
test al,disp_enb ; now wait for it to go off
jz scrwa2 ; so can have whole cycle
pop dx
scrwa3: ret ; that was easy...
scrwait endp
code ends
if1
%out [End of pass 1]
else
%out [End of assembly]
endif
end
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msyibm.asm
/bin/echo -n ' '; /bin/ls -ld msyibm.asm
fi
/bin/echo 'Extracting msyz100.asm'
sed 's/^X//' <<'//go.sysin dd *' >msyz100.asm
; Kermit system dependent module for Heath/Zenith Z100
public term
include msdefs.h
BIOS_SEG SEGMENT AT 40H ; Define segment where BIOS really is
ORG 4*3
BIOS_PRINT LABEL FAR ; Printer output
ORG 6*3
BIOS_AUXOUT LABEL FAR ; AUX output routine
ORG 26*3
BIOS_AUXFUNC LABEL FAR ; AUX: function
ORG 27*3
BIOS_CONFUNC LABEL FAR ; CON: function
BIOS_SEG ENDS
; Function codes for BIOS_xxxFUNC
CHR_WRITE EQU 0 ; Write character
CHR_READ EQU 1 ; Read character
CHR_STATUS EQU 2 ; Get status
CHR_SFGS EQU 0 ; Get status subfunction
CHR_SFGC EQU 1 ; Get config subfunction
CHR_CONTROL EQU 3 ; Control function
CHR_CFSU EQU 0 ; Set new configuration parameters
CHR_CFCI EQU 1 ; Clear input buffer
; Scan code definitions used for translating back to Heath ESC sequences
entscan equ 08dh ; enter key scan code
f0scan equ 096h ; F0 key
f1scan equ 097h ; F1 key
f2scan equ 098h ; F2 key
f3scan equ 099h ; F3 key
f4scan equ 09ah ; F4 key
f5scan equ 09bh ; F5 key
f6scan equ 09ch ; F6 key
f7scan equ 09dh ; F7 key
f8scan equ 09eh ; F8 key
f9scan equ 09fh ; F9 key
f10scn equ 0a0h ; F10 key
f11scn equ 0a1h ; F11 key
f12scn equ 0a2h ; F12 key
homscan equ 0a9h ; Home key
upscan equ 0a5h ; Up arrow
dnscan equ 0a6h ; Down arrow
rtscan equ 0a7h ; Right arrow
lfscan equ 0a8h ; Left arrow
kpminus equ 0adh ; keypad minus
kpdot equ 0aeh ; keypad period
kp0 equ 0b0h ; keypad 0
kp1 equ 0b1h ; keypad 1
kp2 equ 0b2h ; keypad 2
kp3 equ 0b3h ; keypad 3
kp4 equ 0b4h ; keypad 4
kp5 equ 0b5h ; keypad 5
kp6 equ 0b6h ; keypad 6
kp7 equ 0b7h ; keypad 7
kp8 equ 0b8h ; keypad 8
kp9 equ 0b9h ; keypad 9
sentscn equ 0cdh ; shifted enter key
sf0scan equ 0d6h ; shifted F0 key
sf1scan equ 0d7h ; shifted F1 key
sf2scan equ 0d8h ; shifted F2 key
sf3scan equ 0d9h ; shifted F3 key
sf4scan equ 0dah ; shifted F4 key
sf5scan equ 0dbh ; shifted F5 key
sf6scan equ 0dch ; shifted F6 key
sf7scan equ 0ddh ; shifted F7 key
sf8scan equ 0deh ; shifted F8 key
sf9scan equ 0dfh ; shifted F9 key
sf10scn equ 0e0h ; shifted F10 key
sf11scn equ 0e1h ; shifted F11 key
sf12scn equ 0e2h ; shifted F12 key
shomscn equ 0e9h ; shifted Home key
supscan equ 0e5h ; shifted Up arrow
sdnscan equ 0e6h ; shifted Down arrow
srtscan equ 0e7h ; shifted Right arrow
slfscan equ 0e8h ; shifted Left arrow
skpmins equ 0edh ; shifted keypad minus
skpdot equ 0eeh ; shifted keypad period
skp0 equ 0f0h ; shifted keypad 0
skp1 equ 0f1h ; shifted keypad 1
skp2 equ 0f2h ; shifted keypad 2
skp3 equ 0f3h ; shifted keypad 3
skp4 equ 0f4h ; shifted keypad 4
skp5 equ 0f5h ; shifted keypad 5
skp6 equ 0f6h ; shifted keypad 6
skp7 equ 0f7h ; shifted keypad 7
skp8 equ 0f8h ; shifted keypad 8
skp9 equ 0f9h ; shifted keypad 9
; Miscellaneous scan codes used for functions
prscan equ f12scn ; print-screen scan code (F12)...
brkscan equ 0aah ; Break key
modfrm struc ; format of mode line
db 'Esc chr: '
m_echr db 2 dup (?)
db ', Speed: '
m_baud db 4 dup (?)
db ', Parity: '
m_par db 4 dup (?)
db ', Echo: '
m_echo db 3 dup (?)
db ', Prn: '
m_prs db 3 dup (?)
db ', Type '
m_hlp db 2 dup (?)
db '? for Help$'
modfrm ends
datas segment public 'datas'
waste db 100h dup(?) ; assembler problem???
flags1 db 0 ; internal flags
prtscr equ 80h ; print screen pressed flag
; Key translations - F12 is printscreen
ckeys db brkscan,prscan,upscan,dnscan,lfscan,rtscan,homscan
db entscan,f0scan,f1scan,f2scan,f3scan,f4scan,f5scan,f6scan
db f7scan,f8scan,f9scan,f10scn,f11scn,kpminus
db kpdot,kp0,kp1,kp2,kp3,kp4,kp5,kp6,kp7,kp8,kp9
db supscan,sdnscan,slfscan,srtscan,shomscn
db sentscn,sf0scan,sf1scan,sf2scan,sf3scan,sf4scan,sf5scan,sf6scan
db sf7scan,sf8scan,sf9scan,sf10scn,sf11scn,skpmins
db skpdot,skp0,skp1,skp2,skp3,skp4,skp5,skp6,skp7,skp8,skp9
lckeys equ $-ckeys
;ckacts must parallel ckeys above...
ckacts dw trnbrk,trnprs,trnupw,trndnw,trnlfw,trnrgw,trnhom,trnkpn
dw trnf0,trnf1,trnf2,trnf3,trnf4,trnf5,trnf6,trnf7,trnf8,trnf9
dw trnf10,trnf11,trnkpn,trnkpn,trnkpn,trnkpn,trnkpn
dw trnkpn,trnkpn,trnkpn,trnkpn,trnkpn,trnkpn,trnkpn
dw trnupw,trndnw,trnlfw,trnrgw,trnhom,trnkps
dw trnsf0,trnsf1,trnsf2,trnsf3,trnsf4,trnsf5,trnsf6,trnsf7
dw trnsf8,trnsf9,trnsf10,trnsf11,trnkps,trnkps
dw trnkps,trnskp1,trnskp2,trnskp3,trnskp4,trnskp5,trnskp6
dw trnskp7,trnskp8,trnskp9
enascan db ESC,'y?$' ; Enable scan codes
disscan db ESC,'x?$' ; Disable scan codes
uptrn db esc,'A'
dntrn db esc,'B'
rgtrn db esc,'C'
lftrn db esc,'D'
enttrn db cr ; enter key translation
homtrn db ESC,'H' ; home key translation
dottrn db '.' ; keypad . translation
mintrn db '-' ; keypad - translation
kp0trn db '0' ; keypad 0 translation
kp1trn db '1' ; keypad 1 translation
kp2trn db '2' ; keypad 2 translation
kp3trn db '3' ; keypad 3 translation
kp4trn db '4' ; keypad 4 translation
kp5trn db '5' ; keypad 5 translation
kp6trn db '6' ; keypad 6 translation
kp7trn db '7' ; keypad 7 translation
kp8trn db '8' ; keypad 8 translation
kp9trn db '9' ; keypad 9 translation
senttrn db cr ; shifted enter key translation
shomtrn db ESC,'H' ; home key translation
sdottrn db '.' ; shifted keypad . translation
smintrn db '-' ; shifted keypad - translation
skp0trn db '0' ; shifted keypad 0 translation
skp1trn db ESC,'L' ; shifted keypad 1 translation
skp2trn db ESC,'B' ; shifted keypad 2 translation
skp3trn db ESC,'M' ; shifted keypad 3 translation
skp4trn db ESC,'D' ; shifted keypad 4 translation
skp5trn db ESC,'H' ; shifted keypad 5 translation
skp6trn db ESC,'C' ; shifted keypad 6 translation
skp7trn db ESC,'@' ; shifted keypad 7 translation
skp8trn db ESC,'A' ; shifted keypad 8 translation
skp9trn db ESC,'N' ; shifted keypad 9 translation
f0trn db ESC,'J' ; F0 translation
f1trn db ESC,'S' ; F1 translation
f2trn db ESC,'T' ; F2 translation
f3trn db ESC,'U' ; F3 translation
f4trn db ESC,'V' ; F4 translation
f5trn db ESC,'W' ; F5 translation
f6trn db ESC,'P' ; F6 translation
f7trn db ESC,'Q' ; F7 translation
f8trn db ESC,'R' ; F8 translation
f9trn db ESC,'0I' ; F9 translation
f10trn db ESC,'0J' ; F10 translation
f11trn db ESC,'0K' ; F11 translation
f12trn db ESC,'0L' ; F12 translation
sf0trn db ESC,'E' ; shifted F0 translation
sf1trn db ESC,'1A' ; shifted F1 translation
sf2trn db ESC,'1B' ; shifted F2 translation
sf3trn db ESC,'1C' ; shifted F3 translation
sf4trn db ESC,'1D' ; shifted F4 translation
sf5trn db ESC,'1E' ; shifted F5 translation
sf6trn db ESC,'1F' ; shifted F6 translation
sf7trn db ESC,'1G' ; shifted F7 translation
sf8trn db ESC,'1H' ; shifted F8 translation
sf9trn db ESC,'1I' ; shifted F9 translation
sf10trn db ESC,'1J' ; shifted F10 translation
sf11trn db ESC,'1K' ; shifted F11 translation
sf12trn db ESC,'1L' ; shifted F12 translation
ourarg termarg <>
modbuf modfrm <> ; mode line buffer
; some static data for mode line
unkbaud db 'Unk ' ; must be 4 chars...
baudn db '45.5'
db ' 50'
db ' 75'
db ' 110'
db ' 135'
db ' 150'
db ' 300'
db ' 600'
db '1200'
db '1800'
db '2000'
db '2400'
db '4800'
db '9600'
db ' 19K'
db ' 38K'
baudnsiz equ 16 ; # of baud rates known (tbl size / 4)
parnams db 'Even'
db 'Mark'
db 'None'
db 'Odd ' ; must be 4 chars
db 'Spc '
offmsg db 'Off'
onmsg db 'On '
lclmsg db 'Lcl'
remmsg db 'Rem'
datas ends
code segment public
extrn prtchr:near,outchr:near,putmod:near,clrmod:near,sendbr:near
assume cs:code,ds:datas
; This is from the dumb terminal emulator routine in MSXGEN.ASM.
; Had to use bios calls because DOS calls were losing chars.
term proc near
mov si,ax ; this is source
mov di,offset ourarg ; place to store arguments
mov ax,ds
push es ; save caller's extra segment address
mov es,ax ; address destination segment
mov cx,size termarg
rep movsb ; copy into our arg blk
and flags1,not (prtscr) ; print screen mode disabled
test ourarg.flgs,emheath ; Are we to use Heath sequences?
jnz chkmod ; no, do something else
mov ah,prstr
mov dx,offset enascan ; enable scan codes
int dos
chkmod: call clrmod ; clear mode line
test ourarg.flgs,modoff ; is mode line disabled?
jnz term1 ; yes, skip it
call modlin ; turn on mode line
term1: call portchr ; char at port?
jnc term3 ; no, keep going
call outtty ; print on terminal
term3: mov ah,chr_status
mov al,chr_sfgs ; get number of characters
call bios_confunc ; check console
cmp bl,0
jz term1 ; no character, go on
mov ah,chr_read
call bios_confunc ; read it
cmp al,ourarg.escc ; escape char?
je term4 ; yes, exit
push ax ; save char
mov ah,al
call trnout ; translate if nec., output to port
pop ax
jmp term1 ; else echo and keep going
term4: call clrmod
mov ah,prstr
mov dx,offset disscan ; disable scan code generation
int dos
pop es
ret
term endp
; returns with carry on if a character is available
portchr proc near
call prtchr ; character at port?
jmp short portc1 ; yes, go handle
nop ; skip return is stupid
clc ; no carry -> no character
ret
portc1: and al,7fh ; we don't worry about parity here
stc ; have a character
ret
portchr endp
; put the character in al to the screen
outtty proc near
mov ah,chr_write
call bios_confunc
test ourarg.flgs,capt ; capturing output?
jz outtt1 ; no, forget it
call ourarg.captr ; else call the routine
outtt1: test flags1,prtscr ; print screen?
jz outtt2 ; no, try something else
call bios_print
outtt2: ret
outtty endp
; send the character in al out to the serial port
; handle echoing also...
outprt proc near
test ourarg.flgs,lclecho ; echoing?
jz outpr1 ; no, forget it
push ax ; save char
call outtty ; print it
pop ax ; restore
outpr1: mov ah,al ; this is where outchr expects it
call outchr ; output to the port
nop
nop
nop ; skip returns...
ret
outprt endp
modlin proc near ; turn on mode line
mov al,ourarg.escc
mov modbuf.m_echr,' ' ; first char is initial space
mov modbuf.m_hlp,' ' ; goes here too.
cmp al,32 ; printable?
jnb modl1 ; yes, keep going
add al,40h ; made printable
mov modbuf.m_echr,'^' ; note control char
mov modbuf.m_hlp,'^'
modl1: mov modbuf.m_echr+1,al ; fill in character
mov modbuf.m_hlp+1,al
mov al,ourarg.baudb ; get baud bits
mov si,offset unkbaud ; assume unknown baud
cmp al,baudnsiz ; too big?
jnb modl2 ; yes, use default
mov cl,2 ; each is 4 bytes long
shl al,cl
mov ah,0
add ax,offset baudn
mov si,ax
modl2: mov cx,size m_baud ; length of baud space
mov di,offset modbuf.m_baud
rep movsb ; copy in baud rate
mov al,ourarg.parity ; get parity code
mov cl,2 ; each is 4 bytes long...
shl al,cl
mov ah,0
add ax,offset parnams ; names of parity settings
mov si,ax
mov cx,4 ; each is 4 long
mov di,offset modbuf.m_par
rep movsb
mov si,offset remmsg ; assume remote echoing
test ourarg.flgs,lclecho ; echoing?
jz modl4 ; no, keep going
mov si,offset lclmsg
modl4: mov cx,3 ; size of on/off
mov di,offset modbuf.m_echo
rep movsb
; mov al,'1'
; cmp portno,1 ; port 1?
; je modl5 ; yes, keep going
; mov al,'2'
;modl5: mov modbuf.m_prt,al ; fill in port number
; mov cx,size modfrm ; this is size of mode line
; mov si,offset modbuf ; mode line image
mov si,offset offmsg ; assume printer off
test flags1,prtscr ; print screen enabled?
jz modl5 ; no, keep going
mov si,offset onmsg
modl5: mov cx,3
mov di,offset modbuf.m_prs
rep movsb
mov dx,offset modbuf
call putmod
ret ; and return
modlin endp
; translate the scan code in ah according to the translate table
; given in ktrntab/krpltab, output to port. If no translation,
; use ascii char in al. (should probably include shift state
; somewhere). Shift state is in bl.
trnout proc near
test ourarg.flgs,havtt ; translate table given?
jz trnou3 ; no, just output character
cmp ourarg.klen,0 ; did they say we have one
je trnou3 ; but we really don't?
push ax ; save original value
xor ah,ah ; Zero top half
mov di,ourarg.ktab
mov cx,ourarg.klen
repne scasw ; look for our key
pop ax ; recover character
jne trnou3 ; not found, forget it
sub di,ourarg.ktab
sub di,2 ; (minus 2 for pre-increment)
mov bx,ourarg.krpl
mov si,[bx][di] ; and addr of replacement
mov cl,[si] ; get first byte (length)
xor ch,ch ; clear high-order byte
inc si ; point to translation string
trnou2: lodsb ; get a byte
push si
push cx ; save important registers
call outprt ; send to port
pop cx
pop si
loop trnou2 ; send all chars
ret ; and return
trnou3: xor ah,ah ; get scan code
mov cx,lckeys ; length of table
mov di,offset ckeys ; table address
repne scasb
; mov al,0 ; ascii code was 0...
jne trnou4 ; not found, keep going
sub di,offset ckeys+1 ; get table offset
shl di,1 ; shift for word offset
jmp ckacts[di] ; jump to appropriate routine
trnou4: call outprt ; just output single char
ret ; and return
;trnmod: test flags,modoff ; mode line already off?
; jnz trnm1 ; yes, go turn on
; call clrmod ; no, clear mode line here
; or flags,modoff ; turn on flag
; ret ; and return
;trnm1: call modlin ; turn on mode line
; and flags,not modoff ; clear flag
; ret ; and return
trnbrk:
call sendbr
ret
trnprs: xor flags1,prtscr ; flip the flag
and ourarg.flgs,not modoff ; turn on mode line
call modlin ; write into mode line
ret ; and return
trn1ch: mov cx,1 ; length is always 1
jmp trnou2
; common entry for arrow keys
trn2ch: mov cx,2 ; length is always 2
jmp trnou2 ; go send definition
trn3ch: mov cx,3 ; length is always 3
jmp trnou2
trnupw: mov si,offset uptrn
jmp trn2ch
trndnw: mov si,offset dntrn
jmp trn2ch
trnlfw: mov si,offset lftrn
jmp trn2ch
trnrgw: mov si,offset rgtrn
jmp trn2ch
trnhom: mov si,offset homtrn
jmp trn2ch
trnent: mov si,offset enttrn
jmp trn1ch
trnf0: mov si,offset f0trn
jmp trn2ch
trnf1: mov si,offset f1trn
jmp trn2ch
trnf2: mov si,offset f2trn
jmp trn2ch
trnf3: mov si,offset f3trn
jmp trn2ch
trnf4: mov si,offset f4trn
jmp trn2ch
trnf5: mov si,offset f5trn
jmp trn2ch
trnf6: mov si,offset f6trn
jmp trn2ch
trnf7: mov si,offset f7trn
jmp trn2ch
trnf8: mov si,offset f8trn
jmp trn2ch
trnf9: mov si,offset f9trn
jmp trn3ch
trnf10: mov si,offset f10trn
jmp trn3ch
trnf11: mov si,offset f11trn
jmp trn3ch
trnkpn: and al,07fh ; strip high bits
jmp trnou4 ; now output it
trnkps: and al,03fh ; strip high bits (special case)
jmp trnou4
trnsf0: mov si,offset sf0trn
jmp trn2ch
trnsf1: mov si,offset sf1trn
jmp trn3ch
trnsf2: mov si,offset sf2trn
jmp trn3ch
trnsf3: mov si,offset sf3trn
jmp trn3ch
trnsf4: mov si,offset sf4trn
jmp trn3ch
trnsf5: mov si,offset sf5trn
jmp trn3ch
trnsf6: mov si,offset sf6trn
jmp trn3ch
trnsf7: mov si,offset sf7trn
jmp trn3ch
trnsf8: mov si,offset sf8trn
jmp trn3ch
trnsf9: mov si,offset sf9trn
jmp trn3ch
trnsf10: mov si,offset sf10trn
jmp trn3ch
trnsf11: mov si,offset sf11trn
jmp trn3ch
trnskp1: mov si,offset skp1trn
jmp trn2ch
trnskp2: mov si,offset skp2trn
jmp trn2ch
trnskp3: mov si,offset skp3trn
jmp trn2ch
trnskp4: mov si,offset skp4trn
jmp trn2ch
trnskp5: mov si,offset skp5trn
jmp trn2ch
trnskp6: mov si,offset skp6trn
jmp trn2ch
trnskp7: mov si,offset skp7trn
jmp trn2ch
trnskp8: mov si,offset skp8trn
jmp trn2ch
trnskp9: mov si,offset skp9trn
jmp trn2ch
trnout endp
code ends
end
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msyz100.asm
/bin/echo -n ' '; /bin/ls -ld msyz100.asm
fi
/bin/echo 'Extracting msz100.hlp'
sed 's/^X//' <<'//go.sysin dd *' >msz100.hlp
KERMIT VERSION 2.26 FOR Z-DOS
September 20, 1984
This guide is meant to be a supplement to the MSKERMIT.HLP file. It
describes the differences between the Z-100 version of Kermit and
the IBM-PC version. This version has not been tested with Z-DOS
version 2.0. LOCAL command execution may or may not work.
* Program Operation
The Z-100 version of Kermit uses a slightly different concept for
Heath emulation. The Z-100 normally uses the same escape sequences
as the Heathkit H-19 terminal, although a slightly different key
arrangement is used. With Heath emulation mode turned on, the normal
Z-100/H19 escape sequences will be sent by the function keys and keypad.
However, key redefinition will not be available. Printer control is
also not available in Heath emulation mode. When Heath emulation
is turned off (the default), the function keys and keypad emulate the
Heath sequence as best as possible (no checks are made for alternate
or shifted keypad modes), but key redefinition is allowed. If a problem
is encountered running a program that uses the keypad keys or function
keys, swicth to Heath emulation and see if that helps. Heath
emulation only affects what characters are sent for keys typed at the
keyboard. It does not change the affect of incoming characters or
escape sequences.
The Z-100 version of Kermit-MS does not support multiple communication
ports. The modem is assumed to be connected to the AUX port. This
port must be configured as no parity, no handshake, 1 stop bit, 8 data
bits, no pad.
* Terminal Emulation
The Z-DOS version of Kermit-MS uses the following capabilities:
Escape Char: ^]
Modeline
Printer control
Key redefinition (with Heath emulation off)
Screen scroll is not currently supported.
X. Printer Control
The contents of a screen may be printed at any time if a printscreen
driver has been installed prior to running Kermit. This is usually
done by running the PSC command which comes with your ZDOS 1.25
disks. After this, the screen contents may be printed using
Shift-F12.
If you wish to log a terminal session on the printer and you are not
using Heath emulation mode, the F12 function key will start or stop
the spooling of incoming characters to the printer. This may also
be simulated by the Kermit-MS LOG PRN and CLOSE commands.
X. Key Redefinition
Key redefinitions are accomplished in the same way as with the IBM-PC
version. However, key redefintion may only be used when Heath
emulation is turned off.
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msz100.hlp
/bin/echo -n ' '; /bin/ls -ld msz100.hlp
fiknutson@ut-ngp.UUCP (Jim Knutson) (10/05/84)
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
all=TRUE
fi
/bin/echo 'Extracting mskermit.doc'
sed 's/^X//' <<'//go.sysin dd *' >mskermit.doc
79
9. MS-DOS KERMIT
Program: Daphne Tzoar and Jeff Damens, Columbia University; contribu-
tions by many others.
Language: Microsoft Macro Assembler (MASM)
Documentation:
Frank da Cruz, Columbia University; Herm Fischer, Litton
Data Systems, Van Nuys CA.
Version: 2.26
Date: July 1984
Kermit-MS Capabilities At A Glance:
Local operation: Yes
Remote operation: Yes
Transfers text files: Yes
Transfers binary files: Yes
Wildcard send: Yes
^X/^Y interruption: Yes
Filename collision avoidance: Yes
Can time out: Yes
8th-bit prefixing: Yes
Repeat count prefixing: Yes
Alternate block checks: Yes
Terminal emulation: Yes
Communication settings: Yes
Transmit BREAK: Yes
IBM mainframe communication: Yes
Transaction logging: No
Session logging: Yes
Raw transmit: No
Act as server: Yes
Talk to server: Yes
Advanced server functions: No
Advanced commands for servers: Yes
Local file management: Yes
Handle file attributes: No
Command/init files: Yes
Command macros: Yes
Kermit-MS is a program that implements the KERMIT file transfer protocol
for the IBM PC and several other machines using the same processor
family (Intel 8088 or 8086) and operating system family (PC-DOS or
MS-DOS, henceforth referred to collectively as MS-DOS, versions 1.1,
2.0, and 2.1, and thereafter). This section will describe the things
you should know about the MS-DOS file system in order to make effective
use of Kermit, and then it will describe the Kermit-MS program.
Version 2 of MS-DOS Kermit runs on a variety of systems, including the
IBM PC and XT, the HP-150, the DEC Rainbow 100 and 100+ (MS-DOS 2.05 and
above), the Wang PC, and there is a "generic" MS-DOS version. Version 1
was adapted at various stages of development to run on other systems as
well, including the Heath/Zenith 100, Tandy 2000, Victor 9000
(Sirius-1), and Seequa Chameleon, and is still available for those sys-
tems until support for them and others is added to version 2.
80
The program operates under version 1.1 or 2.0 and above of DOS, although
some features require the functionality of 2.0. It runs in ap-
proximately 80K of memory -- over and above the memory used by DOS
-- which means that your system should have at least 128K of RAM to use
version 2 of MS-DOS Kermit; smaller systems may still use Version 1.
9.1. The MS-DOS File System
The features of the MS-DOS file system of greatest interest to KERMIT
users are the form of the file specifications, and the distinction be-
tween pre-MS-DOS 2.0 file names and newer file names which allow direc-
tory paths.
9.1.1. File Specifications
MS-DOS 2.x file specifications are of the form
DEVICE:\PATHNAME\NAME.TYPE
where the DEVICE is a single character identifier (for instance, A for
the first floppy disk, C for the first fixed disk, D for a RAM disk
emulator), PATHNAME is up to 63 characters of identifier(s) (up to 8
characters each) surrounded by reverse slashes, NAME is an identifier of
up to 8 characters, and TYPE is an identifier of up to 3 characters in
length. Device and pathname may be omitted. The first backslash in the
pathname may be omitted if the specified path is relative to the current
directory. In the path field, "." means current directory, ".." means
parent directory. Some DOS implementations (like Wang) may use slash
"/" rather than backslash in the path field.
Pathname is normally omitted, and cannot be specified for MS-DOS 1.x or
with those commands which allow MS-DOS 1.x use. Device and directory
pathnames, when omitted, default to either the user's current disk and
directory, or to the current directory search path as specified in the
DOS PATH environment variable, depending on the context in which the
file name appears.
When this manual says that a file is searched for "in the cur-
rent path," it means that the PATH is searched first, and if the
file is not found, then Kermit-MS looks on the current disk and
directory. If the PATH environment variable is empty, Kermit
looks only at the current disk and directory.
NAME.TYPE is normally sufficient to specify a file, and only this infor-
mation is sent along by Kermit-MS with an outgoing file.
The device, path, name, and type fields may contain uppercase letters,
digits, and the special characters "-" (dash), "_" (underscore), and "$"
(dollar sign). (For use only among MS-DOS processors, additional
filename special characters allowed are "#&!%'`(){}". DOS 1.x allows
others as well.). There are no imbedded or trailing spaces. Other
characters may be not be included; there is no mechanism for "quoting"
otherwise illegal characters in filenames. The fields of the file
specification are set off from one another by the punctuation indicated
81
above.
The name field is the primary identifier for the file. The type, also
called the extension or suffix, is an indicator which, by convention,
tells what kind of file we have. For instance FOO.BAS is the source of
a BASIC program named FOO; FOO.OBJ might be the relocatable object
module produced by compiling FOO.BAS; FOO.EXE could be an executable
program produced by linking FOO.OBJ, and so forth. .EXE and .COM are
the normal suffixes for executable programs.
The MS-DOS allows a group of files to be specified in a single file
specification by including the special "wildcard" characters, "*" and "?
". A "*" matches any string of characters from the current position to
the end of the field, including no characters at all; a "?" matches any
single character. Here are some examples:
*.BAS All files of type BAS (all BASIC source files) in the current
directory.
FOO.* Files of all types with name FOO.
F*.* All files whose names start with F.
F?X*.* All files whose names start with F and contain X in the third
position, followed by zero or more characters.
?.* All files whose names are exactly one character long.
Wildcard notation is used on many computer systems in similar ways, and
it is the mechanism most commonly used to instruct Kermit to send a
group of files.
Note: Kermit-MS uses the "?" character for help while commands
are being typed, so the single-character wildcard in Kermit-MS
commands is "=" rather than "?". For example
Kermit-MS>send =.*
would send files of all types whose names were exactly one
character long.
Kermit-MS users should bear in mind that other (non-MS-DOS) systems may
use different wildcard characters. For instance the DEC-20 uses "%" in-
stead of "?" as the single character wildcard; when using Kermit-MS to
request a wildcard file group from a KERMIT-20 server, the Kermit-MS "="
must be replaced by the DEC-20 "%".
9.1.2. File Formats
MS-DOS systems store files as bulk collections of 8 bit bytes, with no
particular differences between text, program code, and binary files.
ASCII text files consist of lines separated by carriage-return-linefeed
sequences (CRLFs), which conforms exactly to the way Kermit represents
text files during transmission. Since a non-MS-DOS receiving system
might need to make distinctions as to file type, you may need to use
82
various SET functions on the remote system to inform it that the incom-
ing file is of some particular (non-default) type, such as binary. In
transmitting files between Kermit-MS's, regardless of file contents, the
receiving MS-DOS system is equally capable of processing text, code, and
data, and in fact has no knowledge of how the bytes in the file are
used.
MS-DOS (unlike CP/M) is capable of pinpointing the end of file with
precision by keeping a byte count in the directory, so one would expect
no particular confusion in this regard. However, certain MS-DOS
programs continue to use the CP/M convention of terminating a text file
with a Control-Z character, and won't operate correctly unless this ter-
minating byte is present. Therefore, Kermit-MS users should be aware of
a special SET EOF option for both incoming and outbound files, described
below.
Non-MS-DOS systems may well be confused by nonstandard ASCII files from
Kermit-MS. Files produced by Easywriter or Word Star, for example, may
need to be converted to conventional ASCII format prior to transmission
by commonly available "exporter" programs. Spreadsheet or database
files usually need special formatting to be meaningful to non-MS-DOS
recipients (though they can be transmitted between MS-DOS systems with
Kermit-MS). Furthermore, files created by word processors (such as BLUE
or Easy Writer) that store formatting data at the end of the file, after
the control-Z and before physical end, will require special processing
via SET EOF to strip the formatting data, lest they confuse non-MS-DOS
recipients.
9.2. Program Operation
Kermit-MS can be run interactively, from a batch file, or as an
"external" DOS command. Commands consist of one or more fields,
separated by "whitespace" -- one or more spaces or tabs.
Upon initial startup, the program executes any commands found in the
file MSKERMIT.INI in the current path. This initialization file may
contain command macro definitions, communications settings for one or
more ports, or any other Kermit-MS commands. Here is a sample
MSKERMIT.INI file:
set warning on ; Enable filename collision avoidance.
;
; Define some macros
;
define unix set local-echo off, set flow xon, set timer off
def ibm set parity odd, set local on, set handsh xon, set timer on
def modem set port 2, set baud 1200
def noisy set block-check 3, set send packet-length 40
;
; Select a port
;
set port 1 ; Select COM1 for communications,
set baud 4800 ; setting the speed to 4800 baud,
connect ; and make a terminal connection.
83
Note that comments may be included by prefixing them with a semicolon.
The program can be run in several ways.
Interactive Operation:
To run Kermit-MS interactively, invoke the program from DOS command
level by typing its name. When you see the command's prompt,
Kermit-MS>
you may type Kermit commands repeatedly until you are ready to exit the
program, for example:
A>
A>kermit
IBM PC Kermit-MS V2.26
Type ? for help
Kermit-MS>send foo.*
informational messages about the files being sent
Kermit-MS>get bar.*
informational messages about the files being received
Kermit-MS>exit
A>
During interactive operation, you may edit the command you're currently
typing to erase the character most recently typed (BACKSPACE or DEL),
the most recent field (CTRL-W), or the entire command (CTRL-U). In ad-
dition, you may use the help ("?") and recognition (ESC) features freely
while typing Kermit-MS commands. A question mark typed at almost any
point in a command produces a brief description of what is expected or
possible at that point; for this reason, Kermit-MS uses "=" for the
single-character match wildcard in local filenames. ESC typed at any
point, even in a local filename, will cause the current field to be
filled out if what you have typed so far is sufficient to identify it,
and will leave you in position to type the next field (or to type a "?"
to find out what the next field is); otherwise, the program will beep at
you and wait for you to type further characters.
Some Kermit-MS commands, like GET, SHOW KEY, SET KEY, may prompt for ad-
ditional information on subsequent lines. If you have reached one of
these prompts and then wish to cancel the command, you may type
Control-C.
Summary of Kermit-MS Command Characters:
BACKSPACE Delete the character most recently typed. May be typed
repeatedly to delete backwards. You may also use
DELETE, RUBOUT, or equivalent keys.
84
CTRL-W Delete the most recent "word", or field, on the command
line. May be typed repeatedly.
CTRL-U Delete the entire command line.
CTRL-C Cancel the current command and return to the
"Kermit-MS>" prompt.
? Type a brief message describing what you are expected to
type in the current field.
ESC If enough characters have been supplied in the current
field (keyword or file name) to uniquely identify it,
supply the remainder of the field and position to the
next field of the command. Otherwise, sound a beep.
= Wildcard character for matching single characters in
filenames, equivalent to MS-DOS "?".
Command Line Invocation:
Kermit-MS may also be invoked with command line arguments from DOS com-
mand level, for instance:
A>kermit send foo.bar
or
A>kermit set port 1, set baud 9600, connect
In this case, help and recognition are not available (because the
program won't start running until after you type the entire command
line), and Kermit-MS will exit after completing the specified command or
commands. Therefore, when invoked with command line arguments,
Kermit-MS will behave as if it were an external DOS command, like MODE.
Note that several commands may be given on the command line, separated
by commas.
Batch Operation:
Like other MS-DOS programs, Kermit-MS may be operated under batch with
either command line arguments and/or TAKE files; Kermit will also run
interactively if invoked from batch, but it will read commands from the
keyboard and not the batch file.
9.3. Kermit-MS Commands
MS-DOS Kermit implements a large subset of the commands of "ideal" Ker-
mit. Here's a brief summary:
BYE to remote server.
CLOSE log file and stop logging remote session.
CONNECT as terminal to remote system.
85
DEFINE macros of Kermit-MS commands.
DELETE local files.
DIRECTORY listing of local files.
DO a macro expansion.
EXIT from Kermit-MS.
FINISH Shut down remote server.
GET remote files from server.
HELP about Kermit-MS.
LOCAL prefix for local file management commands.
LOG remote terminal session.
LOGOUT remote server.
PUSH to MS-DOS command level.
QUIT from Kermit-MS
RECEIVE files from remote Kermit.
REMOTE prefix for remote file management commands.
RUN an MS-DOS program.
SEND files to remote Kermit.
SERVER mode of remote operation.
SET various parameters.
SHOW various parameters.
SPACE inquiry.
STATUS inquiry.
TAKE commands from file.
The remainder of this section concentrates on the commands that have
special form or meaning for MS-DOS Kermit. Not all of the following
commands are necessarily available on all MS-DOS systems, and some of
the commands may work somewhat differently between DOS versions.
9.3.1. Commands for File Transfer
The file transfer commands are SEND, GET, and RECEIVE.
THE SEND COMMAND
Syntax: SEND filespec1 [filespec2]
The SEND command causes a file or file group to be sent from the local
MS-DOS system to the Kermit on the remote system. The remote Kermit may
be running in either server or interactive mode; in the latter case, you
should already have given it a RECEIVE command and escaped back to your
PC.
filespec1 may contain a device designator, like "A:" and the wildcard
characters "*" and/or "=". The current release of Kermit-MS, however,
does not allow pathnames in the SEND command file specification.
If filespec1 contains wildcard characters then all matching files will
be sent, in the same order that MS-DOS would show them in a directory
listing. If filespec1 specifies a single file, you may direct Kermit-MS
to send that file with a different name, given in filespec2. For in-
stance, in the command
Kermit-MS>send foo.bar framus.widget
86
filespec2 begins with the first nonblank character after filespec1 and
ends with the carriage return; thus it may contain blanks or other un-
usual characters that may be appropriate on the target machine. Lower
case letters in filespec2 are raised to upper case for transmission.
If a file can't be opened for read access, standard MS-DOS recovery
procedures will take place. For example:
Not ready error reading drive A
Abort, Retry, Ignore?
If you select "Abort," you will be returned to DOS.
Files will be sent with their MS-DOS filename and filetype (for instance
FOO.TXT, no device or pathname). Each file is sent as is, with no con-
versions done on the data, except for possibly adding or deleting a ter-
minating Control-Z character (see the SET EOF command).
Once you give Kermit-MS the SEND command, the name of each file will be
displayed on your screen as the transfer begins; packet, retry, and
other counts will be displayed along with informational messages during
the transfer. If the file is successfully transferred, you will see
"Complete", otherwise there will be an error message. When the
specified operation is done, the program will sound a beep.
Several single-character commands may be given while a file transfer is
in progress:
^X (Control-X) Stop sending the current file and go on to the next
one, if any.
^Z Stop sending this file, and don't send any further files.
^C Return to Kermit-MS command level immediately without sending any
kind of notification to the remote system.
^E Like ^C, but send an Error packet to the remote Kermit in an at-
tempt to bring it back to server or interactive command level.
CR Simulate a timeout: resend the current packet, or NAK the expected
one.
Control-X and Control-Z send the proper protocol messages to the remote
Kermit to bring it gracefully to the desired state. Control-C leaves
the remote Kermit in whatever state it happens to be in. Control-E
"aborts" any protocol that is taking place.
THE RECEIVE COMMAND
Syntax: RECEIVE [filespec]
The RECEIVE command tells Kermit-MS to receive a file or file group from
the other system. Kermit-MS simply waits for the file to arrive; this
command is not to be used when talking to a Kermit server (use GET for
that). You should already have issued a SEND command to the remote Ker-
87
mit and escaped back to Kermit-MS before issuing the RECEIVE command.
If the optional filespec is provided, store the incoming file under that
name. The filespec may include a device designator, or may consist of
only a device designator. The incoming file is stored on the default or
specified device (current directory in DOS 2.0 and thereafter). If no
name was specified, the name from the incoming file header packet is
used; if that name is not a legal MS-DOS file name, Kermit-MS will
delete excessive characters from it, and will change illegal characters
to the letter X.
If the optional filespec was provided, but more than one file arrives,
the first file will be stored under the given filespec, and the
remainder will be stored under their own names, but on the specified
device.
If an incoming file does not arrive in its entirety, Kermit-MS will nor-
mally discard it; it will not appear in your directory. You may change
this behavior by using the command SET INCOMPLETE KEEP, which will cause
as much of the file as arrived to be saved in your directory.
The same single-character commands are available as during SEND:
^X Request that the remote Kermit stop sending the current file, and
proceed to the next one immediately. Since this is an optional
feature of the Kermit protocol, the remote Kermit might not honor
the request.
^Z Request that the remote Kermit terminate the entire transfer; this
is also an optional feature that may or may not be supported by
the remote Kermit.
^C, ^E, and CR operate in the same way as they do during SEND.
If the incoming file has the same name as a file that already exists,
and WARNING is set ON, Kermit-MS will change the incoming name (and in-
form you how it renamed it) so as not to obliterate the pre-existing
file. If WARNING is OFF, the original file will be overwritten; if you
type ^X or ^Z to interrupt the transfer, you'll either get a partial new
file, or else both the old and the new file of that name will be lost,
depending on SET INCOMPLETE. In any case, when WARNING is off, files
with the same name as incoming files will not survive.
Caution: If an incoming file's name (the part before the dot) cor-
responds to an MS-DOS device name, such as NUL, COM1, CON, AUX, or PRN,
output will go to that device, rather than to a file with that name.
This is a feature of MS-DOS.
88
THE GET COMMAND
Syntax: GET remote-filespec
The GET command requests a remote KERMIT server to send the file or file
group specified by remote-filespec. This command can be used only when
Kermit-MS has a KERMIT server on the other end of the connection. This
means that you must have CONNECTed to the other system, logged in, run
KERMIT there, issued the SERVER command, and escaped back (e.g. ^]C) to
the local Kermit-MS. If the remote Kermit does not have a SERVER com-
mand, then you should use SEND and RECEIVE as described above.
You may use the GET command to specify a different name for storing the
incoming. Just type GET alone on a line, and you will be prompted
separately for the remote filespec and the local filespec:
Kermit-MS>get
Remote Source File: com1.txt
Local Destination File: xcom1.txt
If more than one file arrives, only the first will be renamed.
The remote filespec is any string that can be a legal file specification
for the remote system; it is not parsed or validated locally. It can
contain whatever wildcard or file-group notation is valid on the remote
system. As files arrive, their names will be displayed on your screen,
along with packet traffic statistics and status messages. You may type
^X to request that the current incoming file be cancelled, ^Z to request
that the entire incoming batch be cancelled, and ^C or ^E to return im-
mediately to the Kermit-MS> prompt, exactly as described for the RECEIVE
command.
9.3.2. Commands for Connecting and Disconnecting
The CONNECT command connects your PC as a terminal to the remote system,
so that you can start up Kermit there. The BYE, FINISH, and LOGOUT com-
mands allow you to shut down a remote Kermit server.
BYE When communicating with a remote KERMIT server, use the
BYE command to shut down the server, log out its job,
and exit from Kermit-MS to DOS.
FINISH Like BYE, FINISH shuts down the remote server. However,
FINISH does not log out the server's job. You are left
at Kermit-MS prompt level so that you can connect back
to the job on the remote system.
LOGOUT The LOGOUT command is identical to the BYE command, ex-
cept you will remain at Kermit-MS prompt level, rather
than exit to DOS, so that you can establish another con-
nection.
89
The CONNECT Command
Establish an interactive terminal connection to the system connected to
the currently selected communications port (e.g. COM1 or COM2) using
full duplex (remote) echoing and no parity unless otherwise specified in
previous SET commands. Get back to Kermit-MS by typing the escape
character followed by the letter C. The escape character is Control-] by
default.
You can use the SET ESCAPE command to define a different escape charac-
ter, and on some systems (including the PC and XT) you can SET BAUD to
change the baud rate, and SET PORT to switch between ports.
Terminal emulation is described in greater detail in section 9.4 below.
9.3.3. Commands for File Management
Kermit-MS provides commands or managing both local and remote files.
THE REMOTE COMMANDS
The REMOTE keyword is a prefix for a number of commands. It indicates
that the command is to be performed by the remote Kermit, which must be
running as a server. Note that not all Kermit servers are capable of
executing all these commands, and some Kermit servers may be able to
perform functions for which Kermit-MS does not yet have the correspond-
ing commands. In case you send a command the server cannot execute, it
will send back a message stating that the command is unknown to it. If
the remote server can execute the command, it will send the results to
your screen. Here are the REMOTE commands which Kermit-MS may issue:
CWD [directory] Change Working Directory on the remote host. Change the
default source and destination area for file transfer
and management. You will be prompted for a password,
which will be erased as you type it. If you do not
supply a password (i.e. you type only a carriage
return), the server will attempt to access the specified
directory without a password. If you do not supply a
directory name, your default or login directory on the
remote system will be assumed.
DELETE filespec Delete the specified file or files on the remote system.
In response, the remote host should display a list of
the files that were or were not successfully deleted.
DIRECTORY [filespec] The remote system will provide a directory listing
of the specified files. If no files are specified, then
all files in the default area (the current working
directory) will be listed.
HELP The remote host tells what server functions it is
capable of.
HOST [command] Send the command to the remote system's command proces-
90
sor for execution.
SPACE [directory]
Provide a brief summary of disk usage in the specified
area on the remote host. If none specified, the default
or current area will be summarized.
TYPE filespec Display the contents of the specified remote file or
files on the screen.
THE LOCAL COMMAND
The LOCAL keyword is a prefix for a number of commands. It indicates
that the specified command is to be executed on the local MS-DOS system.
The LOCAL prefix may be omitted. The local commands available are:
DELETE filespec Deletes the specified file or files. As in DOS, the
names of the deleted files are not listed, only the mes-
sage "file(s) deleted" or "file(s) not found", and if
you give the command "delete *.*", Kermit-MS will prompt
"Are you sure?", like DOS.
DIRECTORY [filespec] Lists the names, sizes, and creation dates of
files that match the given file specification. If no
filespec is given, the command is equivalent to DIR *.*.
SPACE Performs the MS-DOS CHKDSK function by running the
CHKDSK program from the current path, or default disk
under DOS 1.1.
RUN filespec Runs the specified file, which must be in .EXE or .COM
format, from the specified path or according to the
value of the PATH variable if no path was included in
the filespec. This command requires MS-DOS 2.0 or
higher.
PUSH Invokes an MS-DOS command processor "under" Kermit-MS,
either COMMAND.COM or whatever shell you have specified
with COMSPEC. When you return to Kermit-MS (for in-
stance, by typing the MS-DOS EXIT command), you will
find Kermit-MS as you left it, with all settings intact.
This command only works in MS-DOS 2.0 or higher.
The local RUN command has various uses, one of which is to supplement
the features of Kermit-MS. For instance, suppose there is an involved
procedure that you regularly perform on a certain remote system -- this
might include giving commands to a modem to dial the system, looking for
a particular herald or prompt, performing a login command sequence, run-
ning a selected application, and then running Kermit to send the results
back to your PC. You could write a program in the compiled language of
your choice, say C or BASIC, to send the desired commands to your modem
and the remote system and to look for the appropriate responses. You
could put all this in a Kermit-MS TAKE command file (see below), like
91
run update.com
receive
The program, called UPDATE in this case, does everything up to and in-
cluding starting Kermit sending from the remote system. When the
program terminates, the next Kermit-MS command, "receive," is executed
from the command file. When the end of the command file is reached, in-
teractive operation is resumed.
THE TAKE COMMAND
Syntax: TAKE filespec
Execute Kermit commands from the specified file, which may include an
explicit path; if no path is specified, the value of the PATH variable
is used; if PATH has no value, then the current disk and directory are
searched. The command file may include TAKE commands, but it cannot in-
clude characters to be sent to a remote host during terminal emulation
(i.e. after a CONNECT command). A command file may include comments
prefixed by semicolons.
THE LOG COMMAND
Syntax: LOG filespec
Specifies that all characters that appear on your screen during CONNECT
will be recorded in the specified file. This allows you to "capture"
files from a remote system that doesn't have Kermit, as well as to
record remote command typescripts. The log is closed when you EXIT from
Kermit-MS or when you issue an explicit CLOSE command.
9.3.4. The SERVER Command
Kermit-MS is capable of acting as a Kermit server, providing file trans-
fer for users coming in through one of the communication ports. The
current version of Kermit-MS can send files (the user on the other end
types the GET command), receive files (the user types SEND), and ter-
minate, giving control back to the console (user types BYE).
To put Kermit-MS into server mode, first issue any desired SET commands
to select and configure the desired port, and then type the SERVER com-
mand. Kermit-MS will await all further instructions from the user Ker-
mit on the other end of the connection, which may be hardwired or con-
nected through an autoanswer modem. For example:
Kermit-MS>set port 1
Kermit-MS>set baud 1200
Kermit-MS>set timer on
Kermit-MS>set warning on
Kermit-MS>server
92
9.3.5. The SET Command
Syntax: SET parameter [value]
Establish or modify various parameters for file transfer or terminal
connection. You can examine their values with the SHOW command. Note
that there is no "set ibm" command; IBM mainframe communication
parameters may be selected with a command macro (see below). The fol-
lowing SET commands are available in Kermit-MS:
BAUD Communications port line speed
BELL Whether to beep at the end of a transaction
BLOCK-CHECK-TYPE Level of error checking for file transfer
DEBUG Display packet contents during file transfer
DEFAULT-DISK Default disk drive for file i/o
DESTINATION Default destination device for incoming files
END-OF-LINE Packet terminator
EOF Method for determining or marking end of file
ESCAPE Escape character for CONNECT
FLOW-CONTROL Enable or disable XON/XOFF
HANDSHAKE Half-duplex line turnaround option
HEATH19 Heath/Zenith-19 terminal emulation
INCOMPLETE What to do with an incompletely received file
KEY Specify key redefinitions, or "keystroke macros"
LOCAL-ECHO Specify which host does the echoing during CONNECT
PARITY Character parity to use
PORT Select a communications port
PROMPT Change the "Kermit-MS>" prompt to something else
RECEIVE Request remote Kermit to use specified parameters
REMOTE For running Kermit-MS interactively from back port
SEND Use the specified parameters during file transfer
TAKE-ECHO Control echoing of commands from TAKE files
TIMER Enable/disable timeouts during file transfer
WARNING Specify how to handle filename collisions
The SET commands that are peculiar to MS-DOS Kermit are now described in
greater detail. The others behave as in "ideal" Kermit.
SET BAUD
Syntax: SET BAUD rate
Set the speed of the currently selected terminal communications port
(COM1 by default) to 300, 1200, 1800, 2400, 4800, 9600 or other common
baud rate. Some implementations do not support this command. In any
case, Kermit-MS leaves the current communication port settings alone un-
less you issue explicit SET commands to change them.
SET BELL
Syntax: SET BELL ON or OFF
Specifies whether bell (beeper) should sound upon completion of a file
transfer operation.
93
SET DEBUG
Syntax: SET DEBUG ON or OFF
ON Display the Kermit packet traffic on your screen during file
transfer. If the debugger is loaded, transfer control to it
when CTRL-C is typed. In Heath-19 terminal emulation on the IBM
PC, display unusual control characters in uparrow notation.
OFF Don't display debugging information (this is the default). If
debugging was in effect, turn it off.
SET DEFAULT-DISK
Syntax: SET DEFAULT-DISK x:
Specify the default disk drive to use for file transfer, directory list-
ings, and so forth. Equivalent to typing the DOS command for changing
disks.
SET DESTINATION
Syntax: SET DESTINATION device
Specify the device for incoming files, DISK or PRINTER. SET DESTINATION
PRINTER will cause incoming files to be spooled directly to the printer.
The normal destination is DISK.
END-OF-LINE
Syntax: SET END-OF-LINE number
If the remote system needs packets to be terminated by anything other
than carriage return, specify the decimal value of the desired ASCII
character.
SET EOF
Syntax: SET EOF option
Controls how the end of file is handled. The options are:
CTRL-Z Append a Control-Z character to the end of an incoming
file, unless it already ends with a Control-Z. Certain
MS-DOS text editors and other applications require files
to be in this format. For outbound files, treat the
first Control-Z as the end of file, and do not send it
nor any characters following it.
NOCTRL-Z (Default) Store incoming files exactly as is, and send
MS DOS files exactly as is (according to their byte
count).
94
SET ESCAPE
Syntax: SET ESCAPE character
Specify the control character you want to use to "escape" from remote
connections back to Kermit-MS. The default is normally ^] (Control-
Rightbracket). The character is entered literally, and should normally
be chosen from the ASCII control range.
SET FLOW-CONTROL
Syntax: SET FLOW-CONTROL option
Specify the full duplex flow control to be done on the currently
selected port. The current options are XON/XOFF and NONE. The
specified type of flow control will be done during both terminal emula-
tion and file transfer. If set to XON/XOFF, HANDSHAKE is automatically
set to OFF.
SET HANDSHAKE
Syntax: SET HANDSHAKE option
Specify any half-duplex handshaking to be done on the currently selected
port. The options are BELL, CR, LF, NONE, XOFF, or XON. The specified
handshaking will be done during file transfer only. If HANDSHAKE is set
to anything other than NONE, FLOW-CONTROL is automatically set to OFF.
SET HEATH19
Syntax: SET HEATH19 ON or OFF
Specify whether Kermit-MS should use its built-in software facility for
emulating a Heath/Zenith-19 (H19) terminal.
ON During CONNECT, incoming characters are to be examined for H19
terminal screen control commands (escape sequences), and if en-
countered, the commands are to be emulated on the PC screen.
The H19 codes are a superset of the popular DEC VT52 codes, so
if your system does not support the Heath-19, you may tell it
that your terminal type is VT52 (or one of the many VT52
compatibles). The Heath-19 codes are listed in section 9.10,
below.
OFF All incoming characters will be sent to the screen "bare",
through DOS. If you have loaded a device driver into DOS for
the CON: device, such as ANSI.SYS, then that driver will be able
to interpret the codes itself. Most non-IBM systems have their
own screen control code interpreter built into DOS or firmware,
or available as a loadable device driver.
See section 9.4 for details about terminal emulation.
95
SET KEY
Syntax: SET KEY key-specifier
Specifies that when the designated key is struck during terminal emula-
tion, the associated character string is sent. The key-specifier is one
of the keywords F1, F2, ..., or SCAN followed by a scan code. Systems
that have a BACKSPACE key also include BACKSPACE as a keyword.
If SCAN is used, it is followed by a decimal number to indicate the scan
code of the key, which you would ascertain from your system reference
manual, or else by using the Kermit-MS SHOW KEY command. SET KEY
prompts you on a new line for the definition string. Certain charac-
ters, like ESC and CR, may not be entered literally into the string, but
can be included by inserting escape codes of the form \ooo, a backslash
followed by a 2- or 3-digit octal number corresponding to the ASCII
value of the desired character. If some other key redefinition package,
like ProKey, has been loaded, then its redefinitions will take
precedence over Kermit's.
The SET KEY command is illustrated in the terminal emulation section,
9.4, below.
SET LOCAL-ECHO
Syntax: SET LOCAL-ECHO option
Specify how characters are echoed during terminal emulation on the cur-
rently selected port. ON specifies that characters are to be echoed by
Kermit-MS (because neither the remote computer nor the communications
circuitry has been requested to echo), and is appropriate for half-
duplex connections. LOCAL-ECHO is OFF by default, for full-duplex,
remote echo operation.
When you SET LOCAL-ECHO ON, the current HANDSHAKE (if any) is automati-
cally enabled and full-duplex FLOW-CONTROL is automatically turned off.
When you SET LOCAL-ECHO OFF, HANDSHAKE is also disabled, and the current
mode of FLOW-CONTROL (if any) is enabled. If this behavior is un-
desired, you may override it by typing explicit SET HANDSHAKE or SET
FLOW commands after entering the SET LOCAL-ECHO command.
SET PARITY
Syntax: SET PARITY keyword
Specify the character parity to be used on the currently selected port.
The choices for SET PARITY are NONE (the default), ODD, EVEN, MARK, and
SPACE. NONE means no parity processing is done, and the 8th bit of each
character can be used for data when transmitting binary files.
You will need to SET PARITY to ODD, EVEN, MARK, or possibly SPACE when
communicating with a system, or over a network, or through modems, con-
centrators, multiplexers, or front ends that require or impose character
parity on the communication line. For instance, GTE Telenet requires
96
MARK parity. If you neglect to SET PARITY when the communications equi-
pment requires it, the symptom may be that terminal emulation works par-
tially, and file transfer does not work at all.
If you have set parity to ODD, EVEN, MARK, or SPACE, then Kermit-MS will
request that binary files will be transferred using 8th-bit-prefixing.
If the other side knows how to do 8th-bit-prefixing (this is an optional
feature of the KERMIT protocol, and not all implementations of KERMIT
have it), then binary files can be transmitted successfully. If NONE is
specified, 8th-bit-prefixing will not be requested. Note that there is
no advantage to using parity; it only slows Kermit file transfer down.
The SET PARITY command is provided only to allow Kermit to adapt to
hardware that insists upon using parity.
SET PORT
Syntax: SET PORT number
On machines with more than one communications port, select the port to
use for file transfer and CONNECT. This command lets you use a dif-
ferent asynchronous adapter, or switch between two or more simultaneous
remote sessions. Subsequent SET BAUD, PARITY, HANDSHAKE, FLOW, and
LOCAL-ECHO commands will apply to this port only. SET PORT 1 selects
COM1, SET PORT 2 selects COM2.
SET REMOTE
Syntax: SET REMOTE ON or OFF
If you wish to run Kermit-MS interactively through the back port, for
instance after the operator has done CTTY COM1, you must give the com-
mand SET REMOTE ON; this suppresses the file transfer display screen, so
that the display won't interfere with the file transfer itself.
SET RECEIVE
Syntax: SET RECEIVE parameter value
At the beginning of a protocol operation, request the remote Kermit to
use the given value specified parameter, or inform Kermit-MS that the
remote Kermit will be using it.
PACKET-LENGTH Ask the remote Kermit to use the specified maximum
length for packets that it sends to Kermit-MS. The nor-
mal (and maximum) length is 94. Use this command to
shorten packets if the communication line is noisy; this
will decrease the probability that a particular packet
will be corrupted, and will reduce the retransmission
overhead when corruption occurs, but it will increase
the protocol overhead.
PADCHAR Ask the remote Kermit to use the given character for in-
terpacket padding. Kermit-MS should never require any
97
padding.
PADDING Ask the remote Kermit to insert the given number of pad-
ding characters before each packet it sends. This
should never be necessary.
START-OF-PACKET The remote Kermit will be marking the beginning of pack-
ets with something other than Control-A. This will be
necessary only if the hosts or communication equipment
involved cannot pass a Control-A through as data.
TIMEOUT Ask the remote Kermit to time out after the given number
of seconds if a packet expected from Kermit-MS has not
arrived. Use this command to change the normal timeout
interval.
SET SEND
Syntax: SET SEND parameter value
PACKET-LENGTH Use the specified maximum length for outbound packets.
Normally, Kermit-MS uses whatever length the other Ker-
mit requests.
PADCHAR Use the specified character for interpacket padding.
Some hosts may require some padding characters (normally
NUL or DEL) before a packet.
PADDING How many padding characters to use between packets, nor-
mally zero.
QUOTE Use the indicated printable character for prefixing
(quoting) control characters and other prefix charac-
ters. The only reason to change this would be for send-
ing a very long file that contains very many "#" charac-
ters (the normal control prefix) as data.
START-OF-PACKET Mark the beginning of outbound packets with some control
character other than Control-A. This will be necessary
only if the remote host or the communication channel in-
volved cannot accept a Control-A as data. The remote
host must have been given the corresponding SET RECEIVE
START-OF-PACKET command.
TIMEOUT Change Kermit-MS's normal timeout interval; this command
is effective only if TIMER is set to be ON; it is nor-
mally OFF so that the remote KERMIT can control
timeouts.
98
SET TAKE-ECHO
Syntax: SET TAKE-ECHO ON or OFF
Specifies whether screen display should occur during implicit or ex-
plicit TAKE operations on MSKERMIT.INI or other Kermit-MS command files,
and during evaluation of macro definitions. Handy for finding errors in
command files.
SET TIMER
Syntax: SET TIMER ON or OFF
Enable or disable the timer that is used during file transfer to break
the deadlock that occurs when an expected packet does not arrive. By
default, the timer is OFF, because Kermit-MS is usually used in conjunc-
tion with a mainframe that is doing its own timeouts. During a file
transfer, it is sufficient for one side to do the timing out and the
mainframe is usually better equipped to adjust timeout intervals based
on system load or other conditions. The timer should be set ON if you
are communicating with a system that cannot do timeouts, such as IBM
VM/CMS Kermit.
SET WARNING
Syntax: SET WARNING option
Specify what to do when an incoming file has the same name as an exist-
ing file in the default directory of the default device. If ON, Kermit
will warn you when an incoming file has the same name as an existing
file, and automatically rename the incoming file (as indicated in the
warning message) so as not to destroy (overwrite) the pre-existing one.
If OFF, the pre-existing file is destroyed, even if the incoming file
does not arrive completely.
9.3.6. The SHOW Command
Syntax: SHOW option
Currently, most parameters that may be altered with SET commands are
displayed by the STATUS command. The SHOW command is used for display-
ing macro definitions and key redefinitions.
The SHOW MACROS command displays the definitions of all currently
defined macros.
The SHOW KEY command allows you to determine the scan code produced by
pressing a given key, so that you can construct a SET KEY command to
redefine the key. If the key already has a redefinition in effect, that
too will be displayed. In this example, a DEC Rainbow user determines
the scan code for the accent grave key, and then redefines that key to
send ESC:
99
Kermit-MS>show key
Press a key: `
Scan Code: 96
Definition:
Kermit-MS>set key scan 96
Definition string: \33
Kermit-MS>show key
Press a key: `
Scan Code: 96
Definition: \33
Kermit-MS>
The SHOW KEY command only works on certain systems.
9.3.7. Command Macros
Kermit-MS provides a facility for combining commands into "macros."
Command macro definitions may be included in your MSKERMIT.INI file,
TAKEn explicitly from a specified file, or typed interactively, and may
be invoked with the DO command.
THE DEFINE COMMAND
Kermit-MS command macros are constructed with the DEFINE command. The
syntax is
DEFINE macro-name [command [, command [, ...]]]
Any Kermit-MS commands may be included. Example:
define telenet set parity mark, set baud 1200, connect
THE DO COMMAND
A Kermit-MS command macro is invoked using the DO command. For in-
stance, Kermit-MS comes with a predefined macro to allow convenient
setup for IBM communications; to invoke it, you would type
do ibm
The IBM macro is defined as "parity mark, handshake xon, local-echo on,
timer on". You can delete or replace this definition by adding a new
(perhaps null) definition, such as
define ibm parity even, handshake cr, local-echo on, timer on
or
define ibm
100
9.4. Terminal Emulation
When you issue the CONNECT command, your PC acts as a terminal connected
to a remote computer through the currently selected port. The charac-
ters you type are sent out the port, and characters that arrive at the
port are displayed on your screen. If you have not previously issued a
SET PORT command, COM1 is used. If you have SET LOCAL-ECHO ON for the
selected port, then Kermit-MS will display characters on the screen as
you type them. If LOCAL-ECHO is OFF, then XON/XOFF flow control will be
done unless you have SET FLOW-CONTROL OFF. If you have SET PARITY to
anything other than NONE, Kermit-MS will add the appropriate parity to
each outbound character, and strip any parity from incoming ones. While
CONNECTed, you can also communicate with an autodialer or "smart modem"
to control the communications line, hang it up, and the like; for in-
stance, typing +++ to a Hayes-like modem will allow you to follow that
by dialing or hangup commands.
If Heath-19 emulation is being done, incoming characters will be
monitored for H19/VT52 escape sequences. These will be interpreted ac-
cording to the table in section 9.10. In addition, keys on the numeric
keypad will send H19/VT52 sequences unless you disable this feature in
some way, for instance by pressing Num Lock on the IBM PC keyboard, or
with key redefinitions.
Caution: On some systems, such as the IBM PC and XT, Kermit-MS
accesses the screen memory memory directly to perform certain
H19 emulation functions such as character insert/delete and
screen scroll. Without direct screen memory access, these func-
tions would be painfully slow. Although Kermit-MS has been
tested successfully on a variety of monochrome and color adap-
ters and monitors, there may be combinations for which this
method could cause video problems, such as snow. Should this
occur, you can alleviate the problem by setting HEATH19 emula-
tion OFF. In that case, however, you remove not only the
problems, but also the desirable features of emulation. But
Kermit-MS does permit you to load an external console device
driver, such as IBM's ANSI.SYS, to provide any desired screen
control.
Here are the terminal emulation options for the systems presently sup-
ported by Kermit-MS:
System EscChar Cabilities Terminal Service
IBM PC, XT ^] R M P K Heath19 emulation
DEC Rainbow ^] R P K VT102 firmware
HP-150 ^] R HP-2623 firmware
Wang PC ^A Wang firmware
Generic DOS ^] Depends on system
Under Capabilities, R means rollback, M means mode line, P means printer
control, and K means key redefinition.
IBM PC/XT Kermit can disable Heath-19 emulation and use an external con-
sole device driver like ANSI.SYS instead.
When you first issue the CONNECT command, a message (on some systems, an
101
inverse video "mode line") will display the most important facts about
the connection you've just established, so that you can quickly diagnose
any problems. The items displayed in the mode line include the escape
character, port number, the baud rate, the parity, the echo, and how to
get help, for instance:
+---------------------------------------------------------------------+
|EscChar:^],Port:1,Baud:9600,Parity:None,Echo:Remote,Type ^]? for Help|
+---------------------------------------------------------------------+
The escape character is used to regain the attention of Kermit-MS. When
you type the escape character, Kermit-MS waits for you to follow it with
a single character command. For instance, the single-character-command
"?" produces a list of available single character commands, such as
this:
? Help -- prints the available single-character commands.
C Close the connection and return to Kermit-MS prompt level.
S Show the status of the connection.
B Send a BREAK signal to the port.
0 (the digit zero) Send a NUL (ASCII 0) to the port.
Q Temporarily quit logging the remote session.
R Resume logging the remote session.
M Toggle the mode line, i.e. turn it off if it is on & vice versa.
^] (or whatever you have set the escape character to be)
Typing the escape character twice sends one copy of it to the con-
nected host.
Typing any other character (except the space bar, which is the "null
command") after the escape character will cause Kermit-MS to beep, but
will do no harm. The escape character can be changed to something other
than Control-Rightbracket by using the SET ESCAPE command.
Kermit-MS includes several advanced features for use during terminal
emulation, including screen scroll, printer control, and key redefini-
tions.
Screen Scroll
Kermit-MS provides several pages of screen memory, which may be scrolled
up and down using keys as follows:
Function IBM PC/XT Rainbow HP-150
Screen Down PgDn PrevScreen Prev
Line Down Ctrl-PgDn Ctrl-PrevScreen Shift-UpArrow
Screen Up PgUp NextScreen Next
Line Up Ctrl-PgUp Ctrl-NextScreen Shift-DownArrow
Top of Memory Home
Bottom of Memory End
There is presently no way to assign these functions to other keys.
102
Printer Control
A locally attached printer may be controlled in the normal manner, on
most systems. Pushing the "Print Screen" key (shifted on some systems)
will cause the current contents of the screen to be printed or spooled;
holding down CTRL while depressing Print Screen will start or stop the
spooling of incoming characters to the printer. ^P or ^N are sent to
the host during terminal emulation, and do not toggle printing, as they
do when you're talking directly to DOS.
CTRL-Print-Screen can be simulated with the Kermit-MS LOG PRN and CLOSE
commands.
Key Redefinitions
Key redefinitions are useful for defining "keystroke macros" of login
sequences, frequently issued commands, and so forth, and for setting up
the terminal for use with host resident software designed to work with
terminals that send predefined sequences from their function keys. For
instance, here's a key redefinition file for arranging the DEC Rainbow
keyboard into the normal ASCII keyboard layout:
; Make shift-comma send a left angle bracket
set key scan 556
<
; Shift-period sends a right angle bracket
set key scan 558
>
; Accent grave is where ESC is supposed to be
set key scan 96
\33
; Put accent grave on the ESC function key
set key f11
`
The SET KEY facility may be used provide the PC with a "meta" key for
use with editors like EMACS or TVEDIT that can use "meta characters" as
commands. A meta key is a shift key whose effect is to turn on the 8th
(parity) bit of the character. For instance, on the IBM PC the scan
codes produced by holding down ALT together with other keys can be
determined using SHOW KEY, and then 8-bit ASCII equivalents with the 8th
bit turned on can be defined using SET KEY; if the scan code produced by
typing ALT-a, i.e. the letter "a" (ASCII 141, octal) with the ALT key
held down, is 2078 (decimal), you would set the META equivalent to
141+200=341 (octal), or "\341" in octal SET KEY notation:
Kermit-MS>sho key
Press a key: ALT-a
Scan Code: 2078
Definition:
Kermit-MS>set key scan 2078
Definition String: \341
Whenever you type ALT-a with this definition in effect, Kermit-MS will
transmit octal 341, rather than 141.
103
9.5. Installation of Kermit-MS
by Bill Catchings, Columbia University
If you already have Kermit on your PC, you can use it to obtain new ver-
sions of Kermit-MS when they appear on the central system at your site.
If you do not have Kermit or any other reliable file capture facility on
your PC, and there is no one from whom you can borrow a floppy disk to
copy Kermit, then you should read the following instructions for in-
itially "bootstrapping" Kermit-MS from a mainframe where it is stored
onto your microcomputer.
There are at least three methods of initially getting Kermit-MS onto
your PC:
1. Try again to find a copy on diskette.
2. Use another file capture facility to get it.
3. Type in and run a bootstrapping program.
9.5.1. Try Again To Find A Kermit Disk
Before explaining how to bootstrap Kermit onto your PC, a disclaimer
must be made. Although a fair amount of thought and time has gone into
these procedures, they are far from error free. If they were foolproof,
there would be no need for a protocol such as Kermit. There are many
places where things can go wrong, from something as simple as a typing
mistake to something as unavoidable and probably inevitable as a com-
munications line failure. By far the easiest and best way to install
Kermit is from a floppy disk. Before you embark on any of the following
procedures it is a good idea to check once again for a diskette to copy,
even it it contains an old version of Kermit. The time you spend
searching is likely to be far less frustrating than the time you spend
trying to bootstrap Kermit by the methods described below.
9.5.2. Bootstrapping From the Communication Line
If you can't find a diskette with Kermit on it, there are two other
methods available for bootstrapping MS-DOS Kermit onto your PC. The
first method is to use a file capture method or other file transfer
protocol to transfer the file to your PC. Some systems come supplied
with facilities like this, and various public domain or commercial
packages are available. The second method requires you to type in your
own downloading program.
In either case, you must transmit the file from the system where it
resides over a communication line and into your PC. Since version 2 of
MS-DOS Kermit is much larger than version 1, it comes with a new
bootstrapping procedure in which the executable program is encoded much
more compactly than in the earlier "fix" files. The new encoding packs
3 .EXE file bytes into 4 printable characters in the MSxxx.BOO file, and
also compresses adjacent zero bytes (of which there are many). The .BOO
file contains only printable characters, to ensure that downloading can
104
take place regardless of parity or other peculariaries of the communica-
tion channel.
9.5.2.1. Use An Existing File Capture Facility
In the rest of this discussion of bootstrapping, the host-resident boot
X.BOO file will be referred to as MSKERMIT.BOO. In fact, the actual name
will depend on which MS-DOS system you are using -- MSIBMPC.BOO for the
IBM PC or XT, MSRB100.BOO for the Rainbow 100, etc.
Use your file capture facility, whatever it may be, to get the file
MSKERMIT.BOO onto your PC's disk, but first make sure you have enough
room for it. Once the file is on your disk, you must run the BASIC
program MSPCTRAN.BAS to decode the file back into KERMIT.EXE. This
program can be downloaded by the same method you used with MSKERMIT.BOO.
The program looks on your current disk and directory for the file
MSKERMIT.BOO and outputs KERMIT.EXE to the same place. KERMIT.EXE is
about 80K bytes, so make sure there is space for it on your disk or else
you will have to start the program over. Since the program will take
about twenty minutes to completely translate the file you will want to
avoid running it more than once.
9.5.2.2. Type In Your Own Bootstrap
If you can't find some method for downloading the .BOO file and the
BASIC program, the second way of bootstrapping Kermit is to use the
programs MSPCBOOT.BAS and MSBOOT.FOR to download via your PC's
asynchronous port from your host and translate it directly, "on the
fly." You run the program MSBOOT.FOR on your host and then run the
program MSPCBOOT.BAS in BASIC on your PC. The FORTRAN program sends the
encoded .EXE file to the BASIC program, which decodes it and stores it
in executable form on your current directory as KERMIT.EXE. A very
rudimentary form of error checking is done to allow obviously corrupted
records to be retransmitted. Follow this procedure:
1. First, you must establish a connection from your PC to the
host system. A high speed connection is preferable; a
"clean" line is preferable to a noisy one. In fact, a clean
line is essential for this procedure. You must be able to
log in to the host system over this connection. If your PC
already has a terminal emulation facility, use that. If not,
you might need to put your PC next to a real terminal and use
that for logging in, then switch the connector to the PC at
the crucial moment. If you are using a terminal, make sure
the terminal and PC have their communication ports set to the
same speed.
2. Ensure that the files MSBOOT.FOR and MSKERMIT.BOO are present
on the host system. MSBOOT.FOR is listed below, in case you
need to type it in.
3. Get back to your PC and type in MSPCBOOT.BAS on your PC; a
listing appears below. There is no need to type in the com-
ments (anything following an apostrophe); they are only there
105
to clarify what the program is doing. Check very carefully
for errors. You should check line 80 in the program to see
that it reflects the way your system is actually set up. If
necessary, substitute the correct baud rate for the supplied
rate of 9600, and if you are not using COM1: make that change
as well. If you are downloading from an IBM or other half-
duplex mainframe, leave line 1000 as it is; otherwise,
replace it by a RETURN statement. If you type it in directly
to BASIC make sure you save the program before you run it, so
you won't have to type it in again in case of error.
4. Get back to your host system and compile MSBOOT.FOR, if it
needs compiling. Define logical unit numbers 5 and 6 to be
the controlling terminal, and logical unit 7 to be the file
MSKERMIT.BOO. On VAX/VMS systems, for example, use these
commands:
$assign sys$input for005
$assign sys$output for006
$assign mskermit.boo for007
On a DECSYSTEM-20, do:
@define 5: tty:
@define 6: tty:
@define 7: mskermit.boo
On a DECsystem-10, do something like this:
.assign tty: 5:
.assign tty: 6:
.assign dsk: 7:
.rename for007.dat=mskerm.boo
On an IBM system under VM/CMS, do this:
.filedef 5 term ( lrecl 80 recfm v
.filedef 6 term ( lrecl 80 recfm v
.filedef 7 disk mskermit boo ( lrecl 77 recfm f perm
5. Set your host system up for downloading:
- Ensure that your terminal does not automatically pause
at the end of a screenful of output. For instance, on a
DEC-20 you would issue the command "terminal no pause
end-of-page".
- Do whatever you can to disable messages from appearing
at your terminal while these programs are running. This
would include messages from other users, mail notifica-
tion, alarms or alerts, system messages, and so forth.
Such messages will interfere with the procedure, and
probably render the result useless.
- You should put your host terminal in "local echo" or
"half duplex" mode, if possible.
106
6. Start the MSBOOT program on your host system.
7. Get back to the PC. If you have been using a terminal,
switch the connector to the PC.
8. Now run the BASIC program, MSPCBOOT.BAS. This procedure will
take at least twenty minutes and possibly longer depending on
line speed. Watch your modem and/or disk lights for reas-
surance that something is happening.
By using one of these installation methods, you should now have a work-
ing version of Kermit. If you experience any problems or quirky be-
havior with the program, it's possible that some part of it was cor-
rupted during the downloading procedure. Perhaps enough usable code
remains to allow you to transfer MSKERMIT.EXE from the host. If not,
you will have to repeat the downloading procedure.
Once you have Kermit-MS on your disk, you should make the disk available
to other users for copying, so that they can be spared the tedium of
this bootstrap procedure.
Here is a listing of MSPCBOOT.BAS. The "outdented" PRINT statements
with line numbers ending in 5 may be included if you want incoming
records to be displayed on the screen. You don't need to include the
comments.
1 'Run this program on the PC in conjunction with a Fortran program
2 '(MSBOOT.FOR) on the mainframe to download Kermit to the PC. This
3 'program will run for about thirty minutes, depending on line speed.
4 ' Bill Catchings, June 1984
5 ' Columbia University Center for Computing Activities
10 t$ = time$ ' Save the time.
20 defint a-z ' All integer to gain some speed.
30 n$ = chr$(0)
40 z = asc("0")
50 t = asc("~")-z
60 def fnuchr%(a$)=asc(a$)-z
70 open "com1:9600,s,7,1,cs,ds,cd" as #1
100 print#1,"O ," ' Char constants "O", " " and ","
110 input#1,f$
120 if len(f$) < 5 then goto 110 ' In case the host echos the ACK.
130 input#1,n
135 print f$+" "+str$(n)
140 if n > 20 then goto 900
150 open f$ for output as #2
160 print "Outputting to "+f$
170 goto 300 ' Correct version of the file.
200 gosub 1000 ' Do turnaround char processing
210 print#1,"NO" ' Tell host data was incorrect.
220 goto 320
107
300 gosub 1000 ' Do turnaround char processing
310 print#1,"OK" ' Say the line was all right.
320 input#1,x$
330 if len(x$) < 5 then goto 320 ' In case the host echos ACK/NAK
340 input#1,n
345 print x$+" "+str$(n)
350 if len(x$) <> n then goto 200 ' Length doesn't match, NAK it.
360 if x$ = "&&&&&&&&&&" then goto 800 ' End of file?
370 y$ = "" ' Set output string to null.
380 goto 500
400 print#2,y$; ' Print the output string.
410 goto 300 ' Go get another line.
500 if len(x$) = 0 goto 400 ' Done with input string?
510 a = fnuchr%(x$)
520 if a = t then goto 700 ' Null repeat character?
530 q$=mid$(x$,2,3) ' Get the quadruplet to decode.
540 x$=mid$(x$,5)
550 b = fnuchr%(q$)
560 q$ = mid$(q$,2)
570 c = fnuchr%(q$)
580 q$ = mid$(q$,2)
590 d = fnuchr%(q$)
600 y$ = y$ + chr$(((a * 4) + (b \ 16)) and 255) ' Decode the quad.
610 y$ = y$ + chr$(((b * 16) + (c \ 4)) and 255)
620 y$ = y$ + chr$(((c * 64) + d) and 255)
630 goto 500 ' Get another quad.
700 x$ = mid$(x$,2) ' Expand nulls.
710 r = fnuchr%(x$) ' Get the number of nulls.
715 print " Null: ",r
720 x$ = mid$(x$,2)
730 for i=1 to r ' Loop, adding nulls to string.
740 y$ = y$ + n$
750 next
760 print#2,y$; ' Print the nulls.
770 y$ = "" ' Clear the output buffer.
780 goto 500
800 print "Processing complete, elapsed time: "+t$+" to "+time$
810 print "Output in "+f$
820 close #1,#2
830 goto 9999
900 print "?The format of the BOO file is incorrect"
910 goto 820
1000 x$ = input$(1,#1) ' Make this line RETURN for full-duplex
1010 if x$ <> chr$(17) then goto 1000 ' Loop for a turn around char.
1020 return
9999 end
108
Here is a listing of MSBOOT.FOR, in case you can't find it on your host
system:
C This Fortran program should be run on the mainframe in conjunction
C with a Basic program (MSPCBOOT.BAS) on the PC to transfer
C MSKERMIT.BOO to the PC and translate it into KERMIT.EXE. This
C program uses a very rudimentary technique to try to insure that
C the characters it sends arrive correctly. It just sends a count
C of the number of characters sent after each line. In this way any
C errors of character loss or insertion will be caught. If a
C character is just corrupted it will not be caught. Hopefully if
C this happens it will be in a non-critical part of the KERMIT.EXE
C file. The reason a simple checksum was not used was so that this
C program could run on machines using either EBCIDIC or ASCII
C characters. This program should take about thirty minutes to run.
C This program assumes that 5 and 6 are directed to the terminal and
C 7 is directed to the file MSKERMIT.BOO.
INTEGER LINE(77), ACK(4), CHECK, OK, SPACE, COMMA
WRITE(6,100)
100 FORMAT(' Ready to transfer data, now run MSPCBOOT.BAS on the PC.')
C Get characters for constants (character constants are rough in
C some FORTRANs!)
READ (5,200) OK, SPACE, COMMA, ACK
200 FORMAT(4A1)
GO TO 30
C Get terminal handshake.
10 READ (5,200)ACK
C Did the other side like it? (Did they send OK?)
IF (ACK(1) .NE. OK) GO TO 50
C Yes, get new line from file.
20 READ (7,300,END=99)LINE
300 FORMAT(77A1)
C Count the characters as some rudimentary check for noise.
I = 1
30 IF (LINE(I) .EQ. SPACE) GO TO 40
I = I + 1
GO TO 30
C Put in a comma followed by the count.
40 LINE(I) = COMMA
C Write to TTY.
50 WRITE (6,400)LINE,I-1
400 FORMAT(' ',77A1,I2)
GOTO 10
109
C Send good-bye message.
99 WRITE (6,500)
500 FORMAT(' ',10('&'),',10')
STOP
END
9.6. Compatibility with Older Versions of MS-DOS Kermit
MS-DOS Kermit supports many different systems. Like CP/M-80 KERMIT,
this support was added to the program piecemeal, at many sites, using
conditional assembly. However, before allowing the program to grow into
a complicated monolith like CP/M-80 KERMIT, we have broken the program
up into separate modules, with system dependencies isolated into a
single module consisting of compact collections of low-level primitives
for console and port i/o.
The last monolithic (single source file) release of MS-DOS Kermit was
1.20. To this and earlier versions was added support for systems like
the Seequa Chameleon, the Tandy 2000, the Victor 9000, the Heath/Zenith
100, and others. Eventually, support for these systems may be in-
tegrated with the new modular version. Meanwhile, implementations based
on these old versions will have at least the following incompatibilies
from the version described here:
- RECEIVE filespec is used instead of GET filespec. There is no
GET command in older versions, and no way to specify a new
name for an incoming file.
- No LOCAL or REMOTE commands.
- No 8th-bit prefixing, repeat counts, CRCs or 2-character
checksums.
- No TAKE or initialization files.
- No command macros or command line arguments.
- No terminal session logging.
and others, depending on the specific version.
9.7. What's Missing
Kermit-MS has plenty of room for improvement. Features that need to be
improved or added include:
- A built-in facility for sending files "raw" to the remote sys-
tem, obeying current settings for parity, flow control, hand-
shake, and so forth. This might include a script interpreta-
tion facility to allow remote sessions to be conducted
automatically. For the present, this can be accomplished with
a user-supplied program invoked with the Kermit-MS RUN com-
mand.
- Additional functionality when running in server mode
-- directory listings, file deletion, execution of DOS com-
mands, etc.
110
- More commands when talking to remote servers -- REMOTE RENAME,
COPY, STATUS, WHO, etc.
- Filename conversion options (normal form, handling of fully
qualified filespecs, etc.).
- Transaction file logging.
- Improved command parsing; for instance, accept default values
for omitted trailing fields.
- A better built-in help facility.
- Support for Kermit file attribute packets.
- The Kermit-MS program is quite large. Much of the size is due
to the deliberate decision to provide support for versions of
MS-DOS prior to 2.0. At some point, this support should be
removed. This will not only reduce the size of the program
considerably, but also provide much more flexibility.
9.8. Program Organization
Kermit-MS version 2 is composed of separate assembler source files, as-
sembled separately, and linked together. The modules are:
System/Device Independent:
MSKERM.ASM Main program
MSSEND.ASM File sender
MSRECV.ASM File receiver
MSSERV.ASM Server operation
MSFILE.ASM File i/o
MSCMD.ASM Command parser
MSTERM.ASM CONNECT command
MSCOMM.ASM Communications port buffering & flow control
MSSET.ASM SET, SHOW, and STATUS commands
MSDEFS.H Data structure definitions and equates
System/Device Dependent:
MSXxxx.ASM System-dependent code for system xxx
MSYxxx.ASM System-dependent screen and keyboard code
MSZxxx.ASM Modem control (modem-dependent)
The modular organization allows easier modification of the program,
quicker transfer of modified portions from system-to-system. The
modules are designed to be well-defined and self-contained, such that
they can be easily replaced. For instance, someone who prefers windows
and mice to typing commands could replace the command parsing module
without having to worry about the effect on the other modules.
To assemble any of the kermit modules, file MSDEFS.H must be on the
default disk.
111
All the Kermit implementations require the modules MSCMD, MSCOMM,
MSFILE, MSKERM, MSRECV, MSSEND, MSSERV, MSSET, MSTERM.
The IBM PC version requires MSXIBM and MSYIBM as well.
The Rainbow version requires MSXRB and MSXDMB; MSXDMB must be the first
object file given to the linker for Kermit to link properly for the
Rainbow.
The HP150 version requires MSXHP150, the Wang version requires MSXWNG,
and the generic version requires MSXGEN.
Once all the required object modules exist, they may be linked together
to produce Kermit. For example, on the Rainbow:
A>link
Microsoft Object Linker V2.00
(C) Copyright 1982 by Microsoft Inc.
Object Modules [.OBJ]: msxdmb mskerm msxrb mscomm msset mssend +
msrecv msserv msfile msterm mscmd
Run File [MSXDMB.EXE]: kermit
List File [NUL.MAP]: kermit
A>
9.9. Adding Support For New Systems
You can bring Kermit-MS to systems that are not explicitly supported in
one of two ways -- attempt to run the "generic" MS-DOS Kermit on it, or
add explicit code to support your system.
9.9.1. Generic MS-DOS Kermit
To get started with Kermit on a new system, try running "generic" MS-DOS
Kermit; in many cases, it will run as is. The generic version ac-
complishes all its port and console i/o through DOS calls, and during
terminal connection does not attempt to emulate any particular kind of
terminal. In some cases, the generic version may still require some
fiddling to run on a new system; for instance, different systems refer
to their communication ports in different ways -- COM1, AUX, etc. It
attempts to do this automatically by trying various DOS file handles for
the communication port, and asking you to supply one if it does not
succeed.
Generic MS-DOS Kermit will probably run no faster than 1200 baud, and it
only works with DOS 2.0 or later.
112
9.9.2. Adding System-Dependent Code
The following is a guide to the system dependent module of Kermit-MS.
SPECIFICATION FOR KERMIT SYSTEM-DEPENDENT MODULES
by Jeff Damens, Columbia University
All the system-independent global data structures used in Kermit-MS are
defined in the file MSDEFS.H.
The routine MSXxxx.ASM contains system-dependent support for system xxx,
except for terminal emulation, which is in MSXxxx.ASM, described below.
The routines in the MSX module may change any registers but the stack
pointer and segment registers, unless otherwise noted. A routine that
returns via a RET instruction is said to return normally; a routine that
skip returns is one that returns to three bytes past the normal return
address.
Global variables that must be defined in the system-dependent module:
XXOFSNT byte. This should be set to a non-zero value if we are
doing flow control and have sent an XOFF character to
the remote host, zero otherwise.
MACHNAM byte. A $-terminated string identifying the machine
this version of Kermit is for; it is printed when Kermit
starts up.
SETKTAB byte. A keyword table associating terminal key names to
16-bit scan code values, used in the set key command.
If the kermit version can accept arbitrary decimal
values as scan codes, the word "SCAN" should appear in
the table with a scan value of -1. If key redefinition
is not implemented, the first byte of the table should
be a zero.
SETKHLP byte. A $-terminated string to be printed when ? is
typed in the SET KEY command. This is usually simply a
list of the key names in SETKTAB. SETKHLP must be
defined even if key redefinition is not implemented, to
satisfy the linker; if key redefinition is not imple-
mented, SETKHLP will never be displayed.
COUNT word. The number of characters in the serial input
buffer, if known. This is how Kermit knows to send an
XON if the serial handler has sent an XOFF. If the num-
ber of characters in the buffer isn't known, COUNT
should be 0.
These are the required entry points for the system dependent dependent
module MSXxxx.ASM.
113
SERINI
Parameters None.
Returns Normally, no return value.
Description Perform any initialization that must be done before the
serial port can be used, including setting baud rate,
interrupt vectors, etc. Parity and baud rate should be
set according to the values in the PORTINFO structure.
The external variable PORTVAL points to the PORTINFO
structure for the current port. Calling SERINI more
than once without an intervening call to SERRST should
have no effect.
SERRST
Parameters None.
Returns Normally, no return value.
Description Undoes any initialization done by SERINI, including
resetting the serial port, restoring any interrupt vec-
tors changed by SERINI, etc. Calling this more than
once without an intervening call to SERINI should be
harmless.
CLRBUF
Parameters None.
Returns Normally, no return value.
Description Remove and discard from the serial port's input buffer
any characters sent by the remote host that have not yet
been read by Kermit, and set COUNT to 0. This is used
before a file transfer to flush NAK's that accumulate in
the buffer when the remote host is in server mode.
114
OUTCHR
Parameters A character in AH.
Returns Skip returns if the character has been transmitted;
returns normally if the character can not be transmitted
because of a hardware error.
Description Sends the character in AH out the currently selected
serial port. OUTCHR can assume that SERINI will have
been called previously. OUTCHR should call the external
routine DOPAR to set the parity of the character if the
communications hardware doesn't automatically set
parity. Flow control should be honored; the external
variable PORTVAL contains a pointer to a PORTINFO struc-
ture (as defined in MSDEFS.H) containing the current
flow control definitions.
COMS
Parameters None.
Returns Normally if a parse error is encountered, skip returns
otherwise.
Description Called by the SET PORT command. On a machine with mul-
tiple serial ports, COMS should parse for the name or
number of a serial port and make that the port used by
succeeding calls to SERINI, PRTCHR, OUTCHR, and SERRST.
It should set the external variable PORTVAL to point to
one of the external port structures PORT1 or PORT2, and
set COMFLG in the FLAGS structure to 1 for port one, 0
for port 2. For implementations that use only one
serial port, COMS should print a message to that effect
and skip return.
VTS
Parameters None.
Returns Normally if a parse error is encountered, skip returns
otherwise.
Description Parses for an ON or OFF, sets HEATH-19 emulation while
in terminal emulation appropriately. The VTFLG field of
the FLAGS structure should be set non-zero if HEATH-29
emulation is on, zero otherwise. If HEATH-19 emulation
is not done, VTS should print a message and skip return.
115
DODEL
Parameters None.
Returns Normally, no return value.
Description Erases the character immediately to the left of the cur-
sor from the screen, then backs up the cursor.
CTLU
Parameters None.
Returns Normally, no return value.
Description Move the cursor to the left margin, then clear the line.
CMBLNK
Parameters None.
Returns Normally, no return value.
Description Clears the screen and homes the cursor.
LOCATE
Parameters None.
Returns Normally, no return value.
Description Homes the cursor.
LCLINI
Parameters None.
Returns Normally, no return value.
Description Performs any system-dependent initialization required by
this implementation.
116
PRTCHR
Parameters None.
Returns Normally, with the next character from the currently
selected serial port in AL. Skip returns if no charac-
ter is available.
Description Reads the next character from the current serial port.
PRTCHR can assume SERINI has been called previously, and
should handle flow control correctly.
DOBAUD
Parameters None.
Returns Normally, no return value.
Description Sets the baud rate for the current port. The baud rate
should be obtained from the BAUD field of the PORTINFO
structure, pointed to by the external variable PORTVAL.
CLEARL
Parameters None.
Returns Normally, no return value.
Description Clears from the cursor to the end of the current line.
DODISK
Parameters None.
Returns Normally, no return value.
Description Sets the external variable DRIVES to the number of disk
drives attached to the machine.
GETBAUD
Parameters None.
Returns Normally, no return value.
Description Store current baud rate of the currently selected port
in the BAUD field of the current PORTINFO structure,
which is pointed to by PORTVAL. If the baud rate is to
default to a particular value, this routine can store
that value into the BAUD field instead.
117
BEEP
Parameters None.
Returns Normally, no return value.
Description Rings the terminal bell.
PUTHLP
Parameters A pointer to a string in AX.
Returns Normally, no return value.
Description Writes the null-terminated string given in AX to the
terminal. This is used to display help and status mes-
sages. The IBM and Rainbow versions write the string in
a reverse video box.
PUTMOD
Parameters A pointer to a string in AX.
Returns Normally, no return value.
Description Writes the null-terminated string given in AX to the
last line of the screen, in inverse video if possible.
CLRMOD
Parameters None.
Returns Normally, no return value.
Description Clears the line written by PUTMOD.
POSCUR
Parameters Row in DH, column in DL.
Returns Normally, no return value.
Description Positions the cursor to the row and column given in DX.
Rows and columns both originate at 0 (not 1!).
118
SENDBR
Parameters None.
Returns Normally, no return value.
Description Send a break to the current serial port.
SHOWKEY
Parameters Pointer to a terminal argument block in AX (see TERM
below).
Returns Normally, with a string pointer in AX and the length of
the string in CX.
Description Called by the SHOW KEY command. Reads a key from the
terminal and returns a string containing
implementation-dependent information about the key. In
the usual case, the string contains the key's
(machine-dependent) scan code, and the key's definition
(if any) from the terminal argument block. The length
of the returned string should be returned in CX. The
string may contain any characters; unprintable charac-
ters will be quoted when the string is printed. If the
implementation does not support key redefinition, SHOW-
KEY may return a static string saying so.
TERM
Parameters Pointer to terminal argument block in AX.
Returns Normally, no return value.
Description Do terminal emulation, based on argument block described
below...
The terminal emulator is supplied in the file MSYxxx.ASM. The terminal
argument block passed to the terminal emulator has the following fields:
FLGS Byte containing flags. Flags are:
SCRSAM (80H) If on, the terminal emulator shouldn't
re-display the screen when entered.
CAPT (40H) Capture output. If on, the routine
passed in field CAPTR is called with
each character sent to the screen.
EMHEATH (20H) Emulate a Heath-19 terminal if on.
119
HAVTT (10H) A key redefinition table is present.
TRNCTL (08H) Print control character X as ^X (useful
for debugging).
MODOFF (04H) Do not display emulator mode line if on.
LCLECHO (01H) Echo keyboard characters on the screen
in addition to sending them to the port.
PRT Port to use for terminal emulation, used only in mode
line. This is just a copy of COMFLG in FLAGS.
COLS Number of columns on screen.
ROWS Number of rows on screen.
CAPTR Routine to call to with each character sent to the
screen if CAPT flag is on. Characters are passed in AL.
BELLD Bell divisor (used only on IBM).
KLEN Number of keys in key redefinition table, if HAVTT flag
is on.
KTAB Address of key redefinition table. The key redefinition
table is a table of KLEN 16-bit scan codes. Each
(machine dependent) scan code represents a key that is
redefined.
KRPL Address of key replacement table. The key replacement
table parallels the key redefinition table given in
KTAB. Entries in the replacement table are 16-bit
pointers to redefinitions. Each redefinition has a
one-byte length, followed by the definition.
ESCC Escape character (single byte). When this character is
typed to the emulator, it should return.
BAUDB byte. Bits describing the baud rate so it can be
printed on the mode line. This is a copy of the BAUD
field in the PORTINFO structure. Currently used only on
the IBM. See MSDEFS.H for possible values.
PARITY byte. Current parity to print on the mode line. This
is a copy of PARFLG in the PORTINFO structure. Cur-
rently used only on the IBM. See MSDEFS.H for possible
values.
120
9.10. Heath/Zenith-19 Control Codes
The Heath/Zenith-19 terminal is equivalent to the DEC VT52 with exten-
sions for line and character insertion and deletion. Items marked with
an asterisk are not currently supported by Kermit-MS H19 emulation.
Cursor Functions
Sequence Mnemonic Definition
ESC H HCUH Cursor Home
ESC C HCUF Cursor Forward
ESC D HCUB Cursor Backward
ESC B HCUD Cursor Down
ESC A HCUU Cursor Up
ESC I HRI Reverse Index
*ESC n HCPR Cursor Position Report
*ESC j HSCP Save Cursor Position
*ESC k HRCP Set Cursor to Previously Saved Position
ESC Y HDCA Direct Cursor Addressing, 1-based:
31+line# 31+col# (same as VT52)
Erasing and Editing
Sequence Mnemonic Definition
ESC E HCD Clear Display (Shift Erase)
ESC b HBD Erase Beginning of Display
ESC J HEOP Erase to End of Page (Erase Key)
ESC l HEL Erase Entire Line
ESC o HEBL Erase Beginning of Line
ESC K HEOL Erase to End of Line
ESC L HIL Insert Line
ESC M HDL Delete Line
ESC N HDCH Delete Character
ESC @ HEIM Enter Insert Character Mode
ESC O HERM Exit Insert Character Mode
Configuration
Sequence Mnemonic Definition
*ESC z HRAM Reset to Power-Up Configuration
*ESC r Bn HMBR Modify Baud Rate: Bn=
A=110, B=150, C=300, D=600, E=1200,
F=1800, G=2000, H=2400, I=3600, J=4800,
K=7200, L=9600, M=19200
*ESC x Ps HSM Set Mode(s): Ps=
1 = Enable 25th line
2 = No key click
3 = Hold screen mode
4 = Block cursor
5 = Cursor off
121
6 = Keypad shifted
7 = Alternate keypad mode
8 = Auto line feed on CR
9 = Auto CR on line feed
*ESC y Ps HRM Reset mode(s): Ps=
1 = Disable 25th line
2 = Enable key click
3 = Exit hold screen mode
4 = Underscore cursor
5 = Cursor on
6 = Keypad unshifted
7 = Exit alternate keypad mode
8 = No auto line feed
9 = No auto CR
*ESC < HEAM Enter ANSI Mode
Modes of Operation
Sequence Mnemonic Definition
*ESC [ HEHS Enter Hold Screen Mode
*ESC \ HXHS Exit Hold Screen Mode
ESC p HERV Enter Reverse Video Mode
ESC q HXRV Exit Reverse Video Mode
*ESC F HEGM Enter Graphics Mode
*ESC G HXGM Exit Graphics Mode
*ESC t HEKS Enter Keypad Shifted Mode
*ESC u HXKS Exit Keypad Shifted Mode
*ESC = HAKM Enter Alternare Keypad Mode
*ESC > HXAM Exit Alternate Keypad Mode
Additional Operations
Sequence Mnemonic Definition
*ESC } HDK Keyboard Disable
*ESC { HEK Keyboard Enable
ESC v HEWA Wrap Around at End of Line
ESC w HXWA Discard at End of Line
ESC Z HID Identify as VT52 (ESC / K)
*ESC ] HX25 Transmit 25th Line
*ESC # HXMP Transmit Page
The Heath-19 transmits the following sequences, but it will not
respond to them if they are received. Kermit-MS will transmit them
only if they are programmed with SET KEY.
ESC S HF1 Function Key #1
ESC T HF2 Function Key #2
ESC U HF3 Function Key #3
ESC V HF4 Function Key #4
ESC W HF5 Function Key #5
122
ESC P HF7 Function Key #7
ESC Q HF8 Function Key #8
ESC R HF9 Function Key #9
123
Index
RECEIVE 86
ANSI.SYS 94 Recognition 83
Autodialer 100
Smart Modem 100
Batch Operation of Kermit-MS 84
Baud Rate 92 Telenet 95
Beeper 92 Timeout 98
Bell 92
Binary Files 96 Warning 98
Wildcard 81
Cancelling a File Transfer 86, 87
Command Files 98
Command Macro 99
CONNECT 100
Control-X 86, 87
Control-Z 86, 87
Debugging 93
DEFINE 99
DO Command 99
Eighth-Bit Prefix 96
EMACS 102
End Of File 82, 93
EOF 93
Escape Character for CONNECT 94
File Renaming 98
File Warning 98
Flow Control 94
Generic MS-DOS Kermit 111
Handshake 94
Heath-19 Terminal Emulation 94, 100,
120
Help 83
IBM PC 79
Incomplete File Disposition 87
Key Redefinition 95
Local Echoing 95
Macro 99
META Key 102
Mode Line 100
Modem 100
MS-DOS 79
Parity 95
PC-DOS 79
i
Table of Contents
9. MS-DOS KERMIT 79
9.1. The MS-DOS File System 80
9.1.1. File Specifications 80
9.1.2. File Formats 81
9.2. Program Operation 82
9.3. Kermit-MS Commands 84
9.3.1. Commands for File Transfer 85
9.3.2. Commands for Connecting and Disconnecting 88
9.3.3. Commands for File Management 89
9.3.4. The SERVER Command 91
9.3.5. The SET Command 92
9.3.6. The SHOW Command 98
9.3.7. Command Macros 99
9.4. Terminal Emulation 100
9.5. Installation of Kermit-MS 103
9.5.1. Try Again To Find A Kermit Disk 103
9.5.2. Bootstrapping From the Communication Line 103
9.5.2.1. Use An Existing File Capture Facility 104
9.5.2.2. Type In Your Own Bootstrap 104
9.6. Compatibility with Older Versions of MS-DOS Kermit 109
9.7. What's Missing 109
9.8. Program Organization 110
9.9. Adding Support For New Systems 111
9.9.1. Generic MS-DOS Kermit 111
9.9.2. Adding System-Dependent Code 112
9.10. Heath/Zenith-19 Control Codes 120
Index 123
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 mskermit.doc
/bin/echo -n ' '; /bin/ls -ld mskermit.doc
fi
/bin/echo 'Extracting msbuild.hlp'
sed 's/^X//' <<'//go.sysin dd *' >msbuild.hlp
To assemble any of the kermit modules, file MSDEFS.H must be on the
default disk.
All the Kermit implementations require the modules
MSCMD, MSCOMM, MSFILE, MSKERM, MSRECV, MSSEND, MSSERV, MSSET, MSTERM.
The IBM PC version requires MSXIBM and MSYIBM as well.
The Rainbow version requires MSXRB and MSXDMB; MSXDMB must be the first
object file given to the linker for Kermit to link properly.
The HP150 version requires MSXHP150, the Wang version requires MSXWNG,
and the generic version requires MSXGEN.
Once all the required object modules exist, they may be linked together
to produce Kermit. For example, on the Rainbow:
A>link
Microsoft Object Linker V2.00
(C) Copyright 1982 by Microsoft Inc.
Object Modules [.OBJ]: msxdmb mskerm msxrb mscomm msset mssend msrecv +
msserv msfile msterm mscmd
Run File [MSXDMB.EXE]: kermit
List File [NUL.MAP]: kermit
A>
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msbuild.hlp
/bin/echo -n ' '; /bin/ls -ld msbuild.hlp
fi
/bin/echo 'Extracting msboot.for'
sed 's/^X//' <<'//go.sysin dd *' >msboot.for
C This Fortran program should be run on the mainframe in conjunction
C with a Basic program (MSPCBOOT.BAS) on the PC to transfer
C MSKERMIT.BOO to the PC and translate it into KERMIT.EXE. This
C program uses a very rudimentary technique to try to insure that
C the characters it sends arrive correctly. It just sends a count
C of the number of characters sent after each line. In this way any
C errors of character loss or insertion will be caught. If a
C character is just corrupted it will not be caught. Hopefully if
C this happens it will be in a non-critical part of the KERMIT.EXE
C file. The reason a simple checksum was not used was so that this
C program could run on machines using either EBCDIC or ASCII
C characters. This program should take about thirty minutes to run.
C
C This program assumes that 5 and 6 are directed to the terminal and
C 7 is directed to the file MSKERMIT.BOO.
C
C Bill Catchings, Columbia University Center for Computing Activities
C June 1984 (Revised September 1984)
C
INTEGER LINE(77), ACK(4), CHECK, OK, SPACE, COMMA
WRITE(6,100)
100 FORMAT(' Ready to transfer data, now run MSPCBOOT.BAS on the PC.')
C Get characters for constants (character constants are rough in
C some FORTRANs).
READ (5,200) OK, SPACE, COMMA, ACK
200 FORMAT(4A1)
C The following statement has been changed from GO TO 30.
GO TO 20
C Get terminal handshake.
10 READ (5,200)ACK
C Did the other side like it? (Did they send OK?)
IF (ACK(1) .NE. OK) GO TO 50
C Yes, get new line from file.
20 READ (7,300,END=99)LINE
300 FORMAT(77A1)
C Count the characters as some rudimentary check for noise.
I = 1
30 IF (LINE(I) .EQ. SPACE) GO TO 40
I = I + 1
GO TO 30
C Put in a comma followed by the count.
40 LINE(I) = COMMA
C Write to TTY.
50 WRITE (6,400)LINE,I-1
400 FORMAT(' ',77A1,I2)
GOTO 10
C Send good-bye message.
99 WRITE (6,500)
500 FORMAT(' ',10('&'),',10')
STOP
END
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 msboot.for
/bin/echo -n ' '; /bin/ls -ld msboot.for
fi
/bin/echo 'Extracting mspcboot.bas'
sed 's/^X//' <<'//go.sysin dd *' >mspcboot.bas
1 'Run this program on the PC in conjunction with a Fortran program
2 '(MSBOOT.FOR) on the mainframe to download Kermit to the PC. This
3 'program will run for about thirty minutes, depending on line speed.
4 ' Bill Catchings, June 1984 (Revised Sept 1984)
5 ' Columbia University Center for Computing Activities
10 t$ = time$ ' Save the time.
20 defint a-z ' All integer to gain some speed.
30 n$ = chr$(0)
40 z = asc("0")
50 t = asc("~")-z
60 def fnuchr%(a$)=asc(a$)-z
70 open "com1:9600,s,7,1,cs,ds,cd" as #1
100 print#1,"O ,2" ' Char constants "O", " " and ","
110 input#1,f$
120 if len(f$) < 5 then goto 110 ' In case the host echos the ACK.
130 input#1,n
135 print f$+" "+str$(n)
140 if n > 20 then goto 900
150 open f$ for output as #2
160 print "Outputting to "+f$
170 goto 300 ' Correct version of the file.
200 gosub 1000 ' Do turnaround char processing
210 print#1,"NO" ' Tell host data was incorrect.
220 goto 320
300 gosub 1000 ' Do turnaround char processing
310 print#1,"OK" ' Say the line was all right.
320 input#1,x$
330 if len(x$) < 5 then goto 320 ' In case the host echos ACK/NAK
340 input#1,n
345 print x$+" "+str$(n)
350 if len(x$) <> n then goto 200 ' Length doesn't match, NAK it.
360 if x$ = "&&&&&&&&&&" then goto 800 ' End of file?
370 y$ = "" ' Set output string to null.
380 goto 500
400 print#2,y$; ' Print the output string.
410 goto 300 ' Go get another line.
500 if len(x$) = 0 goto 400 ' Done with input string?
510 a = fnuchr%(x$)
520 if a = t then goto 700 ' Null repeat character?
530 q$=mid$(x$,2,3) ' Get the quadruplet to decode.
540 x$=mid$(x$,5)
550 b = fnuchr%(q$)
560 q$ = mid$(q$,2)
570 c = fnuchr%(q$)
580 q$ = mid$(q$,2)
590 d = fnuchr%(q$)
600 y$ = y$ + chr$(((a * 4) + (b \ 16)) and 255) ' Decode the quad.
610 y$ = y$ + chr$(((b * 16) + (c \ 4)) and 255)
620 y$ = y$ + chr$(((c * 64) + d) and 255)
630 goto 500 ' Get another quad.
700 x$ = mid$(x$,2) ' Expand nulls.
710 r = fnuchr%(x$) ' Get the number of nulls.
715 print " Null: ",r
720 x$ = mid$(x$,2)
730 for i=1 to r ' Loop, adding nulls to string.
740 y$ = y$ + n$
750 next
760 print#2,y$; ' Print the nulls.
770 y$ = "" ' Clear the output buffer.
780 goto 500
800 print "Processing complete, elapsed time: "+t$+" to "+time$
810 print "Output in "+f$
820 close #1,#2
830 goto 9999
900 print "?The format of the BOO file is incorrect"
910 goto 820
1000 x$ = input$(1,#1) ' Make this line RETURN for full-duplex
1010 if x$ <> chr$(17) then goto 1000 ' Loop for a turn around char.
1020 return
9999 end//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
/bin/chmod 640 mspcboot.bas
/bin/echo -n ' '; /bin/ls -ld mspcboot.bas
ficsitc@ucbopal.CC.Berkeley.ARPA (10/08/84)
It is also possible to get source to ALL the Kermits (not just MSDOS) by anonymous FTP to columbia-20.ARPA, with the usual "guest" password. The files themselves are in ps:<KERMIT>file. They also have have full documentation, including a manual to the protocol used in Kermit, for those interested in writing their own versions.... (For those who may not know what Kermit is, it is essentially a file- transfer protocol used for communications between micros and large machines. Most implementations also include some kind of terminal emulation, such as for a vt52 or h/z19.)
wdn@hp2610.UUCP (10/29/84)
I'm having a problem with the ms-kermit sources that were posted to the net recently. The file msfile.asm will not assemble on the hp150. Two of the errors seem to be related to addressing modes (LEA instructions), but the rest were undefined symbols. The file seems to be corrupted in the data declaration section. PLEASE! If anyone has a good copy of this file, will you send me a copy? Thanks in advance... Bill Nestor hp St. Louis ihnp4!wuphys!hp2610!wdn