home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
kermit.columbia.edu
/
kermit.columbia.edu.tar
/
kermit.columbia.edu
/
archives
/
ccdos.zip
/
ccsfil.asm
< prev
next >
Wrap
Assembly Source File
|
1991-09-08
|
101KB
|
2,134 lines
NAME ccsfil
; Fle CCSFIL.ASM
;CHINESE
ifdef MSDOS
include mssfil.dat
else
include ccsfil.dat
endif
code segment public 'code'
extrn spack:near, cmblnk:near, locate:near, decout:near, comnd:near
extrn putmod:near, poscur:near, clearl:near, isfile:near
assume cs:code, ds:datas
; Position cursor for an error message
ERPOS PROC NEAR
test flags.remflg,dquiet ; quiet screen?
jnz erpx ; nz = yes
push dx ; save any preexisting message pointer
test flags.remflg,dserial ; serial mode display?
jnz erpo1 ; nz = yes
test flags.remflg,dserver ; are we a server
jnz erp0 ; nz = yes, and display is regular
cmp flags.xflg,1 ; Packet header seen?
jne erp0 ; No, do as normal
erpo1: mov dx,offset crlf
mov ah,prstr
int dos
mcmsg erword ,cerword ; put out word Error
int dos
pop dx ; restore old pointer
ret
erp0:
; mov dx,screrr
mcscr screrr,cscrerr
call poscur
pop dx ; restore old pointer
erpx: ret
ERPOS ENDP
; Position cursor for number of retries message
RTPOS PROC NEAR
test flags.remflg,dquiet ; quiet display mode?
jnz rtpx ; nz = yes
test flags.remflg,dserver ; in server mode?
jnz rtp0 ; nz = yes
cmp flags.xflg,1 ; Packet header seen?
jne rtp0 ; No, do as normal
ret
rtp0: test flags.remflg,dserial ; serial mode display?
jnz rtp1 ; nz = yes
; mov dx,scrnrt
mcscr scrnrt,cscrnrt
call poscur
jmp clearl
rtp1: mcmsg rtword,crtword ; display word Retry
mov ah,prstr
int dos
rtpx: ret
RTPOS ENDP
; Reassure user that we acknowledge his ^X/^Z
INTMSG PROC NEAR
cmp fmtdsp,0 ; non-formatted screen?
je int5 ; e = yes
test flags.remflg,dserver ; server mode?
jnz int4 ; nz = yes
cmp flags.xflg,0 ; Writing to screen?
jne int1 ; Yes. Don't do anything
int4: test flags.remflg,dquiet ; quiet screen?
jnz int1 ; yes, supress msg
test flags.remflg,dserial ; serial mode display?
jz int2 ; ne = no
int5: mov dx,offset crlf ; yes. output initial cr/lf
mov ah,prstr
int dos
jmp int3 ; display the message
int2:
; mov dx,scrint
mcscr scrint,cscrint
call poscur
call clearl
int3: mcmsg infms7,cinfms7 ; File interrupted?
cmp flags.cxzflg,'X' ; Yes.
je int0
mcmsg infms8,cinfms8 ; File group interrupted?
cmp flags.cxzflg,'Z'
je int0
cmp flags.cxzflg,'C' ; just a control-C?
je int1 ; e = yes, suppress msg
mov dl,flags.cxzflg
mov infms9+6,dl ; store interrupt code letter
mcmsg infms9, cinfms9
int0: mov ah,prstr
int dos
int1: ret
INTMSG ENDP
; Print error message that a high bit set char was found in the file
BITERR PROC NEAR
test flags.remflg,dquiet ; remote mode?
jnz biter1 ; nz = yes, no printing
push bx
cmp fmtdsp,0 ; non-formatted display?
je biter3 ; e = yes
test flags.remflg,dserial ; serial mode display?
jz biter2 ; z = no
mov ah,prstr ; display an initial cr/lf
mov dx,offset crlf
int dos
jmp biter3
biter2:
; mov dx,scrhi
mcscr scrhi,cscrhi
call poscur
call clearl
biter3: mov ah,prstr
mcmsg hibit,chibit
int dos
pop bx
biter1: ret
BITERR ENDP
; Clear out message about interrupted file
CXMSG PROC NEAR
test flags.remflg,dserver ; server mode?
jnz cxm1 ; nz = yes
cmp flags.xflg,0 ; Writing to screen?
jne cxm0 ; Yes. Don't do anything
cxm1: test flags.remflg,dquiet+dserial ; quiet or serial display?
jnz cxm0 ; nz = yes
; mov dx,scrint
mcscr scrint,cscrint
call poscur
call clearl
cxm0: ret
CXMSG ENDP
; Clear out the old filename on the screen.
CLRFLN PROC NEAR
test flags.remflg,dquiet ; quiet display?
jnz clrflnx ; nz = yes
test flags.remflg,dserial ; serial display mode?
jnz clrfln1 ; nz = yes, use just cr/lf
; mov dx,scrfln
mcscr scrfln,cscrfln
call poscur
call clearl ; Clear to end of line
ret
clrfln1:push ax ; for serial display, does cr/lf
mov ah,prstr
mov dx,offset crlf
int dos
pop ax
clrflnx:ret
CLRFLN ENDP
PKTSIZE PROC NEAR ; display packet size
cmp fmtdsp,0 ; formatted display?
je pktsiz3 ; e = no, no display
push ax
push dx
mov ax,pack.datlen ; packet size (data part)
add al,trans.chklen ; plus checksum
adc ah,0
add ax,3 ; plus LEN, SEQ, TYPE
cmp ax,94 ; larger than Regular?
jbe pktsiz1 ; be = no
add ax,3 ; add Long Packet len and chksum
pktsiz1:cmp ax,prepksz ; same as previous packet?
je pktsiz2 ; e = yes, skip display
mov prepksz,ax ; remember new value
push ax
; mov dx,scrsz ; position cursor
mcscr scrsz,cscrsz
call poscur
call clearl ; clear to end of line
pop ax
call decout ; show packet length
pktsiz2:pop dx
pop ax
pktsiz3:ret
PKTSIZE ENDP
; some random screen positioning functions
kbpos:
; mov dx,scrkb ; KBytes transferred
mcscr scrkb,cscrkb
test flags.remflg,dquiet+dserial ; quiet or serial display mode?
jnz kbpos1
jmp setup2 ; z = no
kbpos1: ret ; else ignore postioning request
perpos:
; mov dx,scrper ; Percent transferred
mcscr scrper,cscrper
test flags.remflg,dquiet+dserial ; quiet or serial display mode?
jnz perpos1
jmp setup2 ; z = no
perpos1: ret ; else ignore postioning request
frpos:
; mov dx,scrfr ; Say renamed file
mcscr scrfr,cscrfr
jmp setup2
stpos:
; mov dx,scrst ; Print status of file transfer
mcscr scrst,cscrst
jmp setup2
nppos:
; mov dx,scrnp ; Number of packets sent
mcscr scrnp,cscrnp
test flags.remflg,dquiet+dserial ; quiet or serial display mode?
jz setup1 ; z = no
ret
rprpos:
; mov dx,scrrpr ; Reprompt position
mcscr scrrpr,cscrrpr
call setup1 ; position cursor
mov fmtdsp,0 ; turn off formatted display flag
ret
nrtpos:
; mov dx,scrnrt ; Number of retries
mcscr scrnrt,cscrnrt
jmp short setup2
sppos:
; mov dx,scrsp ; Send packet location
mcscr scrsp,cscrsp
jmp short setup1
rppos:
; mov dx,scrrp ; Receive packet location
mcscr scrrp,cscrrp
jmp short setup1
; common service routines for positioning
setup1: test flags.remflg,dquiet+dserial; quiet or serial display mode?
jnz setupa ; nz = yes
cmp fmtdsp,0 ; non-formatted display?
je setupa ; e = yes
jmp poscur
setup2: test flags.remflg,dquiet+dserial; quiet or serial display mode?
jnz setupa ; nz = yes
cmp fmtdsp,0 ; non-formatted display?
je setupa ; e = yes
call poscur ; no
jmp clearl
setupa: test flags.remflg,dquiet ; quiet mode?
jnz setupx ; nz = yes, do nothing
push ax ; display cr/lf and return
push dx
mov dx,offset crlf
mov ah,prstr
int dos
pop dx
pop ax
setupx: ret
; Start recording of statistics for this operation. [jrd]
begtim proc near
test sflag,80h ; is this a duplicate call?
jz begtim1 ; z = no
ret ; else just return
begtim1:push ax
push cx
push dx
xor ax,ax ; clear statistics counters for this file
mov fsta.prbyte,ax ; bytes received from serial port
mov fsta.prbyte+2,ax
mov fsta.psbyte,ax ; bytes sent out serial port
mov fsta.psbyte+2,ax
mov fsta.frbyte,ax ; bytes received for this file
mov fsta.frbyte+2,ax
mov fsta.fsbyte,ax ; bytes sent for this file
mov fsta.fsbyte+2,ax
mov fsta.prpkt,ax ; packets received for this file
mov fsta.prpkt+2,ax
mov fsta.pspkt,ax ; packets sent for this file
mov fsta.pspkt+2,ax
mov fsta.nakrcnt,ax ; NAKs received for this file
mov fsta.nakscnt,ax ; NAKs sent for this file
mov fsta.xstatus,al ; clear status byte
mov ah,getdate ; get current date, convert to ascii
int dos
mov date+9,'0' ; init day of month
begtim2:cmp dl,10 ; day of month. Ten or more days?
jl begtim3 ; l = no
sub dl,10
inc date+9 ; add up tens of days
jmp short begtim2 ; repeat for higher order
begtim3:add dl,'0' ; ascii bias
mov date+10,dl ; day units
mov dl,dh ; months (1-12)
dec dl ; start at zero to index table
mov dh,0
mov di,dx ; months
shl di,1
add di,dx ; times three chars/month
mov al,months[di] ; get text string for month
mov date+12,al
mov ax,word ptr months[di+1]
mov word ptr date+13,ax
mov ax,cx ; year since 1980
mov dx,0
mov di,offset date+16 ; destination
call lnout ; convert number to asciiz in buffer
; start time
mov ah,gettim ; DOS time of day, convert to ascii
int dos
mov fsta.btime,dx ; store ss.s low word of seconds
mov fsta.btime+2,cx ; store hhmm high word of seconds
mov date,'0' ; init begin hours field
begtim4:cmp ch,10 ; ten or more hours?
jl begtim5 ; l = no
sub ch,10
inc date ; add up tens of hours
jmp short begtim4 ; repeat for twenties
begtim5:add ch,'0' ; ascii bias
mov date+1,ch ; store units of hours
mov date+3,'0' ; minutes field
begtim6:cmp cl,10 ; ten or more minutes?
jl begtim7 ; l = no
sub cl,10
inc date+3 ; add up tens of minutes
jmp short begtim6 ; repeat for higher orders
begtim7:add cl,'0' ; ascii bias
mov date+4,cl ; store units of minutes
mov date+6,'0' ; seconds field
begtim8:cmp dh,10 ; ten or more seconds?
jl begtim9 ; l = no
sub dh,10
inc date+6 ; add up tens of seconds
jmp short begtim8 ; repeat for higher orders
begtim9:add dh,'0' ; ascii bias
mov date+7,dh
mov sflag,80h ; say begtim has been run
pop dx
pop cx
pop ax
ret
begtim endp
; Take snapshot of statistics counters at end of an operation
; Enter with ax = 0 for a receive operation, ax = 1 for a send. [jrd]
endtim proc near
test sflag,80h ; called more than once without calling begtim?
jnz endtim1 ; ne = no, so do statistics snapshot
ret ; yes, do nothing
endtim1:and sflag,not (1) ; assume receive operation
or ax,ax ; send (ax > 0), receive (ax = 0) flag
jz endtim2 ; z = receive opeation
or sflag,1 ; say send operation
endtim2:
push ax
push cx
push dx
mov ah,gettim ; get DOS time of day
int dos
mov fsta.etime,dx ; store ss. s
mov fsta.etime+2,cx ; hhmm
cmp cx,fsta.btime+2 ; end time less than start time?
ja endtim2a ; a = above (no need to test low order word)
cmp dx,fsta.btime ; be. How about low order word
jae endtim2a ; ae = no wrap around of time
add ch,24 ; add one day to hours field
endtim2a:sub dl,byte ptr fsta.btime ; 0.01 sec difference
jns endtim2b
dec dh ; borrow a second
add dl,100 ; make difference positive
endtim2b:sub dh,byte ptr fsta.btime+1; seconds difference
jns endtim2c
dec cl ; borrow a minute
add dh,60 ; make difference positive
endtim2c:mov bh,0
mov bl,dh ; bx has seconds difference
sub cl,byte ptr fsta.btime+2 ; minutes
jns endtim2d
dec ch ; borrow an hour
add cl,60
endtim2d:mov al,cl
mov ah,0
mul sixty ; minutes to seconds
add bx,ax ; seconds to bx
sub ch,byte ptr fsta.btime+3 ; hours difference
jns endtim2e
add ch,24
endtim2e:mov al,ch
mov ah,0
mul sixty ; hours to minutes in ax
mul sixty ; minutes to seconds in dx,ax
add ax,bx ; ax = seconds
adc dx,0 ; dx = high word of seconds
mov fsta.etime,ax ; store elapsed time, seconds, low wd
mov fsta.etime+2,dx ; high word
add ssta.etime,ax ; add to session time, low word
adc ssta.etime+2,dx ; add to session time, high word
mov ax,fsta.prbyte ; port bytes received for this file
add ssta.prbyte,ax ; port bytes received for this session
mov ax,fsta.prbyte+2 ; high word
adc ssta.prbyte+2,ax
mov ax,fsta.psbyte ; port bytes sent for this file, low word
add ssta.psbyte,ax ; port bytes sent for this session, low word
mov ax,fsta.psbyte+2 ; high word
adc ssta.psbyte+2,ax
test sflag,1 ; completing a receive operation?
jnz endtim3 ; nz = no, a send operation
mov ax,tfilsz+2 ; file bytes received, low word
mov fsta.frbyte,ax
add ssta.frbyte,ax ; session received file bytes, low word
mov ax,tfilsz ; high word
mov fsta.frbyte+2,ax
adc ssta.frbyte+2,ax
jmp short endtim4
endtim3:mov ax,tfilsz+2 ; file bytes sent, low word
mov fsta.fsbyte,ax ; file bytes sent
add ssta.fsbyte,ax ; session sent file bytes, low word
mov ax,tfilsz ; high word
mov fsta.fsbyte+2,ax
adc ssta.fsbyte+2,ax
endtim4:mov ax,fsta.prpkt ; packets received for this file
add ssta.prpkt,ax ; session received packets
mov ax,fsta.prpkt+2
adc ssta.prpkt+2,ax
mov ax,fsta.pspkt ; packets sent for this file
add ssta.pspkt,ax ; session sent packets
mov ax,fsta.pspkt+2
adc ssta.pspkt+2,ax
mov ax,fsta.nakrcnt ; NAKs received for this file
add ssta.nakrcnt,ax ; session received NAKs
mov ax,fsta.nakscnt ; NAKs sent for this file
add ssta.nakscnt,ax ; session sent NAKs
; do transaction logging
cmp tloghnd,0 ; logging transaction? -1 = not opened
jg endtim5 ; g = logging
jmp endtim12 ; skip logging
endtim5:push di ; kind of transaction
push bx ; save these registers
mov bx,tloghnd ; handle for transaction log
mov dx,offset rcvmsg ; assume receive message
test sflag,1 ; 1 for send, 0 for receive
jz endtim6 ; z = receive
mov dx,offset sndmsg ; send message
endtim6:call strlen ; length of message to cx
mov ah,write2
int dos ; write kind of transfer
; File names
cmp diskio.string,0 ; local filename
je endtim9 ; e = no filename
test sflag,1 ; a send operation?
jnz endtim8 ; nz = yes
; Receive
mov dx,offset fsta.xname ; remote name
call strlen ; length to cx
jcxz endtim7 ; no name
mov ah,write2
int dos
mov dx,offset diskio.string ; local name
call strlen ; length to cx
mov si,offset fsta.xname ; compare these two names
mov di,dx
push ds
pop es
repe cmpsb ; compare
je endtim9 ; e = same, so no 'as' msg
mcmsg fasmsg,cfasmsg ; give 'as' message
mov cx,faslen ; length
mov ah,write2
int dos
endtim7:mov dx,offset diskio.string ; local name
call strlen ; get length
mov ah,write2 ; write local name
int dos
jmp short endtim9
endtim8:mov dx,offset diskio.string ; Send. local name
call strlen
mov ah,write2
int dos
cmp fsta.xname,0 ; using an alias?
je endtim9 ; e = no
; mov dx,offset fasmsg ; give 'as' message
mcmsg fasmsg,cfasmsg
mov cx,faslen
mov ah,write2
int dos
mov dx,offset fsta.xname ; get alias
call strlen
mov ah,write2
int dos
; status of transfer
endtim9:mov dx,offset atmsg ; say At
mov cx,atlen ; length
mov bx,tloghnd ; handle
mov ah,write2
int dos
mov dx,offset date ; write time and date field
mov cx,datelen ; length
mov ah,write2
int dos
mcmsg fsucmsg ,cfsucmsg ; assume success message
cmp fsta.xstatus,0 ; 0 = completed?
je endtim10 ; e = completed
mcmsg fbadmsg,cfbadmsg ; failed message
test fsta.xstatus,80h ; interrupted?
jz endtim10 ; z = no
mcmsg fintmsg, cfintmsg ; interrupted message
endtim10:call strlen ; get length to cx
mov ah,write2
int dos
; file bytes transferred
mov ax,tfilsz+2 ; file bytes, low word
mov dx,tfilsz ; high word
mov di,offset temprp ; work buffer
call lnout ; transform to ascii
mov [di],0a0dh ; append cr/lf
add di,2 ; count them
mov dx,offset temprp ; start of work buffer
mov cx,di ; next free byte
sub cx,dx ; compute length
mov ah,write2
int dos
pop bx
pop di
endtim12:mov tfilsz,0 ; clear file size area
mov tfilsz+2,0
mov sflag,0 ; say have done ending once already
mov fsta.xname,0 ; clear statistics "as" name
pop dx
pop cx
pop ax
ret
endtim endp
; SHOW STATISTICS command. Displays last operation and session statistics
; 9 March 1987 [jrd]
shosta proc near ; show file transfer statistics
mov ah,cmcfm ; confirm with carriage return
call comnd
ret ; not confirmed
nop
nop
call endtim ; update statistics, just in case
push bx
push cx
push dx
mov bx,offset fsta ; pointer to file (Last op) statistics
mov cx,2 ; two sets to display
shosta0:push cx ; save loop counter
cmp cx,2 ; doing Last operation set?
;--Pay attention to the next instructon ' je ... '(eflag), Sept.14,1990[zqf]
; mov cx,offset lastmsg ; totals for last transfer
pushf
mcmsgc lastmsg,clastmsg
popf
je shosta1 ; e = yes
;-----------
mov bx,offset ssta ; point to Session statistics area
; mov cx,offset sessmsg ; totals for whole session
mcmsgc sessmsg,csessmsg
shosta1:
mov ax,[bx].etime ; elapsed time of operation
mov dx,[bx].etime+2
call shoprt ; show result
; mov cx,offset pinmsg ; port bytes received
mcmsgc pinmsg,cpinmsg
mov ax,[bx].prbyte
mov dx,[bx].prbyte+2
call shoprt ; show result
; mov cx,offset poutmsg ; port bytes sent
mcmsgc poutmsg,cpoutmsg
mov ax,[bx].psbyte
mov dx,[bx].psbyte+2
call shoprt ; show result
; mov cx,offset finmsg ; file bytes received
mcmsgc finmsg,cfinmsg
mov ax,[bx].frbyte
mov dx,[bx].frbyte+2
call shoprt ; show result
; mov cx,offset foutmsg ; file bytes sent
mcmsgc foutmsg,cfoutmsg
mov ax,[bx].fsbyte
mov dx,[bx].fsbyte+2
call shoprt ; show result
; mov cx,offset pkimsg ; packets received
mcmsgc pkimsg,cpkimsg
mov ax,[bx].prpkt
mov dx,[bx].prpkt+2
call shoprt ; show result
; mov cx,offset pkomsg ; packets sent
mcmsgc pkomsg,cpkomsg
mov ax,[bx].pspkt
mov dx,[bx].pspkt+2
call shoprt ; show result
; mov cx,offset nakimsg ; naks received
mcmsgc nakimsg,cnakimsg
mov ax,[bx].nakrcnt
xor dx,dx
call shoprt ; show result
; mov cx,offset nakomsg ; naks sent
mcmsgc nakomsg,cnakomsg
mov ax,[bx].nakscnt
xor dx,dx
call shoprt
; compute baud rate as 10 * total port bytes / elapsed time
mov ax,[bx].prbyte ; port bytes received, low
mov dx,[bx].prbyte+2 ; port bytes received, high
add ax,[bx].psbyte ; port bytes sent, low
adc dx,[bx].psbyte+2 ; high. [dx,ax] = total port bytes
mov cx,[bx].etime ; low word of sec in cx
cmp [bx].etime+2,0 ; is high word of sec zero (e.t. < 65536 sec)?
jz shosta3 ; z = yes, ready for arithmetic
push ax ; else scale values, save byte count
push dx
mov ax,[bx].etime ; elapsed time for file, low word
mov dx,[bx].etime+2 ; high word
shr ax,1 ; divide seconds by two, low word
ror dx,1 ; get low bit of high word
and dx,8000 ; pick out just that bit
or ax,dx ; mask in that bit, new time in ax (dx = 0)
mov cx,ax ; save elapsed time (double-seconds)
pop dx ; get byte count again
pop ax
shr ax,1 ; divide byte count by two also
push dx
ror dx,1 ; rotate low bit to high position
and dx,8000h ; get low bit of high word
or ax,dx ; byte count divided by two, low word
pop dx
shr dx,1 ; and high word
shosta3:or cx,cx ; is elapsed time (in cx) zero seconds?
jnz shosta4 ; nz = no
inc cx ; set time to one second (no div by 0)
shosta4:div cx ; bytes div seconds, ax = quo, dx = rem
push dx ; save remainder of bytes/second
mul ten ; quotient times ten to dx,ax
pop dx ; discard overflow, recover remainder
push ax ; save partial baud rate
xchg ax,dx ; remainder to ax
xor dx,dx ; clear extension
mul ten ; remainder times ten too (keep only overflow)
pop ax ; recover main partial result
add ax,dx ; add two partial results
xor dx,dx ; clear extension ( < 65536 baud )
; mov cx,offset baudmsg
mcmsgc baudmsg,cbaudmsg
call shoprt ; show result
pop cx ; recover loop counter
dec cx
jcxz shostax ; cx = 0 means we are done
jmp shosta0 ; do next set of statistics (session stuff)
shostax:
pop dx
pop cx
pop bx
jmp rskp
shosta endp
; Print show statistics line. Enter with CX=offset of initial message,
; dx,ax with long value
shoprt proc near
push ax
push dx
mov dx,cx ; setput initial print
mov ah,prstr ; display title line (dx is ptr)
int dos
pop dx
pop ax
push di
mov di,offset temprp ; work space for output
call lnout ; show long integer
pop di
mov dx,offset temprp
call prtasz ; print asciiz string
ret
shoprt endp
; LNOUT - Table driven unsigned long integer (32 bit) display
; Register dx holds high order word and ax holds low order word of unsigned
; long integer to be stored in decimal. Storage area is given by DS:[DI]
; DI is incremented for each storage, null terminated
; Table TENS holds set of double word values of ten raised to powers 0 to 9
; TENSLEN holds the number of these double words
; All registers preserved. 8 March 1987 [jrd]
lnout proc near
push ax
push bx
push cx
push dx
push si
xor si,si ; flag to say start printing (no leading 0's)
mov cx,tenslen ; number of table entries
lnout1: push cx ; save loop counter
mov bx,cx ; index into tens double word table
dec bx ; index starts at zero
add bx,bx
add bx,bx ; bx times four (double words to bytes)
xor cx,cx ; cx is now a counter of subtractions
lnout2: cmp dx,word ptr tens[bx+2] ; pattern 10**(bx/4), high order part
jb lnout4 ; b = present number is less than pattern
ja lnout3 ; a = present number is larger than pattern
cmp ax,word ptr tens[bx] ; high words match, how about lows
jb lnout4 ; b = present number is smaller than pattern
lnout3: sub ax,word ptr tens[bx] ; subtract low order words
sbb dx,word ptr tens[bx+2] ; subtract high order words, w/borrow
inc cl ; count number of subtractions
inc si ; flag to indicate printing needed
jmp lnout2 ; try again to deduct present test pattern
lnout4: or bx,bx ; doing least significant digit?
jz lnout5 ; z = yes, always print this one
or si,si ; should we print?
jz lnout6 ; z = no, not yet
lnout5: add cl,'0' ; get number of subtractions
mov [di],cx ; store it (ch is still zero), asciiz
inc di
lnout6: pop cx ; recover loop counter
loop lnout1
pop si
pop dx
pop cx
pop bx
pop ax
ret
lnout endp
; Initialize buffers and clear line
INIT PROC NEAR
mov hierr,0 ; clear high-bit-seen flag
test flags.remflg,dquiet ; quiet display mode?
jnz init3 ; nz = yes
test flags.remflg,dserial ; serial mode display?
jnz init2 ; nz = yes
call cmblnk
mcmsg cxzhlp,ccxzhlp
call putmod ; write mode line
mov fmtdsp,1 ; say doing formatted display
test flags.remflg,dserver ; server mode?
jz init1 ; z = no
; mov dx,scrser ; move cursor to top of screen
mcscr scrser,cscrser
call poscur
mov ah,prstr
mcmsg infms1,cinfms1 ; say now in server mode
int dos
init1: call locate
mov ah,prstr ; Put statistics headers on the screen
mcmsg outlin, coutlin
int dos
mov wrpmsg,0 ; haven't printed the messsage yet
mov prepksz,0 ; set previous packet size to zero
ret
init2: mov ah,prstr ; print string
mcmsg cxzser,ccxzser ; status line as a text string
int dos
init3: mov wrpmsg,1 ; suppress display of percentage msg
mov fmtdsp,0 ; say doing unformatted display
ret
INIT 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
mov ax,offset outbuf ; routine to call when buffer gets full
mov chrcnt,maxpack ; size of buffer Data
mov bufpnt,offset decbuf ; decoded data placed here pending output
mov bx,offset data ; source of data
jmp short 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 repeat count
cmp cx,0 ; any more chars in source?
jg decod2 ; g = yes
jmp decod6 ; Else, we're through
decod2: cld ; forward direction
lodsb ; Pick up a char
dec cx ; count number left
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,0 ; Assume no 8-bit quote char
cmp al,dh ; This the 8-bit quot char?
jne decod3 ; ne = no
lodsb ; Get the real character
dec cx ; Decrement # chars in packet
mov ah,80H ; Turn on 8-bit quot char flag
decod3: cmp al,trans.squote ; Is it the quote char?
jne decod4 ; ne = no, 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?
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
cmp al,3fh ; char less than '?' ?
jl decod4 ; l = yes; leave it intact
cmp al,5fh ; char greater than '_' ?
jg decod4 ; g = yes; leave it alone
add al,40H ; Make it a control char again
and al,7FH ; Modulo 128
decod4: or al,ah ; or in parity
dcod41: stosb ; store the character
dec rptct ; Repeat counter
dec chrcnt ; Decrement number of chars in dta
cmp chrcnt,0 ; space left in output buffer?
jg dcod42 ; g = yes
push ax ; Save the char
push cx ; flush output buffer
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
pop ax ; recover repeated char
dcod42: cmp rptct,0 ; Write out char again?
jg dcod41 ; g = yes
jmp decod1 ; No, get 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 ; store address for next output char
push cx
push dx
push bx
call bx ; flush output buffer before final ret
jmp decod5 ; Error return if disk is full
nop
pop bx
pop dx
pop cx
pop dx
pop es
pop di
pop si
jmp rskp ; Return successfully if done
; output the buffer, reset bufpnt and chrcnt
outbuf: mov cx,maxpack ; get full size of buffer
sub cx,chrcnt ; minus space remaining = # to write
jnc outbu7
jmp outbf0 ; c = bad buffer pointers
outbu7: jnz outbu6
jmp outb11 ; cx = 0 means nothing to do
outbu6: cmp flags.xflg,1 ; Writing to screen?
jne outbu0
jmp outbf2 ; Yes, handle specially
outbu0:
mov cx,maxpack ; get full size of buffer
sub cx,chrcnt ; minus space remaining = # to write
jc outbf0 ; c = bad buffer pointers
jnz outbu1
jmp outb11 ; cx = 0 means nothing to do
outbu1: push bx
mov dx,offset decbuf ; address of buffer
cmp flags.destflg,1 ; disk destination?
je outbu5 ; e = yes
cmp flags.eofcz,0 ; end on Control-Z?
jne outbu5 ; ne = yes, let DOS do it
push cx ; else map Control-Z to space
push di
push es
push ds
pop es ; datas to es
mov di,dx ; scan buffer es:di, cx chars worth
mov al,ctlz ; look for Control-Z
cld
outbu3: repne scasb
jne outbu4 ; ne = found no Control-Z's
mov byte ptr [di-1],' ' ; replace Control-Z with space
jcxz outbu4 ; z = examined all chars
jmp short outbu3 ; until examined everything
outbu4: pop es
pop di
pop cx
outbu5: mov bx,diskio.handle ; file handle
mov ah,write2 ; DOS 2.0 write
int dos ; Write the record
pop bx
jc outbf0 ; c set means disk writing error
cmp ax,cx ; did we write all the bytes?
je outbf1 ; e = yes
call erpos ; no
mcmsg erms11,erms11 ; Disk full error
cmp flags.destflg,1 ; writing to disk?
je outbu0a ; e = yes
push bx
mov bx,offset decbuf
add bx,ax ; look at break character
cmp byte ptr [bx],ctlz ; ended on Control-Z?
pop bx
je outbf1 ; e = yes, say no error
mcmsg ermes9,cermes9 ; Printer not ready message
outbu0a:mov ah,prstr ; Tell about it
int dos
jmp abfil ; Fix things up before aborting
outbf0: call erpos
mov ah,prstr ; Tell about it
mcmsg erms13,cerms13 ; Disk writing error
cmp flags.destflg,0 ; writing to printer?
jne outbf0a ; ne = no
; mov dx,offset ermes9 ; Printer not ready message
mcmsg ermes9,cermes9
outbf0a:int dos
jmp abfil ; Fix things up before aborting
outbf1: add tfilsz+2,cx ; count received chars
adc tfilsz,0
test flags.remflg,dserial ; serial mode display?
jnz outb11 ; nz = yes, skip kbyte and % displays
call kbpr ; Print the kilobytes received
call perpr ; Print the percent
outb11: mov bufpnt,offset decbuf ; Addr for beginning
mov chrcnt,maxpack ; size of empty buffer
jmp rskp
outbf2: ; writing to screen
mov cx,maxpack ; size of full buffer
sub cx,chrcnt ; minus # of unused in buffer
jle outb11 ; none to print, don't try
add tfilsz+2,cx ; count received chars
adc tfilsz,0
mov di,offset decbuf ; Where they are
call prtscr ; Output buffer to screen
jmp outb11 ; Reset counter & pointer
; Tidy up before aborting. Retidied by [jrd]
ABFIL PROC NEAR
cmp flags.xflg,1 ; Writing to screen?
je abfil1 ; Yes don't delete "file"
mov bx,diskio.handle ; get file handle
cmp bx,4 ; writing to DOS set of files?
jbe abfil1 ; be = yes, never close them
mov ah,close2 ; DOS 2.0 file close
int dos
cmp flags.abfflg,1 ; Delete what got across or keep it?
jne abfil1 ; Nope, keep it
push dx
mov dx,offset diskio.string ; the full file name
mov ah,del2 ; DOS 2.0 file delete
int dos
pop dx
abfil1: mcmsg erms10, cerms10 ; 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
ERRPACK PROC NEAR
push di
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: pop di
mov ah,0
mov pack.datlen,ax
mov ah,'E' ; And send an error packet
call spack
nop ; 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?
je gtchr0 ; e = yes, 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: mov bx,offset 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 cx,trans.maxdat ; Maximum packet size
push ds
pop es ; make es:di point to datas segment
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: cmp cx,0 ; any space left in output buffer?
jg encod2 ; g = yes
sub di,offset filbuf
mov ax,di
mov bufpnt,si ; update pointer into DMA
jmp rskp
encod2: cmp chrcnt,0 ; Any data in buffer?
jg 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: dec chrcnt ; Decrement input count
cld ; forward direction
lodsb
cmp flags.eofcz,0 ; Is a control-z an end of file?
je encd30 ; No, don't have to look for one
cmp al,'Z'-40H ; Is this a control-Z?
jne encd30 ; No, skip eof-processing
mov flags.eoflag,0FFH ; Yes, set eof flag
mov flags.filflg,0FFH ; No more input in buffer
mov chrcnt,0 ; Ditto
jmp encod8 ; Go set character count and return
encd30: 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
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
mov al,rptq
mov origr,al ; Save original repeat prefix
mov rptq,0 ; Pretend we're not doing 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 ; e = no, forget this
test al,80h ; parity on?
je encod4 ; no, don't bother with this
and al,7fh ; turn off parity
mov ah,trans.ebquot ; get quote char
mov [di],ah ; put in packet
inc di
dec cx ; decrement # of chars left
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?
je encod5 ; e = yes, go quote it
cmp al,dl ; Is it the quote char?
je encod6 ; e = yes, go add it
cmp dh,0 ; are we doing 8-bit quoting?
je encd41 ; e = no, don't translate it
cmp al,trans.ebquot ; Is it the 8-bit quote char?
je encod6 ; e = yes, just output with quote
encd41: cmp origr,0 ; Doing repeat prefixing?
je encod7 ; e = no, don't check for quote char
cmp al,origr ; Is this the repeat quote character
je encod6 ; e = yes, then quote it
jmp short encod7 ; else don't quote it
encod5: xor al,40h ; control char, uncontrollify
encod6: mov [di],dl ; insert control quote char
inc di
dec cx
encod7: or al,ah ; put parity back
stosb
dec cx ; Decrement output buffer counter
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 ; buffer empty?
je encod9 ; e = yes
mov ax,di ; report size encoded
jmp rskp ; return success
encod9: mov ax,-1 ; Get a minus one
ret ; return failure
inbuf: cmp flags.eoflag,0 ; Have we reached the end?
jz inbuf0
ret ; Return if set
inbuf0: push si
push dx
push bx
push cx
mov bx,offset buff ; Set the r/w buffer pointer
mov bufpnt,bx
mov bx,diskio.handle ; get file handle
mov cx,buffsz ; record size
mov dx,bufpnt ; buffer address
mov ah,readf2 ; DOS 2.0 read a record
int dos
jc inbuf1 ; c = error, ie file not open
or ax,ax ; any bytes read?
jne inbuf2 ; ne = yes (the number read)
inbuf1: mov flags.eoflag,0FFH ; Set End-of-file
mov flags.filflg,0ffh ; Buffer empty
mov chrcnt,0 ; zero bytes left in buffer
pop cx
pop bx
pop dx
pop si
ret
inbuf2: add tfilsz+2,ax ; total the # bytes transferred so far
adc tfilsz,0 ; it's a double word
mov chrcnt,ax ; Number of chars read from file
mov flags.filflg,0 ; Buffer not empty
test flags.remflg,dserial ; serial display mode?
jnz inbuf3 ; nz = yes, skip kbyte and % display
push ax
call kbpr ; Print the kilobytes sent
call perpr ; Print the percent sent
pop ax
inbuf3: pop cx
pop bx
pop dx
pop si
jmp rskp
nulref: mov chrcnt,0 ; No data to return
jmp rskp
nulr: ret ; dummy buffer emptier
; Print the number of Kilobytes transferred
kbpr: test flags.remflg,dquiet ; quiet display mode?
jnz kbpr1 ; nz = yes, no printing
push bx
mov ax,tfilsz+2 ; low order word
mov bx,tfilsz ; high order word
add ax,512 ; round up, add half the denominator
adc bx,0
mov al,ah ; divide double word by 1024, in steps
mov ah,bl
shr ax,1
shr ax,1
ror bh,1
ror bh,1
and bh,not (3fh)
or ah,bh ; ax has the result
pop 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 decout ; Print number of KBytes transferred
kbpr1: ret
; Print the percent transferred
perpr: test flags.remflg,dquiet ; quiet display mode?
jz perpr1 ; z = no. allow printing
ret ; skip printing in remote mode
perpr1: cmp ofilsz,0 ; high word of original file size > 0 ?
jne perpr3 ; ne = yes, use big file code
cmp ofilsz+2,0 ; anything here at all?
jne perpr2 ; ne = yes, use small file code
ret ; otherwise, quit now
perpr2: push dx ; case for files < 64 Kb
mov ax,ofilsz+2 ; original size (low word)
mov denom,ax
mov dx,tfilsz ;transferred size times 256 in [dx,ax]
mov ax,tfilsz+2
mov dh,dl ; whole value multiplied by 256
mov dl,ah
mov ah,al
mov al,0
mov cx,denom ; round up, add half the denominator
shr cx,1
add ax,cx
adc dx,0
div denom ; (256*xfer)/orig. ax = quo, dx = rem
mul onehun ; multiply quotient above by 100
mov al,ah ; divide result (ax) by 256
mov ah,0 ; percentage is in ax
jmp perpr4 ; finish in common code
perpr3: push dx ; case for file size > 64 KB
mov ax,ofilsz+2 ; original file size low order word
shr ax,1 ; divide by 2
mov al,ah ; divide again by 256 for total of 512
mov ah,0 ; clear ah
mov dx,ofilsz ; high order word
xchg dh,dl ; do shl dx,cl=7
ror dx,1 ; old low bit of dh to high bit of dh
and dl,80h ; clear lower bits. divided by two
or ax,dx ; paste together the two parts into ax
mov denom,ax ; denom = original size divided by 512
mov dx,tfilsz ; high order word of transferred size
mov ax,tfilsz+2 ; low order word
mov cx,denom ; round up, add half the denominator
shr cx,1
add ax,cx
adc dx,0
div denom ; xfer/(512*orig). ax=quot, dx=rem
mul onehun ; times 100 for 512*percentage, in ax
mov al,ah ; divide ax by 512
mov ah,0
shr ax,1 ; final percentage, in ax
perpr4: pop dx
cmp ax,oldper ; same as it was before?
je perpr7 ; yes, don't bother printing
mov oldper,ax ; remember this for next time
cmp wrpmsg,0 ; did we write the percentage message?
jne perpr5 ; ne = yes, skip this part
push ax
call perpos ; position cursor
mcmsg permsg,cpermsg
mov ah,prstr
int dos ; write out message
pop ax
mov wrpmsg,1 ; init flag so we don't do it again
perpr5: push ax
call perpos ; Position the cursor
pop ax
cmp ax,onehun ; > 100% ?
jle perpr6 ; no, accept it
mov ax,onehun ; else just use 100
perpr6: call decout
mov dl,25h ; Load a percent sign
mov ah,conout ; Print the character
int dos
perpr7: ret
; GETFIL, called only by send code
getfil: mov flags.filflg,0ffh ; Say nothing is in the buffer
mov flags.eoflag,0 ; Not the end of file
mov dx,offset diskio.dta ; data transfer address
mov ah,setdma ; set disk transfer address
int dos ; do it
mov cx,0 ; attributes: find only normal files
mov dx,offset diskio.string ; filename string (may have wild cards)
mov ah,first2 ; DOS 2.0 search for first
int dos ; get file's characteristics
pushf ; save c flag
mov ah,setdma ; reset dta address
mov dx,offset buff ; restore dta
int dos
popf ; restore status of search for first
jnc getfi1 ; nc = ok so far
ret ; else take error exit
getfi1:
mov dx,offset diskio.string ; original file spec (may be wild)
mov di,offset templp ; place for path part
mov si,offset templf ; place for filename part
call fparse ; split them
mov si,offset diskio.fname ; current filename from DOS
call strcat ; local path + diskio.fname
mov si,di ; make it a source
mov di,offset diskio.string ; new destination
call strcpy ; new string = old path + DOS's filename
mov ah,open2 ; DOS 2.0 file open
mov al,0 ; open readonly
cmp dosnum,2 ; above DOS 2?
jna getfi1a ; na = no, so no shared access
mov al,0+40h ; open readonly, deny none
getfi1a:mov dx,offset diskio.string ; filename string
int dos
jnc getfi2 ; nc = opened the file
ret ; else take error return
getfi2: mov diskio.handle,ax ; save file handle
mov ax,diskio.sizehi ; get file size (high order word)
mov ofilsz,ax ; new form
mov ax,diskio.sizelo ; low order word
mov ofilsz+2,ax ; new form
mov ax,0
mov tfilsz,ax ; Set bytes sent to zero
mov tfilsz+2,ax
mov ax,-1 ; get a minus one
mov oldkbt,ax
mov oldper,ax
cmp ofilsz,0 ; Null file?
jne getfl0 ; Nope
cmp ofilsz+2,0 ; Null file?
jne getfl0 ; Nope
mov flags.eoflag,0FFH ; yes. Set EOF
getfl0: jmp rskp
; GTNFIL called by send code to get next file. Rewritten by [jrd]
gtnfil: cmp flags.cxzflg,'Z' ; Did we have a ^Z?
jne gtn1 ; ne = no, else done sending files
ret ; take failure exit
gtn1: mov flags.filflg,0ffh ; Nothing in the DMA
mov flags.eoflag,0 ; Not the end of file
mov dx,offset diskio.dta ; point at dta
mov ah,setdma ; set the dta address
int dos
mov ah,next2 ; DOS 2.0 search for next
int dos
pushf ; save carry flag
mov ah,setdma ; restore dta
mov dx,offset buff
int dos
popf ; recover carry flag
jc gtn4 ; carry set means no more files found
call endtim ; get tod of end of file transfer
mov di,offset templp ; place for path part
mov si,offset templf ; place for filename part
mov dx,offset diskio.string ; current full filename
call fparse ; split them
mov si,offset diskio.fname ; new filename part from DOS
call strcat ; rejoin path and new filename
mov si,di ; new source
mov di,offset diskio.string ; place for whole new name
call strcpy ; copy new string
mov dx,offset diskio.string ; address of new string
mov ah,open2 ; DOS 2.0 file open
mov al,0 ; open readonly
cmp dosnum,2 ; above DOS 2?
jna gtn3 ; na = no, so no shared access
mov al,0+40h ; open readonly, deny none
gtn3: int dos
jc gtn4 ; c = could not open the file
mov diskio.handle,ax ; save file handle
call begtim ; start statistics counter
mov ax,diskio.sizehi ; get file size (high order word)
mov ofilsz,ax ; save as original file size
mov ax,diskio.sizelo ; low order word
mov ofilsz+2,ax
mov tfilsz,0 ; Set bytes sent to zero
mov tfilsz+2,0
mov oldkbt,-1
mov oldper,-1
mov ax,1 ; tell statistics this was a send operation
cmp ofilsz,0 ; Null file?
jne gtn2 ; Nope
cmp ofilsz+2,0 ; Null file?
jne gtn2 ; Nope
mov flags.eoflag,0FFH ; Set EOF
gtn2: jmp rskp ; set success condition
gtn4: ret ; set failure condition
; Get the file name from the data portion of the F packet or from locally
; specified override filename (in locfil)
; prints the filename, handles any manipulation of the filename
; necessary, including changing the name to prevent collisions
; Called by READ (receive a file, at rfil32)
gofil: push si
push di
mov si,offset data ; filename in packet
cmp flags.xflg,0 ; receiving to screen
je gofil0a ; e = no
mov diskio.handle,1 ; screen is stdout, handle 1
cmp data,0 ; filename given?
jne gofil0a ; ne = yes
mov si,offset toscreen ; then use this dummy name
gofil0a:mov di,offset diskio.string ; place where prtfn prints name
call strcpy ; copy pkt filename to diskio.string
mov di,offset fsta.xname ; statistics filespec save area
call strcpy ; record external name
pop di
pop si
cmp flags.xflg,0 ; Receiving to screen? (X versus F)
je gofil1 ; e = no
jmp gofi20 ; Yes. so skip this stuff
gofil0: cmp flags.destflg,2 ; file destination = screen?
jne gofil1 ; ne = no
jmp gofi20 ; yes
gofil1: test flags.remflg,dquiet ; quiet display mode?
jnz gofi1c ; nz = yes, don't display filename
call prtfn ; display the packet's filename
gofi1c: mov byte ptr diskio.string,0 ; clear final filename
cmp flags.destflg,0 ; writing to printer?
jne gofi1a ; ne = no, go on
mov ax,offset printer ; this is filename now
mov diskio.handle,4 ; system printer is handle 4
jmp gofi16 ; and do it directly
gofi1a: mov flags.nmoflg,0 ; assume no override name
cmp byte ptr locfil,0 ; overriding name from other side?
jne gofi1e ; ne = yes
jmp gofil4 ; e = No. get the other end's filename
gofi1e: mov flags.nmoflg,0ffh ; say using an override name
mov ax,offset locfil ; get local override filename
cmp word ptr locfil+1,003ah ; colon+null?(primative drive spec A:)
je gofil3 ; e = yes, skip screwy DOS response (No Path)
cmp word ptr locfil,'..' ; parent directory?
jne gofi1g ; ne = noo
cmp word ptr locfil+1,002eh ; dot dot + null?
je gofi1b ; e = yes, process as directory
gofi1g: cmp word ptr locfil,002eh ; dot + null (parent dir)?
je gofi1b ; e = yes, process as directory
call isfile ; does it exist?
jnc gofi1f ; nc = file exists
test filtst.fstat,80h ; serious error?
jz gofil3 ; z = no, just no such file
jmp gofi18a ; else quit here
gofi1f: test byte ptr filtst.dta+21,10H ; subdirectory name?
jnz gofi1b ; nz = yes
cmp byte ptr locfil+2,5ch ; could it be a root directory like b:\?
jne gofi1d ; ne = no. (DOS is not helpful with roots)
cmp byte ptr locfil+3,0 ; and is it terminated in a null?
je gofi1b ; e = yes, so it is a root spec
gofi1d: test byte ptr filtst.dta+21,0fh ; r/o, hidden, system, vol label?
jz gofil3 ; z = no
jmp gofi18a ; yes. Complain and don't transfer file
gofi1b: mov dx,offset locfil ; locfil is a subdirectory name
call strlen ; get its length w/o terminator
jcxz gofil2 ; zero length
dec cx ; examine last char
push bx ; save bx
mov bx,cx
add bx,dx
cmp byte ptr [bx],5ch ; ends in backslash?
je gofil2 ; e = yes
cmp byte ptr [bx],2fh ; maybe forward slash?
je gofil2 ; e = yes
mov byte ptr [bx + 1],5ch ; no slash yet. use backslash
mov byte ptr [bx + 2],0 ; plant new terminator
gofil2: pop bx
gofil3: mov di,offset templp ; local path
mov si,offset templf ; local filename
mov dx,offset locfil ; local string
call fparse ; split local string
mov di,offset temprp ; remote path
mov si,offset temprf ; remote file
mov dx,offset data ; remote string
push bx ; guard against long filenames
mov bx,offset data
mov byte ptr [bx+64],0 ; force filename to be <= 64 text chars
pop bx
call fparse ; split remote string
mov si,offset templp ; copy local path to
mov di,offset data ; final filename
call strcpy ; do the copy
gofi3a: mov si,offset templf ; assume using local file name
cmp byte ptr templf,0 ; local file name given?
jne gofi3b ; ne = yes
mov si,offset temprf ; else use remote file name
gofi3b: call strcat ; do the append
; now offset data holds the new filename
;
gofil4: mov ax,offset data ; assume we're writing to disk
push bx ; guard against long filenames
mov bx,offset data
mov byte ptr [bx+64],0 ; force filename to be <= 64 text char
pop bx
; recheck legality of filename in 'data'
gofil5: mov di,offset temprp ; remote path
mov si,offset temprf ; remote file
mov dx,offset data ; remote string
call strlen ; get original size
push cx ; remember it
call fparse ; further massage filename
push si ; put pieces back together
call verfil ; verify each char in temprf string
mov si,di ; get path part first
mov di,dx ; set destination
call strcpy ; copy in path part
pop si ; recover (new) filename
cmp byte ptr [si],'.' ; does filename part start with a dot?
jne gofil5a ; ne = no
push di ; save regs
push si
mov di,offset rdbuf ; a work area
mov byte ptr [di],'X' ; start name with letter X
inc di
call strcpy ; copy rest of filename
mov di,si
mov si,offset rdbuf ; copy new name back to original location
call strcpy
pop si ; restore regs
pop di
gofil5a:call strcat ; append it
call strlen ; see if we chopped out something
pop si ; get original length (from push cx above)
cmp cx,si ; same size?
je gofil9 ; e = yes
mov flags.nmoflg,0ffh ; say that we have a replacement name
; filename is now in 'data', all converted
gofil9: test flags.remflg,dquiet ; quiet display mode?
jnz gofi10 ; nz = yes, don't print it
cmp flags.nmoflg,0 ; using local override name?
je gofi10 ; e = no
mov ah,prstr
; mov dx,offset asmsg ; print " as "
mcmsg asmsg,casmsg
int dos
mov dx,offset data ; plus the local filename
call prtasz ; print asciiz string
gofi10: mov ax,offset data ; point to name
cmp flags.flwflg,0 ; Is file warning on?
jne gofi100
jmp gofi16 ; e = no, just proceed
gofi100:call isfile ; does it exist?
mov ax,offset data ; reload ptr in case
jc gofi16 ; carry set = no, just proceed
mov ah,open2 ; could it be a device name?
mov al,0 ; open readonly
cmp dosnum,2 ; above DOS 2?
jna gofi10a ; na = no, so no shared access
mov al,0+40h ; open for reading, deny none
gofi10a:mov dx,offset data ; the filename
int dos
jc gofi11 ; c = cannot open so just proceed
mov bx,ax ; file handle
mov ah,ioctl
mov al,0 ; get info
int dos
mov ah,close2 ; close it
int dos
mov ax,offset data ; point to filename again
test dl,80h ; ISDEV bit set?
jz gofi11 ; z = no, not a device
jmp gofi16 ; device, use name as given
gofi11: call unique ; generate unique name
jc gofi14 ; could not generate a unique name
test flags.remflg,dquiet ; quiet display mode?
jnz gofi13 ; nz = yes, skip printing
push ax ; save unique name again
call frpos ; Position cursor.
mov ah,prstr ; Inform the user we are renaming the file
mcmsg infms5,cinfms5
int dos
pop ax ; get name back into ax again
push ax ; save around these calls
mov dx,ax ; print current filename
call prtasz ; display filename
pop ax ; pointer to name, again
gofi13: jmp gofi16 ; and go handle file
gofi14: mcmsg ermes4, cermes4
test flags.remflg,dquiet ; quiet display mode?
jnz gofi15 ; nz = yes, no printing
call erpos ; Position cursor
mov ah,prstr ; Tell the user we can't rename it
int dos
gofi15: mov bx,dx ; Tell host can't rename
call errpack ; Send error packet before abort
ret
gofi16: mov si,ax ; pointer to (maybe new) name
mov di,offset diskio.string ; filename, used in open
mov dx,di ; for isfile and open below
call strcpy ; copy name to diskio.string
mov ax,0
mov ofilsz,ax ; original file size is unknown
mov ofilsz+2,ax ; double word
mov tfilsz,ax ; Set bytes received to zero
mov tfilsz+2,ax
mov ax,-1 ; get a minus one
mov oldkbt,ax
mov oldper,ax
mov diskio.handle,ax ; clear handle of previous usage
mov ax,dx ; filename for isfile
call isfile ; check for read-only/system/vol-label/dir
jc gofi16a ; c = file does not exist
test byte ptr filtst.dta+21,1fh ; the no-no file attributes
jz gofi16b ; z = ok
jmp gofi18 ; nz = shouldn't write over one of these
gofi16a:test filtst.fstat,80h ; access problem?
jnz gofi18 ; nz = yes, quit here
mov diskio.handle,-1 ; clear handle of previous usage
mov ah,creat2 ; DOS 2.0 create file
mov cx,0 ; attributes bits
int dos
jc gofi16b ; c = did not work, try regular open
mov diskio.handle,ax ; save file handle here
call begtim ; start file loggging
jmp rskp
gofi16b:test byte ptr filtst.dta+21,1bh ; r/o, hidden, volume label?
jnz gofi18 ; we won't touch these
mov ah,open2 ; open existing file (usually a device)
mov al,1+1 ; open for writing
int dos
jc gofi18 ; carry set means can't open
mov diskio.handle,ax ; file handle
call begtim ; start file loggging
jmp rskp
gofi18a:mov si,ax ; pointer to local override name
mov di,offset diskio.string ; filename, used in open
call strcpy ; copy name to diskio.string
; fall through to gofi18
gofi18: test flags.remflg,dquiet ; quiet display mode?
jnz gofi19 ; nz = yes, don't try printing
call erpos ; Position cursor
mov ah,prstr ; tell the user
mcmsg erms12,cerms12
int dos
mov dx,offset diskio.string ; print offending name
call prtasz ; display filename
gofi19:
;mov dx,offset erms12 ; reset error message for packet
mcmsg erms12,cerms12
mov bx,dx
call errpack ; Send an error packet
ret
gofi20: cmp pack.datlen,0 ; Any data in "X" packet?
je gofi21 ; Nothing to print.
mov ah,prstr
mov dx,offset crlf
int dos
int dos ; Print another crlf
mov di,offset data ; Where data is
mov cx,pack.datlen ; How much data we have
call prtscr ; Print it on the screen
mov ah,prstr
mov dx,offset crlf
int dos
gofi21: jmp rskp ; And done
FILEIO ENDP
; Given incoming filename in 'data'. Verify that each char is legal
; (if not change it to an "X"), force max of three chars after a period (dot)
; Source is at ds:si (si is changed here). [jrd]
VERFIL PROC NEAR
push es ; verify each char in 'data'
push cx
mov ax,ds
mov es,ax
mov havdot,0 ; say no dot found in name yet
cld
verfi1: lodsb ; get a byte of name from si
and al,7fH ; strip any eight bit
cmp al,0 ; end of name?
je verfi5 ; e = yes
cmp al,'.' ; a dot?
jne verfi2 ; ne = no
cmp havdot,0 ; have one dot already?
jne verfi3 ; ne = yes, change to X
mov byte ptr [si+3],0 ; forceably end filename after 3 char ext
mov havdot,1 ; say have a dot now
jmp verfi4 ; continue
verfi2: cmp al,3ah ; colon?
je verfi4
cmp al,5ch ; backslash path separator?
je verfi4
cmp al,2fh ; or forward slash?
je verfi4
cmp al,'0'
jb verfi3 ; See if it's a legal char < '0'
cmp al,'9'
jbe verfi4 ; It's between 0-9 so it's OK
cmp al,'A'
jb verfi3 ; Check for a legal punctuation char
cmp al,'Z'
jbe verfi4 ; It's A-Z so it's OK
cmp al,'a'
jb verfi3 ; Check for a legal punctuation char
cmp al,'z'
ja verfi3
and al,5FH ; It's a-z, capitalize
jmp verfi4 ; continue with no change
verfi3: push di ; special char. Is it on the list?
mov di,offset spchar2 ; list of acceptable special chars
mov cx,spc2len
cld
repne scasb ; Search string for input char
pop di
je verfi4 ; e = in table, return it
mov al,'X' ; else illegal, replace with "X"
mov flags.nmoflg,0FFH ; say we have a replacement filename
verfi4: mov [si-1],al ; update name
jmp verfi1 ; loop thru rest of name
verfi5: mov byte ptr[si-1],0 ; make sure it's null terminated
pop cx
pop es
ret
VERFIL ENDP
; find a unique filename... Upgraded by [jrd]
; Enter with a pointer to a (null-terminated) filename in ax
; Return with same pointer but with a new name (or old if failure)
; Success = carry clear; failure = carry set
; The idea is to pad out the main name part (8 chars) with ascii zeros and
; then change the last chars successively to a 1, 2, etc. until
; a unique name is found. All registers are preserved
; Add patch to make empty main name fields start with letter X, not digit 0
; 23 March 1986 [jrd]
unique proc near
push bx
push cx
push dx
push si
push di
push es
push ax ; save address of source string
mov dx,ds ; make es use ds segment
mov es,dx
mov dx,ax ; point at original filename string
mov di,offset templp ; place for path
mov si,offset templf ; place for filename
call fparse ; separate path (di) and filename (si)
mov dx,di ; point at path part
call strlen ; put length in cx
mov si,ax ; point to original string
add si,cx ; point to filename part
mov di,offset templf ; destination is temporary location
mov cx,0 ; a counter
cld ; set direction to be forward
uniq1: lodsb ; get a byte
cmp al,'.' ; have a dot?
je uniq2 ; e = yes
cmp al,0 ; maybe null at end?
jne uniq3 ; ne = no. continue loop
uniq2: cmp cl,8 ; have we copied any chars before dot?
jge uniq3 ; ge = all 8
mov byte ptr [di],'0' ; avoid clobbers; pad with 0's
cmp cl,0 ; first char of filename?
jne uniq2a ; ne = no
mov byte ptr [di],'X' ; start name with letter X, not 0
uniq2a: inc di ; and count the output chars
inc cl ; and this counter too
jmp uniq2 ; continue until filled 8 slots
uniq3: inc cl ; cl = # char in destination
stosb ; store the char
cmp al,0 ; null at end?
jne uniq1 ; ne = no, continue copying
mov di,offset templf
add di,7 ; address of last name char
mov byte ptr [di],'1' ; put '1' in last name char
mov unum,1 ; start with this generation digit
uniq4: mov di,offset rdbuf ; build a temporary full filename
mov si,offset templp ; path part
call strcpy ; copy that much
mov si,offset templf ; get rebuilt filename part
call strcat ; paste that to the end
mov ax,offset rdbuf ; point to full name
call isfile ; does it exist?
jc uniq6 ; c = no, succeed now
inc unum ; move to next generation
mov di,offset templf ; position for characters
add di,7 ; point to last name char
mov cx,7 ; max # of digits to play with
mov bx,10 ; divisor (16 bits)
mov ax,unum ; low order part of generation #
uniq5: mov dx,0 ; high order part of generation #
div bx ; compute digit (unum / 10)
add dl,'0' ; make remainder part printable
mov byte ptr [di],dl ; put into right place
cmp ax,0 ; any more to do? (quotient nonzero)
jz uniq4 ; z = no, try this name
dec di ; else decrement char position
loop uniq5 ; and keep making a number
stc ; failure: set carry, keep old name
jmp short uniq7 ; and exit
uniq6: pop di ; address of original filename
push ax ; save for exit clean up
mov si,offset rdbuf
call strcpy ; copy new filename over old
clc ; success: clear carry flag
uniq7: pop ax
pop es
pop di
pop si
pop dx
pop cx
pop bx
ret
unique endp
; [jrd]
; strlen -- computes the length, excluding the terminator, of an asciiz
; string. Input: dx = offset of the string
; Output: cx = the byte count
; Normal 'ret' return. All registers except cx are preserved
;
STRLEN PROC NEAR
push di
push es
push ax
mov ax,ds ; use proper segment address
mov es,ax
mov di,dx
mov cx,0ffffh ; large byte count
cld ; set direction to be forward
mov al,0 ; item sought is a null
repne scasb ; search for it
add cx,2 ; add for -1 and auto dec in scasb
neg cx ; convert to count, excluding terminator
pop ax
pop es
pop di
ret
STRLEN ENDP
; [jrd]
; strcat -- concatenates asciiz string 2 to the end of asciiz string 1
; offset of string 1 is expected to be in ds:di. input & output
; offset of string 2 is expected to be in ds:si. input only (unchanged)
; Preserves all registers. No error returns, returns normally via ret
;
STRCAT PROC NEAR
push di ; save work registers
push si
push es
push dx
push cx
push ax
mov ax,ds ; get data segment value
mov es,ax ; set es to ds for implied es:di usage
mov dx,di
call strlen ; get length (w/o terminator) of dest string
add di,cx ; address of first terminator
mov dx,si ; start offset of source string
call strlen ; find its length too (in cx)
inc cx ; include its terminator in the count
rep movsb ; copy source string to end of output string
pop ax
pop cx
pop dx
pop es
pop si
pop di
ret
STRCAT ENDP
; [jrd]
; strcpy -- copies asciiz string pointed to by ds:si into area pointed to by
; ds:di. Returns via ret. All registers are preserved
;
STRCPY PROC NEAR
mov byte ptr [di],0 ; clear destination string
call strcat ; let strcat do the real work
ret
STRCPY ENDP
; [jrd]
; fparse -- separate the drive:path part from the filename.ext part of an
; asciiz string. Characters separating parts are \ or / or :
; Inputs: asciiz input full filename string offset in ds:dx
; asciiz path offset in ds:di
; asciiz filename offset in ds:si
; Outputs: the above strings in the indicated spots
; Strategy is simple. Reverse scan input string until one of the
; three separators is encountered and then cleave at that point
; Simple filename construction restrictions added 30 Dec 1985;
; to wit: mainname limited to 8 chars or less,
; extension field limited to 3 chars or less and is found by searching
; for first occurence of a dot in the filename field. Thus the whole
; filename part is restricted to 12 (8+dot+3) chars plus a null
; All registers are preserved. Return is always via ret
; (Microsoft should have written this for DOS 2.x et seq.)
FPARSE PROC NEAR
push cx ; local counter
push ax ; local work area
push es ; implied segment register for di
push di ; offset of path part of output
push si ; offset of file name part of output
mov ax,ds ; get data segment value
mov es,ax ; set es to ds for implied es:di usage
mov byte ptr [si],0 ; clear outputs
mov byte ptr [di],0
push si ; save original file name address
mov si,dx ; get original string address
call strcpy ; copy string to original di
call strlen ; find length (w/o terminator), in cx
mov si,di ; address of string start
add si,cx
dec si ; si = address of last non-null char
jcxz fpars5 ; if null skip the path scan
; now find last path char, if any
; start at the end of input string
std ; set direction to be backward
fpars4: lodsb ; get a byte (dec's si afterward)
cmp al,5ch ; is it a backslash ('\')?
je fpars6 ; e = yes
cmp al,2fh ; or forward slash ('/')?
je fpars6 ; e = yes
cmp al,3ah ; or even the drive terminator colon?
je fpars6 ; e = yes
loop fpars4 ; else keep looking until cx == 0
; si is at beginning of file name
fpars5: dec si ; dec for inc below
fpars6: inc si
inc si ; si now points at first filename char
; cx holds number of path chars
; get original file name address (si)
pop di ; and make it place to copy filename
cld ; reset direction to be forward
mov ax,si ; ax holds filename address for awhile
push dx
mov dx,si ; strlen wants string pointer in dx
call strlen ; get length of filename part into cx
pop dx
jcxz fpar7a ; any chars to look at? z = no
fpars7: cmp byte ptr [si],'.' ; look for a dot in filename
je fpars8 ; e = found one
inc si ; look at next filename char
loop fpars7 ; keep looking until cx = zero
fpar7a: mov si,ax ; no dot. recover starting address
mov byte ptr [si+8],0 ; forcably truncate mainname to 8 char
call strcpy ; copy this part to filename field
jmp fparsx ; and exit
fpars8: mov byte ptr [si+4],0 ; plant terminator after dot + 3 ext chars
mov cx,si
sub cx,ax ; cx now = number of chars in mainname field
cmp cx,9 ; more than 8?
jb fpars9 ; b = no, we're safe
mov cx,8 ; limit ourselves to 8 chars in mainname
fpars9: push si ; remember address of dot and extension
mov si,ax ; point to start of input filename
rep movsb ; copy cx chars from si to di (output)
mov byte ptr [di],0 ; plant terminator where dot goes
pop si ; source = dot and extension address
call strcat ; append the dot & ext to the filename field
fparsx: mov si,ax ; recover start of filename in input string
mov byte ptr [si],0 ; terminate path field
pop si
pop di
pop es
pop ax
pop cx
ret
FPARSE ENDP
; Print filename in offset data. Shortened by [jrd]
PRTFN PROC NEAR
push ax ; saves for messy clrfln routine
push bx
push cx
push dx
push di
call clrfln ; Position cursor & blank out the line
mov dx,offset diskio.string
call strlen ; compute length of asciiz string in cx
mov di,dx ; where prtscr wants its string
call prtscr
pop di
pop dx
pop cx
pop bx
pop ax
ret
PRTFN ENDP
; Print string to screen from offset ds:di for # bytes given in cx,
; regardless of $'s. All registers are preserved. [jrd]
PRTSCR PROC NEAR
jcxz prtscr4 ; cx = zero means nothing to show
push ax
push bx
push dx
mov dx,di ; source ptr for DOS
cmp flags.eofcz,0 ; end on Control-Z?
jne prtscr3 ; ne = yes, let DOS do it
push cx ; else map Control-Z to space
push di
push es
push ds
pop es ; datas to es
mov al,ctlz ; look for Control-Z
cld ; scan buffer es:di, cx chars worth
prtscr1:repne scasb
jne prtscr2 ; ne = found no Control-Z's
mov byte ptr [di-1],' ' ; replace Control-Z with space
jcxz prtscr2 ; z = examined all chars
jmp short prtscr1 ; until examined everything
prtscr2:pop es
pop di
pop cx
prtscr3:mov bx,1 ; stdout file handle
mov ah,write2
int dos
pop dx
pop bx
pop ax
prtscr4:ret
PRTSCR ENDP
; Print to screen asciiz string given in ds:dx. Everything preserved. [jrd]
PRTASZ PROC NEAR
push cx
push di
call strlen ; get length of asciiz string
mov di,dx ; where prtscr looks
call prtscr ; print counted string
pop di
pop cx
ret
PRTASZ 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
code ends
end