|
|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T m
Length: 105870 (0x19d8e)
Types: TextFile
Names: »mssfil.asm«
└─⟦9ae75bfbd⟧ Bits:30007242 EUUGD3: Starter Kit
└─⟦71044c191⟧ »EurOpenD3/misc/kermit.ms-2.32.tar.Z«
└─⟦31f2d420d⟧
└─⟦this⟧ »mssfil.asm«
NAME mssfil
; File MSSFIL.ASM
; Edit history:
; Last edit 21 Nov 1988
; 21 Nov 1988 Version 2.32
; 26 Oct 1988 Modify printer output code to replace Control-Z with space if
; SET EOF NOCTRL-Z is active, otherwise to tolerate a write error if the
; unwritten character is a Control-Z. Done in outbuf. Similar controls are
; in prtscr. Reason: DOS terminates i/o operation at the Control-Z for
; destinations of CON and PRN.
; 19 August Assign system file handles 1 and 4 when receiving to screen and
; printer in gofile, to satisfy disk size test in mssrcv. [jrd]
; 1 July 1988 Version 2.31
; 21 May 1988 Correct add bug in pktsiz, from Dan Norstedt
; 7 May 1988 Round up file transfer display values
; 29 March 1988 Add attribute Deny none (40h) to readonly file opens,
; thanks to Paul Fox of AT&T.
; 25 Feb 1988 Speedup decoder, simplify getfil, add transaction details.
; 26 Jan 1988 Modify gofi1c to clear diskio.string after prtfn call.
; Modify prtfn to reference diskio.string (vs buf data) to see paths.[jrd]
; 1 Jan 1988 version 2.30
public bufpnt, buff, chrcnt, init, ofilsz, lnout
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, prtasz, prtscr, prtfn, fmtdsp
public diskio, locfil, strlen, strcat, strcpy, fparse, pktsize
public shosta, begtim, endtim, fsta ; statistics procedures
include mssdef.h
getdate equ 2ah ; DOS get current date
rptmin equ 3 ; At least 3 of same char in a row
; equates for screen positioning
scrser equ 0209H ; place for server state display line
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
scrsz equ 0916h ; packet size
scrnrt equ 0A16H ; Place for number of retries
screrr equ 0B16H ; Place for error msgs.
scrhi equ 0C16H ; Err when 8th bit is on
scrfr equ 0C16H ; Rename file
scrint equ 0C16H ; Acknowledge interrupt
scrsp equ 0D00H ; Place for send packet
scrrp equ 0F00H ; Place for receive packet
scrrpr equ 1700H ; Prompt when Kermit ends (does cr/lf)
datas segment public 'datas'
extrn data:byte, flags:byte, trans:byte, pack:byte, hierr:byte
extrn filtst:byte, tloghnd:word, dosnum:byte
outlin db 10 dup (' ')
verdef ; version ident
db cr,lf,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,' Packet length:'
db cr,lf,' Number of retries:'
db cr,lf,' Last error:'
db cr,lf,' Last message:'
db cr,lf,'$'
ermes4 db '?Unable to make unique name$'
ermes9 db '?Printer not ready$'
erms10 db '?Unable to store all data$'
erms11 db '?Disk full$'
erms12 db '?Unable to create file $'
erms13 db '?Error writing file$'
infms1 db 'Server mode: type Control-C to exit',cr,lf,'$'
infms5 db 'Renaming file to $'
infms7 db 'File interrupt',cr,lf,'$'
infms8 db 'File group interrupt',cr,lf,'$'
infms9 db 'User ',5eh,' interrupt',cr,lf,'$'
hibit db 'File contains 8-bit data',cr,lf,'$'
asmsg db ' as $'
crlf db cr,lf,'$'
printer db 'PRN',0
; DOS special chars allowed in filenames
spchar2 db '$', 26h, 23h, 40h, 21h, 25h, 27H, '(', ')', '-', 7bh, 7dh
db 5fh, 5eh, 7eh, 60h
spc2len equ $-spchar2
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
chrcnt dw 0 ; Number of chars in the file buffer
outpnt dw 0 ; Position in packet
bufpnt dw 0 ; Position in file buffer
ofilsz dw 0 ; Double word original file size (in bytes.)
dw 0
tfilsz dw 0 ; Bytes transferred
dw 0
oldper dw 0 ; old percentage
oldkbt dw 0 ; old KB transferred
wrpmsg db 0 ; non-zero if we wrote percent message
fmtdsp db 0 ; non-zero if formatted display in use
; Statistics data storage area
fsta statinfo <> ; for last operation values
ssta statinfo <> ; for session values
sflag dw 0 ; flag for send (1) or receive (0)
; 80h = begtim started
lastmsg db cr,lf,cr,lf,' Totals for the last transfer ($'
sessmsg db cr,lf,cr,lf,' Totals since Kermit was started ($'
pinmsg db ' sec)'
db cr,lf,' Serial port characters received $'
poutmsg db cr,lf,' Serial port characters sent $'
finmsg db cr,lf,' File characters received $'
foutmsg db cr,lf,' File characters sent $'
pkimsg db cr,lf,' Packets received $'
pkomsg db cr,lf,' Packets sent $'
nakimsg db cr,lf,' NAKs received $'
nakomsg db cr,lf,' NAKs sent $'
baudmsg db cr,lf,' Effective baud rate $'
sndmsg db 'Sent ',0
rcvmsg db 'Recv ',0
date db '00:00:00 00 Jan 1980',0
datelen equ $-date-1
atmsg db cr,lf,' at '
atlen equ $-atmsg
fasmsg db ' as '
faslen equ $-fasmsg
fsucmsg db ', completed, bytes: ',0
fbadmsg db ', failed, bytes: ',0
fintmsg db ', interrupted, bytes: ',0
months db 'JAN','FEB','MAR','APR','MAY','JUN','JUL','AUG','SEP'
DB 'OCT','NOV','DEC'
tens dd 1,10,100,1000,10000,100000,1000000,10000000,100000000
dd 1000000000
tenslen equ ($-tens) / 4 ; number of double words in array tens
; end statistics data area
onek dw 1024
onehun dw 100
sixty dw 60
ten dw 10
denom dw 0
permsg db cr,' Percent transferred:$'
cxzhlp db '^X cancels file, ^Z cancels batch'
db ', ^E quits protocol'
db ', ^C quits'
db ', Return retries'
db '$'
erword db cr,lf,'Error $'
rtword db cr,lf,'Retry $'
cxzser db cr,lf,'Type Control X to cancel file, Control Z to cancel batch,'
db cr,lf,' Control E to quit protocol, Control C to quit '
db 'abruptly,',cr,lf,' or Return to retry',cr,lf,'$'
templp db 65 dup (?) ; temp for local path part
templf db 14 dup (?) ; temp for local filename part
temprp db 65 dup (?) ; temp for remote path part
temprf db 14 dup (?) ; temp for remote filename part
locfil db 65 dup (?) ; local filename for receive and get
rdbuf db 65 dup (?) ; temp work buffer
diskio filest <> ; ditto, for ordinary file transfers
buff db buffsz dup (?) ; Use as our Disk Transfer Area
filbuf equ this byte ; make filbuf and decbuf the same address
decbuf db maxpack+10 dup (?) ; For decoding incoming data (+guard)
unum dw ? ; unique filename generation number
havdot db ? ; dot-found status in verify
prepksz dw 0 ; previous packet size
toscreen db 'Screen',0 ; for transaction logging
datas ends
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
mov dx,offset erword ; put out word Error
int dos
pop dx ; restore old pointer
ret
erp0: mov dx,screrr
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
call poscur
jmp clearl
rtp1: mov dx,offset rtword ; 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
call poscur
call clearl
int3: mov dx,offset infms7 ; File interrupted?
cmp flags.cxzflg,'X' ; Yes.
je int0
mov dx,offset infms8 ; 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
mov dx,offset infms9
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
call poscur
call clearl
biter3: mov ah,prstr
mov dx,offset hibit
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
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
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
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
test flags.remflg,dquiet+dserial ; quiet or serial display mode?
jz setup2 ; z = no
ret ; else ignore postioning request
perpos: mov dx,scrper ; Percent transferred
test flags.remflg,dquiet+dserial ; quiet or serial display mode?
jz setup2 ; z = no
ret ; else ignore postioning request
frpos: mov dx,scrfr ; Say renamed file
jmp setup2
stpos: mov dx,scrst ; Print status of file transfer
jmp setup2
nppos: mov dx,scrnp ; Number of packets sent
test flags.remflg,dquiet+dserial ; quiet or serial display mode?
jz setup1 ; z = no
ret
rprpos: mov dx,scrrpr ; Reprompt position
call setup1 ; position cursor
mov fmtdsp,0 ; turn off formatted display flag
ret
nrtpos: mov dx,scrnrt ; Number of retries
jmp short setup2
sppos: mov dx,scrsp ; Send packet location
jmp short setup1
rppos: mov dx,scrrp ; Receive packet location
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
mov dx,offset fasmsg ; 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
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
mov dx,offset fsucmsg ; assume success message
cmp fsta.xstatus,0 ; 0 = completed?
je endtim10 ; e = completed
mov dx,offset fbadmsg ; failed message
test fsta.xstatus,80h ; interrupted?
jz endtim10 ; z = no
mov dx,offset fintmsg ; 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?
mov cx,offset lastmsg ; totals for last transfer
je shosta1 ; e = yes
mov bx,offset ssta ; point to Session statistics area
mov cx,offset sessmsg ; totals for whole session
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
mov ax,[bx].prbyte
mov dx,[bx].prbyte+2
call shoprt ; show result
mov cx,offset poutmsg ; port bytes sent
mov ax,[bx].psbyte
mov dx,[bx].psbyte+2
call shoprt ; show result
mov cx,offset finmsg ; file bytes received
mov ax,[bx].frbyte
mov dx,[bx].frbyte+2
call shoprt ; show result
mov cx,offset foutmsg ; file bytes sent
mov ax,[bx].fsbyte
mov dx,[bx].fsbyte+2
call shoprt ; show result
mov cx,offset pkimsg ; packets received
mov ax,[bx].prpkt
mov dx,[bx].prpkt+2
call shoprt ; show result
mov cx,offset pkomsg ; packets sent
mov ax,[bx].pspkt
mov dx,[bx].pspkt+2
call shoprt ; show result
mov cx,offset nakimsg ; naks received
mov ax,[bx].nakrcnt
xor dx,dx
call shoprt ; show result
mov cx,offset nakomsg ; naks sent
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
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
mov dx,offset cxzhlp
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
call poscur
mov ah,prstr
mov dx,offset infms1 ; say now in server mode
int dos
init1: call locate
mov ah,prstr ; Put statistics headers on the screen
mov dx,offset outlin
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
mov dx,offset cxzser ; 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
jc outbf0 ; c = bad buffer pointers
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
mov dx,offset 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
mov dx,offset ermes9 ; 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
mov dx,offset erms13 ; Disk writing error
cmp flags.destflg,0 ; writing to printer?
jne outbf0a ; ne = no
mov dx,offset ermes9 ; Printer not ready message
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: 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
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
mov dx,offset permsg
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 "
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?
je gofi16 ; e = no, just proceed
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
mov dx,offset infms5
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: mov dx,offset ermes4
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
mov dx,offset erms12
int dos
mov dx,offset diskio.string ; print offending name
call prtasz ; display filename
gofi19: mov dx,offset erms12 ; reset error message for packet
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