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