MS-DOS Kermit sources (Part 1 of 7)
Jim Knutson
knutson at ut-ngp.UUCP
Sat Oct 6 02:02:50 AEST 1984
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
fi
More information about the Comp.sources.unix
mailing list