home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Columbia Kermit
/
kermit.zip
/
extra
/
nyenhuis3.arc
/
MSSFIL.ASM
< prev
next >
Wrap
Assembly Source File
|
1990-01-16
|
61KB
|
1,775 lines
NAME mssfil
; File MSSFIL.ASM
include mssdef.h
; Edit history:
; Last edit 15 Jan 1990
public buff, gofil, ptchr, gtchr, getfil, gtnfil, doenc, dodec
public encbuf, decbuf, diskio, auxfile, fparse, prtasz, prtscr
public strlen, strcat, strcpy, tfilsz, templp, latin1, charids
public L1cp437, L1cp850, L1cp860, L1cp863, L1cp865, unique
public load, cplatin
data segment public 'data'
extrn flags:byte, trans:byte, denyflg:word, dosnum:word
extrn oldkbt:word, oldper:word, filtst:byte, rdbuf:byte, fsta:byte
ermes4 db 'Unable to make unique name',0
ermes9 db 'Printer not ready',0
erms12 db 'Unable to create file ',0
erms13 db 'Error writing output file',0
infms5 db 'Renaming file to $'
infms6 db cr,lf,'?Unable to open file$'
asmsg db ' as $'
crlf db cr,lf,'$'
printer db 'PRN',0
screen db 'CON',0
loadhlp db 'filename$'
; DOS special chars allowed in filenames
spchar2 db '$', 26h, 23h, 40h, 21h, 25h, 27H, '(', ')', '-', 7bh, 7dh
db 5fh, 5eh, 7eh, 60h
spc2len equ $-spchar2
textctl db cr,lf,tab,bell,ff,ctlz ; controls allowed in text files
textctlen equ $-textctl
even
filflg db 0 ; input buffer has data, if non-zero
tmprptq db 0 ; working copy of repeat prefix
rptval db 0 ; repeated character
rptct db 1 ; number of times it's repeated
decoutp dw 0 ; ptr to proc to dump decode output buffer
encinp dw 0 ; ptr to proc to refill encode input buffer
dchrcnt dw 0 ; number of chars in the decode file buffer
echrcnt dw 0 ; number of chars in the encode file buffer
dbufpnt dw 0 ; position in file buffer, decoder
ebufpnt dw 0 ; position in file buffer, encoder
decbuf db 512 dup (0) ; decoding source buffer
db 0 ; safety for possible null terminator
encbuf db 512 dup (0) ; encoding source buffer
db 0 ; safety for possible null terminator
tfilsz dw 0,0 ; bytes transferred (double word qty)
nmoflg db 0 ; have override filename, if non-zero
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
auxfile db 65 dup (?) ; auxillary filename for general use
diskio filest <> ; ditto, for ordinary file transfers
buff db buffsz dup (?) ; use as our Disk Transfer Area
havdot db 0 ; dot-found status in verify
unum dw 0 ; unique filename generation number
temp dw 0
; charids: table of transfer char-set idents
charids dw 2,chtrans,chlatin1 ; qty, pointers to char set idents
chtrans db 1,'A' ; Transparent. char count, ident
chlatin1 db 6,'I2/100' ; Latin1. char count, ident
; end of charids info
loadtab db 1 ; LOAD command table
mkeyw 'Transfer-character-set',0
filtab macro
cnt = 128
rept 128 ; 128 idenity entries
db cnt ; initialize table to 128 .. 255
cnt = cnt + 1
endm
endm
userin equ this byte ; LOAD command
filtab ; init table to idenity
namein db 20 dup (0) ; name of the character set
userout equ this byte
filtab ; init table to idenity
nameout db 20 dup (0) ; name of the character set
tblptr dw 0 ; LOAD command
xlines dw 0 ; LOAD command
linecnt dw 0 ; LOAD command
badvalue db cr,lf,'?Bad value on line $'
; Translation tables for byte codes 0a0h..0ffh to map ISO 8859-1 to Code Pages
; Codes 00h-1fh are 7-bit controls (C0), codes 20h..7eh are ASCII, 7fh DEL is
; considered to be a control code, 80h..9fh are 8-bit controls (C1).
; Each table is 96 translatable bytes followed by the table size (96), the
; ISO announcer ident ('A' and a null here).
; from ISO 8859-1 Latin-1 to Code Page
; to CP437
L1cp437 db 80h,81h,82h,83h, 84h,85h,86h,87h ; column 8
db 88h,89h,8ah,8bh, 8ch,8dh,8eh,8fh
db 90h,91h,92h,93h, 94h,95h,96h,97h ; column 9
db 98h,99h,9ah,9bh, 9ch,9dh,9eh,9fh
db 20h,0adh,9bh,9ch, 0fh,9dh,7ch,15h ; column 10
db 22h,40h,0a6h,0aeh, 0aah,0c4h,3fh,2dh
db 0f8h,0f1h,0fdh,33h, 27h,0e6h,14h,0feh ; column 11
db 2ch,60h,0a7h,0afh, 0ach,0abh,3fh,0a8h
db 85h,0a0h,83h,83h, 8eh,8fh,92h,80h ; column 12
db 8ah,90h,88h,89h, 8dh,0a1h,8ch,8bh
db 44h,0a5h,95h,0a2h, 93h,94h,94h,58h ; column 13
db 0edh,97h,0a3h,96h, 9ah,59h,3fh,0e1h
db 85h,0a0h,83h,84h, 84h,86h,91h,87h ; column 14
db 8ah,82h,88h,89h, 8dh,0a1h,8ch,8bh
db 3fh,0a4h,95h,0a2h, 93h,94h,94h,0f6h ; column 15
db 0edh,97h,0a3h,96h, 81h,98h,9eh,98h
db 96,'A',0 ; 96 byte set, letter ident
; to CP850
L1cp850 db 80h,81h,82h,83h, 84h,85h,86h,87h ; column 8
db 88h,89h,8ah,8bh, 8ch,8dh,8eh,8fh
db 90h,91h,92h,93h, 94h,95h,96h,97h ; column 9
db 98h,99h,9ah,9bh, 9ch,9dh,9eh,9fh
db 20h,0adh,0bdh,9ch, 0cfh,0beh,0ddh,15h ; column 10
db 0f9h,0b8h,0a6h,0aeh, 0aah,0f0h,0a9h,0eeh
db 0f8h,0f1h,0fdh,0fch, 0efh,0e6h,14h,0feh ; column 11
db 03fh,0fbh,0a7h,0afh, 0ach,0abh,0f3h,0a8h
db 0b7h,0b5h,0b6h,0c7h, 8eh,8fh,92h,80h ; column 12
db 0d4h,90h,0d2h,0d3h, 0deh,0d6h,0d7h,0d8h
db 0d1h,0a5h,0e0h,0e3h, 0e2h,0e5h,99h,9eh ; column 13
db 9dh,0ebh,0e9h,0eah, 9ah,0edh,0e7h,0e1h
db 85h,0a0h,83h,0c6h, 84h,86h,91h,87h ; column 14
db 8ah,82h,88h,89h, 8dh,0a1h,8ch,8bh
db 0d0h,0a4h,95h,0a2h, 93h,0e4h,94h,0f6h ; column 15
db 9bh,97h,0a3h,96h, 81h,0ech,0e8h,98h
db 96,'A',0 ; 96 byte set, letter ident
; to CP860
L1cp860 db 80h,81h,82h,83h, 84h,85h,86h,87h ; column 8
db 88h,89h,8ah,8bh, 8ch,8dh,8eh,8fh
db 90h,91h,92h,93h, 94h,95h,96h,97h ; column 9
db 98h,99h,9ah,9bh, 9ch,9dh,9eh,9fh
db 20h,0adh,9bh,9ch, 0fh,59h,7ch,15h ; column 10
db 22h,3fh,0a6h,0aeh, 0aah,0c4h,3fh,2dh
db 0f8h,0f1h,0fdh,33h, 27h,0e6h,14h,0feh ; column 11
db 2ch,60h,0a7h,0afh, 0ach,0abh,3fh,0a8h
db 85h,0a0h,83h,83h, 8eh,8fh,92h,80h ; column 12
db 8ah,90h,88h,89h, 8dh,0a1h,8ch,8bh
db 44h,0a5h,95h,0a2h, 93h,94h,94h,58h ; column 13
db 0edh,97h,0a3h,96h, 9ah,59h,3fh,0e1h
db 85h,0a0h,83h,84h, 84h,86h,91h,87h ; column 14
db 8ah,82h,88h,89h, 8dh,0a1h,8ch,8bh
db 3fh,0a4h,95h,0a2h, 93h,94h,94h,0f6h ; column 15
db 0edh,97h,0a3h,96h, 81h,98h,9eh,98h
db 96,'A',0 ; 96 byte set, letter ident
; to CP863
L1cp863 db 80h,81h,82h,83h, 84h,85h,86h,87h ; column 8
db 88h,89h,8ah,8bh, 8ch,8dh,8eh,8fh
db 90h,91h,92h,93h, 94h,95h,96h,97h ; column 9
db 98h,99h,9ah,9bh, 9ch,9dh,9eh,9fh
db 20h,0adh,9bh,9ch, 0fh,9dh,7ch,15h ; column 10
db 22h,40h,61h,0aeh, 0aah,0c4h,3fh,2dh
db 0f8h,0f1h,0fdh,33h, 0a1h,0e6h,86h,0feh ; column 11
db 0a5h,31h,6fh,0afh, 0ach,0abh,0adh,3fh
db 8eh,41h,84h,41h, 41h,41h,3fh,80h ; column 12
db 91h,90h,92h,94h, 49h,49h,88h,95h
db 44h,4eh,4fh,4fh, 99h,4fh,4fh,58h ; column 13
db 0edh,9dh,55h,0aeh, 55h,59h,3fh,0e1h
db 85h,61h,83h,61h, 61h,61h,3fh,87h ; column 14
db 8ah,82h,88h,89h, 69h,69h,8ch,8bh
db 3fh,6eh,6fh,0a2h, 93h,6fh,6fh,0f6h ; column 15
db 0edh,97h,0a3h,96h, 75h,79h,3fh,79h
db 96,'A',0 ; 96 byte set, letter ident
; to CP865
L1cp865 db 80h,81h,82h,83h, 84h,85h,86h,87h ; column 8
db 88h,89h,8ah,8bh, 8ch,8dh,8eh,8fh
db 90h,91h,92h,93h, 94h,95h,96h,97h ; column 9
db 98h,99h,9ah,9bh, 9ch,9dh,9eh,9fh
db 20h,0adh,3fh,9ch, 0afh,3fh,7ch,15h ; column 10
db 0a4h,3fh,0a6h,0aeh, 0aah,0c4h,3fh,0c4h
db 0f8h,0f1h,0fdh,33h, 27h,0e6h,14h,0feh ; column 11
db 2ch,31h,0a7h,03fh, 0ach,0abh,3fh,0a8h
db 41h,41h,41h,41h, 8eh,8fh,92h,80h ; column 12
db 45h,90h,45h,45h, 49h,49h,49h,49h
db 44h,0a5h,4fh,4fh, 4fh,4fh,99h,58h ; column 13
db 0edh,55h,55h,55h, 9ah,59h,3fh,0e1h
db 85h,0a0h,83h,61h, 84h,86h,91h,87h ; column 14
db 8ah,82h,88h,89h, 8dh,0a1h,8ch,8bh
db 3fh,0a4h,95h,0a2h, 93h,6fh,94h,0f6h ; column 15
db 0edh,97h,0a3h,96h, 81h,79h,3fh,98h
db 96,'A',0 ; 96 byte set, letter ident
; 128 byte translation tables from Code Pages to ISO 8859-1 Latin-1
; For GRight only (high bit set).
; from Code Page 437
cp437L1 db 0c7h,0fch,0e9h,0e2h, 0e4h,0e0h,0e5h,0e7h ; column 8
db 0eah,0ebh,0e8h,0efh, 0eeh,0ech,0c4h,0c5h
db 0c9h,0e6h,0c6h,0f4h, 0f6h,0f2h,0fbh,0f9h ; column 9
db 0ffh,0d6h,0dch,0a2h, 0a3h,0a6h,3fh,3fh
db 0e1h,0edh,0f3h,0fah, 0f1h,0d1h,0aah,0bah ; column 10
db 0bfh,3fh,0ach,0bdh, 0bch,0a1h,0abh,0bbh
db 16 dup (3fh) ; column 11
db 16 dup (3fh) ; column 12
db 16 dup (3fh) ; column 13
db 3fh,0dfh, 4 dup (3fh), 0b5h,3fh ; column 14
db 6 dup(3fh), 3fh,3fh
db 3fh,0b1h, 4 dup (3fh), 0f7h,3fh ; column 15
db 0b0h, 4 dup (3fh), 0b2h,0b7h,3fh
; from Code Page 850
cp850L1 db 0c7h,0fch,0e9h,0e2h, 0e4h,0e0h,0e5h,0e7h ; column 8
db 0eah,0ebh,0e8h,0efh, 0eeh,0ech,0c4h,0c5h
db 0c9h,0e6h,0c6h,0f4h, 0f6h,0f2h,0fbh,0f9h ; column 9
db 0ffh,0d6h,0dch,0f8h, 0a3h,0d8h,0d7h,3fh
db 0e1h,0edh,0f3h,0fah, 0f1h,0d1h,0aah,0bah ; column 10
db 0bfh,0aeh,0ach,0bdh, 0bch,0a1h,0abh,0bbh
db 5 dup (3fh), 0c1h,0c2h,0c0h ; column 11
db 0a9h, 4 dup (3fh), 0a2h,0a5h,0ach
db 6 dup (3fh),0e3h,0c3h, 7 dup (3fh),0a4h ; column 12
db 0f0h,0d0h,0cah,0cbh, 0c8h,0b9h,0cdh,0ceh ; column 13
db 0cfh, 4 dup (3fh), 0a6h,0cch,3fh
db 0d3h,0dfh,0d4h,0d2h, 0f5h,0d5h,0b5h,0deh ; column 14
db 0feh,0dah,0dbh,0d9h, 0fdh,0ddh,0afh,0b4h
db 0adh,0b1h,3dh,0beh, 0b6h,0a7h,0f7h,0b8h ; column 15
db 0b0h,0a8h,3fh,0b9h, 0b2h,0b3h,0b7h,20h
; from Code Page 860
cp860L1 db 0c7h,0fch,0e9h,0e2h, 0e3h,0e0h,0c1h,0e7h ; column 8
db 0eah,0cah,0e8h,0cch, 0d4h,0ech,0c3h,0c2h
db 0c9h,0c0h,0c8h,0f4h, 0f5h,0f2h,0dah,0f9h ; column 9
db 0cch,0d5h,0dch,0a2h, 0a3h,0d9h,3fh,0d3h
db 0e1h,0edh,0f3h,0fah, 0f1h,0d1h,0aah,0bah ; column 10
db 0bfh,0d2h,0ach,0bdh, 0bch,0a1h,0abh,0bbh
db 16 dup (3fh) ; column 11
db 16 dup (3fh) ; column 12
db 16 dup (3fh) ; column 13
db 3fh,0dfh, 4 dup (3fh), 0b5h,3fh ; column 14
db 5 dup(3fh), 0f8h,3fh,3fh
db 3fh,0b1h, 4 dup (3fh), 0f7h,3fh ; column 15
db 0b0h, 4 dup (3fh), 0b2h,0b7h,3fh
; from Code Page 863
cp863L1 db 0c7h,0fch,0e9h,0e2h, 0e2h,0e0h,0b6h,0a2h ; column 8
db 0eah,0ebh,0e8h,0efh, 0eeh,3dh,0c0h,0a7h
db 0c9h,0c8h,0cah,0f4h, 0cbh,0cfh,0fbh,0fah ; column 9
db 0a4h,0d4h,0dch,0a2h, 0a3h,0d9h,0dbh,3fh
db 0a6h,0b4h,0f3h,0fah, 0a8h,0a8h,0b3h,0afh ; column 10
db 0ceh,3fh,0ach,0bdh, 0bch,0beh,0abh,0bbh
db 16 dup (3fh) ; column 11
db 16 dup (3fh) ; column 12
db 16 dup (3fh) ; column 13
db 3fh,0dfh, 4 dup (3fh), 0b5h,3fh ; column 14
db 5 dup(3fh), 0f8h,3fh,3fh
db 3fh,0b1h, 4 dup (3fh), 0f7h,3fh ; column 15
db 0b0h, 4 dup (3fh), 0b2h,0b7h,3fh
; from Code Page 865
cp865L1 db 0c7h,0fch,0e9h,0e2h, 0e4h,0e0h,0e5h,0e7h ; column 8
db 0eah,0ebh,0e8h,0efh, 0eeh,0ech,0c4h,0c5h
db 0c9h,0e6h,0c6h,0f4h, 0f6h,0f2h,0fbh,0fah ; column 9
db 0ffh,0d6h,0dch,0f8h, 0a3h,0d8h,3fh,3fh
db 0e2h,0edh,0f3h,0fah, 0f1h,0d1h,0aah,0bah ; column 10
db 0bfh,3fh,0ach,0bdh, 0bch,0a1h,0abh,0a4h
db 16 dup (3fh) ; column 11
db 16 dup (3fh) ; column 12
db 16 dup (3fh) ; column 13
db 3fh,0dfh, 4 dup (3fh), 0b5h,3fh ; column 14
db 5 dup(3fh), 0f8h,3fh,3fh
db 3fh,0b1h, 4 dup (3fh), 0f7h,3fh ; column 15
db 0b0h, 4 dup (3fh), 0b2h,0b7h,3fh
data ends
code segment public 'code'
extrn decout:near, isfile:near, newfn:near, comnd:near, atoi:near
extrn ermsg:near, clrfln:near, frpos:near, kbpr:near, perpr:near
assume cs:code, ds:data, es:nothing
; Set register SI to the offset of the ISO Latin-1 table appropriate to the
; currently active Code Page. Defaults to CP437 if no CP found.
LATIN1 proc near
mov si,offset L1cp437 ; assume CP437
cmp flags.chrset,437 ; current Code Page is 437?
je latin1x ; e = yes
mov si,offset L1cp850 ; assume CP850
cmp flags.chrset,850 ; current Code Page is 850?
je latin1x ; e = yes
mov si,offset L1cp860 ; assume CP860
cmp flags.chrset,860 ; current Code Page is 860?
je latin1x ; e = yes
mov si,offset L1cp863 ; assume CP863
cmp flags.chrset,863 ; current Code Page is 863?
je latin1x ; e = yes
mov si,offset L1cp865 ; assume CP865
cmp flags.chrset,865 ; current Code Page is 865?
je latin1x ; e = yes
mov si,offset userin ; user loadable incoming table
cmp flags.chrset,1 ; User-defined table?
je latin1x ; e = yes
mov si,offset L1cp437 ; default to CP437
latin1x:ret
LATIN1 endp
; Set reg BX to offset of table for Code Page to ISO 8859-1 Latin-1
cplatin proc near
mov bx,offset cp437L1 ; assume CP437
cmp flags.chrset,437 ; current Code Page is 437?
je cplatx ; e = yes
mov bx,offset cp850L1 ; assume CP850
cmp flags.chrset,850 ; current Code Page is 850?
je cplatx ; e = yes
mov bx,offset cp860L1 ; assume CP860
cmp flags.chrset,860 ; current Code Page is 860?
je cplatx ; e = yes
mov bx,offset cp863L1 ; assume CP863
cmp flags.chrset,863 ; current Code Page is 863?
je cplatx ; e = yes
mov bx,offset cp865L1 ; assume CP865
cmp flags.chrset,865 ; current Code Page is 865?
je cplatx ; e = yes
mov bx,offset userout ; user loadable outgoing table
cmp flags.chrset,1 ; User-table?
je cplatx ; e = yes
mov bx,offset cp437L1 ; default to CP437
cplatx:ret
cplatin endp
; Output the chars in a packet, called only by receiver code.
; Enter with SI equal to pktinfo structure pointer.
PTCHR: mov decoutp,offset outbuf ; routine to call when buffer gets full
jmp short decode
; Dodecoding.
; Decode packet to buffer decbuf. Overflow of decbuf yields error ???
; Modifies regs BX, CX.
; Enter with SI equal to pktinfo structure pointer.
dodec proc near
push ax ; save reg
mov decoutp,offset dnulr ; routine to dump buffer (null)
call decode
push bx
mov bx,dbufpnt ; next char position
mov byte ptr [bx],0 ; null terminator
pop bx
pop ax
ret
dodec endp
dnulr: ret ; dummy buffer emptier
; Enter with [si].datlen = length of data, [si].datadr = address of data,
; DECOUTP = pointer to routine which writes output buffer
; Returns DBUFPNT = pointer to output buffer address (offset part)
; All packets are decoded except I, S, and A types.
; Flushes output buffer before returning.
; Returns carry clear if success, otherwise carry set
decode proc near
push si
push di
push es
push dx
push ds
pop es ; set es to data segment
mov dchrcnt,length decbuf ; size of output buffer
mov dbufpnt,offset decbuf ; decoded data placed here pending output
mov cx,[si].datlen ; length of source buffer data
mov si,[si].datadr ; source buffer address
mov di,dbufpnt ; destination of data
mov bl,trans.squote ; regular quote char
xor dh,dh ; assume no quote char
cmp trans.ebquot,'N' ; any 8-bit quoting?
je decod1 ; e = no quoting
cmp trans.ebquot,'Y' ; or not doing it?
je decod1 ; e = no need to quote
mov dh,trans.ebquot ; otherwise use 8-bit quote char
decod1: mov rptct,1 ; 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 al,trans.rptq ; repeat quote char?
jne dcod21 ; ne = no, continue processing it
or al,al ; doing repeat quoting? (0 if no)
jz dcod21 ; z = no, skip this part
lodsb ; get the size
dec cx ; modify buffer count
sub al,20H ; make printable
mov rptct,al ; remember how many repetitions
lodsb ; get the char to repeat
dec cx ; modify buffer count
dcod21: xor ah,ah ; assume no 8-bit quote char
cmp al,dh ; is this the 8-bit quot char?
jne decod3 ; ne = no
lodsb ; yes, get the real character
dec cx ; decrement # chars in packet
mov ah,80H ; turn on 8-bit quot char flag
decod3: cmp al,bl ; 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 ax,807fh ; only parity in ah, remove it in al
cmp al,bl ; quote char?
je decod4 ; e = yes, just go write it out
cmp al,dh ; 8-bit quote char?
je decod4 ; e = yes, just go write it out
cmp al,trans.rptq ; repeat quote character?
je decod4 ; e = yes, just write it out
cmp al,3fh ; char less than '?' ?
jb decod4 ; b = yes; leave it intact
cmp al,5fh ; char greater than '_' ?
ja decod4 ; a = yes; leave it alone
add al,40H ; make it a control char again
and al,7FH ; modulo 128 (includes DEL)
decod4: or al,ah ; or in parity
push cx
decod5: xor ch,ch
mov cl,rptct ; number of chars to be written
jcxz decod5c ; z = none
cmp cx,dchrcnt ; needed vs space available
jbe decod5a ; be = enough space for rptct chars
mov cx,dchrcnt ; insufficient space, do dchrcnt
decod5a:sub rptct,cl ; reduce number left to be written
sub dchrcnt,cx ; reduce output free space
pushf ; save sub status flags
shr cx,1
jnc decod5b ; nc = an even number
stosb ; store the odd byte
jcxz decod5d ; z = nothing else to write
decod5b:mov ah,al ; make a copy for word writes
rep stosw ; store cx words
decod5d:popf ; recover flags from sub dchrcnt,cx
jg decod5c ; g = space remaining in output buffer
push dx ; flush output buffer
push bx
push ax ; save the char
call decoutp ; output the buffer
pop ax ; recover repeated char
pop bx
pop dx
jc decod7 ; c = error if disk is full
mov di,dbufpnt
jmp short decod5 ; see if more chars need be written
decod5c:pop cx ; recover main loop counter
jmp decod1 ; get next source character
decod6: mov dbufpnt,di ; flush buffer before exiting decode
push cx
call decoutp ; flush output buffer before final ret
decod7: pop cx
pop dx
pop es
pop di
pop si
ret ; return successfully if carry clear
decode endp
; output decbuf, reset bufpnt & chrcnt
outbuf: mov cx,length decbuf ; get full size of buffer
sub cx,dchrcnt ; minus space remaining = # to write
jg outbu2 ; g = something to do
jmp outbf1
outbu2: mov dx,offset decbuf ; address of buffer
cmp trans.xtype,1 ; File Type Binary?
je outbu5 ; e = yes, no translation
cmp flags.destflg,1 ; disk destination?
je outbu5 ; e = yes, DOS will do it
cmp flags.eofcz,0 ; end on Control-Z?
je outbu5 ; e = no
push cx ; else map Control-Z to space
push di
push es
push ds
pop es ; data 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
; Character set translation section
outbu5: cmp trans.xtype,1 ; File Type Binary?
je outbu7 ; e = yes, no translation
cmp trans.xchset,0 ; Transfer Transparent?
je outbu7 ; e = yes, no translation
push cx
push si
push di
call latin1 ; set si to Latin-1 to CP table
mov bx,si ; set to bx for xlat
mov si,offset decbuf ; scan this buffer
mov di,si
push es
push ds
pop es
cld
outbu6: lodsb ; get a char
test al,80h ; high bit set?
jz outbu6a ; z = no, do not translate
and al,not 80h ; clear high bit
xlatb ; translate via bx table
outbu6a:stosb ; store char
loop outbu6 ; do all concerned
pop es
pop di
pop si
pop cx
outbu7: push bx
mov bx,diskio.handle ; file handle
mov ah,write2 ; write cx bytes
int dos
pop bx
jc outbf0 ; c set means writing error
cmp ax,cx ; did we write all the bytes?
je outbf1 ; 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
outbf0: mov dx,offset erms13 ; Error writing device
cmp flags.xflg,0 ; writing to screen?
jne outbf0a ; ne = yes
cmp flags.destflg,0 ; writing to printer?
jne outbf0a ; ne = no
mov dx,offset ermes9 ; Printer not ready message
outbf0a:call ermsg
stc ; return failure
ret
outbf1: add tfilsz,cx ; count received chars
adc tfilsz+2,0
test flags.remflg,dserial ; serial mode display?
jnz outb11 ; nz = yes, skip kbyte and % displays
cmp flags.xflg,0 ; receiving to screen?
jne outb11 ; ne = yes
call kbpr ; display kilobytes done
call perpr ; display percentage done
outb11: mov dbufpnt,offset decbuf ; address for beginning
mov dchrcnt,length decbuf ; size of empty buffer
clc ; return success
ret
; Get chars from file, encode them to pktinfo structure pointed to by si
gtchr: mov [si].datlen,0 ; say no output data yet
cmp filflg,0 ; is there anything in the buffer?
jne gtchr0 ; ne = yes, use that material first
call inbuf ; do initial read from source
jc gtchr1 ; c = no more chars, go return EOF
gtchr0: mov encinp,offset inbuf ; buffer refiller routine
jmp short encode
gtchr1: mov [si].datlen,0 ; report EOF
mov flags.eoflag,1 ; say eof
stc ; return failure
ret
; Do encoding.
; Enter with CX = data size, source of data is encbuf, si is pktinfo ptr.
; Writes output to area pointed to by [si].datadr.
; Returns char count in cx and [si].datlen with carry clear if success,
; else carry set if overflow.
; SI is preserved
doenc: clc
jcxz doen0 ; cx = 0 means nothing to encode
mov echrcnt,cx ; number of bytes of source data
mov ebufpnt,offset encbuf ; source of data
mov encinp,offset nulref ; null routine for refilling buffer
call encode ; make a packet with size in AX
mov cx,ax
doen0: ret
nulref: mov echrcnt,0 ; no data to return
stc
ret
; encode - writes data portion of kermit packet into [[si].datadr].
; expects encinp 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, ebufpnt to contain a pointer to
; the source of the characters, and [si].datadr to be output address.
; Returns: AX = the number of characters actually written to the buffer
; All packets except I, S, and A types are encoded.
; Returns carry clear for success, carry set otherwise.
encode proc near
push si ; save caller's si
mov al,trans.rptq ; repeat quote character
mov tmprptq,al ; working copy
mov rptct,1 ; number of times char is repeated
mov rptval,0 ; value of repeated char
mov cx,trans.maxdat ; maximum packet size
push ds
pop es ; make es:di point to data segment
mov di,[si].datadr ; address of output buffer
mov temp,di ; remember output buffer start address
mov si,ebufpnt ; pointer into source buffer
mov dl,trans.rquote ; send quote char
xor dh,dh ; assume no 8-bit quoting
cmp trans.ebquot,'N' ; refusing 8-bit quoting?
je encod1 ; e = yes
cmp trans.ebquot,'Y' ; or can but won't?
je encod1 ; e = yes
mov dh,0ffh ; remember we have to do it
encod1: cmp cx,0 ; any space left in output buffer?
jg encod2 ; g = yes
mov ax,di ; current output location
sub ax,temp ; minus start of buffer, ret cnt in AX
mov ebufpnt,si ; update pointer into source buffer
pop si ; restore caller's si
mov [si].datlen,ax
clc ; success
ret
encod2: cmp echrcnt,0 ; any data in buffer?
jg encod3 ; g = yes, skip over buffer refill
call encinp ; get another buffer full
jnc encod2a ; nc = success
encod8: pop si ; restore user's si
sub di,temp ; minus start of buffer
or di,di ; buffer empty?
jz encod9 ; z = yes
mov ax,di ; report size encoded
mov [si].datlen,ax
clc ; success
ret ; return success
encod9: xor ax,ax ; empty buffer
mov flags.eoflag,1 ; set eof flag
mov filflg,0 ; nothing in input buffer
mov [si].datlen,0
stc ; failure
ret ; return failure
encod2a:mov si,ebufpnt ; update position in source buffer
cmp echrcnt,0 ; any characters returned?
je encod8 ; e = none, assume eof
encod3: dec echrcnt ; decrement input count
cld ; forward direction
lodsb
cmp al,'Z'-40H ; is this a control-Z?
jne encd30 ; ne = no, skip eof-processing
cmp flags.eofcz,0 ; is a Control-Z an end of file?
je encd30 ; e = no
cmp trans.xtype,1 ; file type binary?
je encd30 ; e = yes, send as is
mov flags.eoflag,1 ; yes, set eof flag
mov filflg,0 ; say no more source data in buffer
mov echrcnt,0 ; ditto
jmp encod8 ; set character count and return
encd30: cmp tmprptq,0 ; doing repeat prefixing?
je encd3x ; e = no
cmp echrcnt,0 ; doing the last character?
jle encd31 ; le = yes, there is no next character
cmp rptct,94 ; max number that we can put in a byte
je encd31 ; e = at that limit
cmp al,[si] ; is current char == next char?
jne encd31 ; ne = no, break repeating
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 ; e = no, so just add this char
cmp rptct,3 ; within bounds for repeat prefixing?
jge encd32 ; ge = yes, use repeat prefixing
mov al,rptct ; number of copies
xor ah,ah ; push back
sub si,ax ; not enough characters to warrant it
mov rptval,0 ; clear out this value
mov tmprptq,0 ; pretend we're not doing prefixing
add echrcnt,ax ; adjust input buffer pointer
jmp encod1 ; reprocess those characters
encd32: push ax ; do repeat prefixing - save data
mov al,trans.rptq ; insert 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 ; insert into buffer
dec cx
pop ax ; get back the actual character
mov rptct,1 ; reset repeat count
mov rptval,0 ; and this
encd3x: or dh,dh ; doing 8-bit quoting?
jz encod4 ; z = no, forget this
test al,80h ; parity on?
jz encod4 ; z = 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
jb encod5 ; b = control char
cmp al,del ; delete?
je encod5 ; e = yes, go quote it
cmp al,dl ; quote char?
je encod6 ; e = yes, go add it
or dh,dh ; doing 8-bit quoting?
jz encd41 ; z = no, don't translate it
cmp al,trans.ebquot ; 8-bit quote char?
je encod6 ; e = yes, just output with quote
encd41: cmp trans.rptq,0 ; doing repeat prefixing?
je encod7 ; e = no, don't check for quote char
cmp al,trans.rptq ; 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 ; ne = no
mov al,trans.rptq ; real repeat quote char
mov tmprptq,al ; restore repeat quote char
jmp encod1 ; loop around for some more
encd7x: dec rptct ; count another entry of this char
jmp encod1 ; with quoting and all
encode endp
; Fill encode source buffer, report KB and percentage done.
; Return carry clear for success
; modifies ax
inbuf proc near
cmp flags.eoflag,0 ; reached the end?
je inbuf0 ; e = no
stc ; return failure
ret
inbuf0: push dx
push bx
push cx
mov bx,diskio.handle ; get file handle
mov cx,buffsz ; record size
mov dx,offset buff ; buffer
mov ebufpnt,dx ; buffer pointer
mov ah,readf2 ; read a record
int dos
jc inbuf1 ; c = error, ie file not open
or ax,ax ; any bytes read?
jnz inbuf2 ; nz = yes (the number read)
inbuf1: mov flags.eoflag,1 ; set End-of-File
mov filflg,0 ; buffer empty
mov echrcnt,0 ; zero bytes left in buffer
pop cx
pop bx
pop dx
stc ; failure
ret
inbuf2: add tfilsz,ax ; total the # bytes transferred so far
adc tfilsz+2,0 ; it's a double word
mov echrcnt,ax ; number of chars read from file
mov filflg,1 ; buffer not empty
test flags.remflg,dserial ; serial display mode?
jnz inbuf3 ; nz = yes, skip kbyte and % display
push si
push ax
call kbpr ; show kilobytes sent
call perpr ; show percent sent
pop ax
pop si
; Character set translation section
inbuf3: cmp trans.xchset,0 ; Transfer Transparent?
je inbuf6 ; e = yes, no translation
cmp trans.xtype,1 ; File Type Binary?
je inbuf6 ; e = yes, no translation
push ax ; save buffer count
mov cx,ax ; loop counter
push si
push di
call cplatin ; set bx to offset CP to Latin-1 table
mov si,offset buff ; scan this buffer
mov di,si
push es
push ds
pop es
cld
inbuf4: lodsb ; get a char
test al,80h ; high bit set?
jz inbuf5 ; z = no, no translation
and al,not 80h ; remove high bit
xlatb ; translate via bx table
inbuf5: stosb ; store char
loop inbuf4 ; do all concerned
pop es
pop di
pop si
pop ax
inbuf6: pop cx
pop bx
pop dx
clc ; success
ret
inbuf endp
; GETFIL, called only by send code
; Enter with raw filename pattern in diskio.string
; Returns carry clear if success, else carry set
getfil proc near
mov filflg,0 ; 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
xor cx,cx ; 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: jmp getfcom ; do common code
getfil endp
; GTNFIL called by send code to get next file.
; Returns carry clear for success, carry set for failure.
gtnfil proc near
cmp flags.cxzflg,'Z' ; Did we have a ^Z?
jne gtnfi1 ; ne = no, else done sending files
stc ; carry set for failure
ret ; take failure exit
gtnfi1: mov filflg,0 ; 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
jnc getfcom ; nc = success, do common code
ret ; carry set means no more files found
gtnfil endp
; worker for getfil, gtnfil
getfcom proc near
push si
push di
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 ; (di)= local path + diskio.fname
mov di,offset encbuf ; name to send to host (no path)
call strcpy ; new string = old path + DOS's filename
push bx
push cx
test flags.remflg,dquiet ; quiet display?
jnz getfco1 ; e = yes, do not display filename
call clrfln ; position cursor & blank out the line
mov dx,offset templp
call prtasz
getfco1:call newfn ; update encbuf with "send as" name
pop cx
pop bx
mov ah,open2 ; file open
xor al,al ; 0 = open readonly
cmp dosnum,300h ; at or above DOS 2?
jb getfco2 ; b = no, so no shared access
or al,40h ; open readonly, deny none
getfco2:mov dx,offset templp ; filename string with path
int dos
jc getfco3 ; c = failed to open the file
mov diskio.handle,ax ; save file handle
xor ax,ax
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
clc ; carry clear for success
getfco3:pop si
pop di
ret
getfcom endp
; Get the file name from the data portion of the F packet or from locally
; specified override filename (in auxfile), displays the filename, does any
; manipulation of the filename necessary, including changing the name to
; prevent collisions. Returns carry clear for success. Failures return
; carry set with dx pointing at error message text.
; Called by file receive module in mssrcv.asm.
gofil: mov si,offset decbuf ; filename in packet
mov di,offset diskio.string ; place where prtfn finds name
call strcpy ; copy pkt filename to diskio.string
mov di,offset fsta.xname ; statistics external filespec area
call strcpy ; record external name
cmp auxfile,0 ; have override name?
jne gofil1 ; ne = yes
cmp flags.xflg,0 ; receiving to screen?
jne gofil0a ; ne = yes, filename becomes CON
cmp flags.destflg,1 ; destination is disk?
je gofil1 ; e = yes
mov di,offset printer ; assume PRN is local file name
jb gofil0b ; b = yes
gofil0a:mov di,offset screen ; use CON (screen) as local file name
mov flags.xflg,1 ; say receiving to screen
gofil0b:xchg di,si ; di --> decbuf, si --> file name
call strcpy ; put local name (si) into decbuf
mov nmoflg,1 ; say that we have a replacement name
jmp gofil9 ; final filename is now in 'decbuf'
gofil1: mov nmoflg,0 ; assume no override name
cmp auxfile,0 ; overriding name from other side?
jne gofi1e ; ne = yes
jmp gofil4 ; e = no, get the other end's filename
gofi1e: mov nmoflg,1 ; say using an override name
mov ax,offset auxfile ; get local override filename
cmp word ptr auxfile+1,003ah; colon+null?(primative drive spec A:)
je gofil3 ; e = yes, skip screwy DOS response (No Path)
cmp word ptr auxfile,'..' ; parent directory?
jne gofi1g ; ne = no
cmp word ptr auxfile+1,002eh ; dot dot + null?
je gofi1b ; e = yes, process as directory
gofi1g: cmp word ptr auxfile,002eh ; dot + null (current 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 filtst.fname,2eh ; directory name?
je gofi1b ; e = yes, process as directory
cmp auxfile+2,5ch ; a root directory like b:\?
jne gofi1d ; ne = no. (DOS is not helpful with roots)
cmp auxfile+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 auxfile ; auxfile is a (sub)directory 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 auxfile ; local string
call fparse ; split local string
mov di,offset temprp ; remote path
mov si,offset temprf ; remote file
mov dx,offset decbuf ; remote string
mov decbuf+64,0 ; force filename to be <= 64 chars
call fparse ; split remote string
test flags.remflg,dserver ; running in Server mode?
jz gofi3c ; z = no
test denyflg,sndflg ; is Deny Send mode in operation?
jz gofi3c ; z = no
mov temprp,0 ; DENY, means remove remote path
gofi3c: mov si,offset templp ; copy local path to
mov di,offset decbuf ; final filename
call strcpy ; do the copy
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 ; append path and filename again
; offset decbuf holds the new filename
;
; recheck legality of filename in 'decbuf'
gofil4: mov decbuf+64,0 ; guard against long filenames
mov di,offset temprp ; remote path
mov si,offset temprf ; remote file
mov dx,offset decbuf ; 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 gofil5 ; 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
gofil5: 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 nmoflg,1 ; say that we have a replacement name
; filename is now in 'decbuf', all converted
gofil9: test flags.remflg,dquiet ; quiet display mode?
jnz gofi10 ; nz = yes, don't print it
test flags.remflg,dserial ; serial display mode?
jz gofi9a ; z = no
mov ah,prstr
mov dx,offset crlf ; display cr/lf
int dos
gofi9a: call prtfn ; show packet filename
cmp nmoflg,0 ; using local override name?
je gofil9b ; e = no
cmp flags.xflg,0 ; receiving to screen? (X versus F)
jne gofil9b ; ne = yes
mov ah,prstr
mov dx,offset asmsg ; print " as "
int dos
mov dx,offset decbuf ; plus the local filename
call prtasz ; print asciiz string
gofil9b:mov ah,flags.remflg ; display a following cr/lf?
and ah,dserial ; for serial display mode
or ah,flags.xflg ; receiving to screen
jz gofi10 ; z = neither, no cr/lf
mov ah,prstr ; finish the line with cr/lf
mov dx,offset crlf
int dos
gofi10: mov ax,offset decbuf ; point to name
cmp flags.flwflg,1 ; overwrite existing file?
jne gofi10b ; ne = no
jmp gofi16 ; e = yes
gofi10b:call isfile ; does it exist?
mov ax,offset decbuf ; reload ptr in case
jc gofi16 ; carry set = no, just proceed
mov ah,open2 ; could it be a device name?
xor al,al ; open readonly
cmp dosnum,300h ; above DOS 2?
jb gofi10a ; b = no, so no shared access
or al,40h ; open for reading, deny none
gofi10a:mov dx,offset decbuf ; the filename
int dos
jc gofi11 ; c = cannot open so just proceed
mov bx,ax ; file handle
mov ah,ioctl
xor al,al ; 0 = get info
int dos
mov ah,close2 ; close it
int dos
mov ax,offset decbuf ; 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: cmp flags.flwflg,4 ; no-supersede existing file?
jne gofi12 ; ne = no (i.e., do a rename)
mov flags.cxzflg,'X' ; say stop this file
mov word ptr decbuf,'UN'
mov decbuf+2,'L' ; file name of NUL
mov decbuf+3,0 ; asciiz
jmp short gofi13
gofi12: mov ax,offset decbuf ; point to filename again
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 ; say 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
call ermsg
stc ; failure, dx has msg pointer
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
xor ax,ax
mov diskio.sizehi,ax ; original file size is unknown
mov diskio.sizelo,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 = do not 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 ; create file
xor cx,cx ; 0 = attributes bits
int dos
jc gofi16b ; c = did not work, try regular open
mov diskio.handle,ax ; save file handle here
clc ; carry clear for success
ret
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
clc ; carry clear for success
ret
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
mov dx,offset erms12 ; unable to create file
call ermsg
push dx
mov dx,offset diskio.string ; print offending name
call prtasz ; display filename
pop dx
gofi19: stc ; failure, dx has msg pointer
ret
; Given incoming filename in 'decbuf'. 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
push ds
pop es
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 eighth bit
jz verfi5 ; z = end of name
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 nmoflg,1 ; say we have a replacement filename
verfi4: mov [si-1],al ; update name
jmp short 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.
; 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
; Make empty main name fields start with letter X, not digit 0
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
xor cx,cx ; a counter
cld ; set direction to be forward
uniq1: lodsb ; get a byte
cmp al,'.' ; have a dot?
je uniq2 ; e = yes
or al,al ; maybe null at end?
jnz uniq3 ; nz = 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
or cl,cl ; first char of filename?
jnz uniq2a ; nz = 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
or al,al ; null at end?
jnz uniq1 ; nz = no, continue copying
mov templf+7,'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+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: xor dx,dx ; high order part of generation #
div bx ; compute digit (unum / 10)
add dl,'0' ; make remainder part printable
mov [di],dl ; put into right place
or ax,ax ; 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: ds:dx = address of the string
; Output: cx = the byte count
; 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
xor al,al ; 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 diskio.string.
PRTFN PROC NEAR
test flags.remflg,dquiet ; quiet display mode?
jnz prtfn1 ; nz = yes, don't display filename
push ax ; saves for messy clrfln routine
push bx
push dx
call clrfln ; position cursor & blank out the line
mov dx,offset diskio.string
call prtasz
pop dx
pop bx
pop ax
prtfn1: 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 ; data 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
;;; Load a translation table for file transfer
load proc near
;; mov dx,offset loadtab ; keyword Transfer-character-set
;; xor bx,bx ; help
;; mov ah,cmkey
;; call comnd
;; jnc load0
;; ret
;;load0: mov dx,offset rdbuf ; buffer for filename
;; mov word ptr rdbuf,0
;; mov bx,offset loadhlp ; help
;; mov ah,cmword
;; call comnd ; get filename
;; jnc load1 ; nc = success
;; ret ; failure
;;load1: mov ax,offset rdbuf ; place for filename for isfile
;; call isfile ; does file exist?
;; jnc load1b
;;load1a: mov dx,offset infms6 ; unable to open file
;; mov ah,prstr
;; int dos
;; stc
;; ret ; c = does not exist
;;load1b: mov dx,ax
;; mov cx,134
;; mov ah,open2 ; file open
;; xor al,al ; 0 = open readonly
;; cmp dosnum,300h ; at or above DOS 2?
;; jb load2 ; b = no, so no shared access
;; or al,40h ; open readonly, deny none
;;load2: int dos
;; jc load1a ; if carry then error
;; mov diskio.handle,ax ; file handle
;; ; read and parse lines
;; mov linecnt,0 ; line counter
;; call readln ; L1, read and discard table name
;; jc load5 ; c = failure
;; call readln ; L2, COMMON or LOCAL
;; jc load5 ; c = failure
;; mov ax,word ptr rdbuf
;; or ax,2020h ; to lower case
;; mov tblptr,offset userin
;; cmp ax,'oc' ; "common"? (on the wire to local)
;; je load4 ; e = yes
;; mov tblptr,offset userout
;; cmp ax,'ol' ; "local"? (local to on the wire)
;; jne load5 ; ne = no, fail
;;
;;load4: call readln ; L3 name of comms line char set
;; jnc load6 ; success
;;load5: jmp loadx
;;
;;load6: call readln ; L4 bytes per char in above set
;; jc load5
;; mov si,offset rdbuf ; text, ah has char count
;; call atoi ; ax has value
;; jc load5 ; c = no number
;; cmp ax,1 ; one byte per char?
;; jne load5 ; ne = no, fail here
;;
;; call readln ; L5 chars/plane (94/96/128)
;; jc load7 ; c = failure
;; mov dx,offset rdbuf
;; call strlen
;; mov ah,cl
;; mov si,offset rdbuf ; text, ah has char count
;; call atoi ; ax has value
;; jc load7 ; c = no number
;; cmp ax,128 ; too many?
;; ja load7 ; a = yes, fail here
;;
;; call readln ; L6 name of local display char set
;; jnc load8
;;load7: jmp loadx
;;
;;load8: call readln ; L7 bytes per char in above set
;; jc load7
;; mov dx,offset rdbuf
;; call strlen
;; mov ah,cl
;; mov si,offset rdbuf ; text, ah has char count
;; call atoi ; ax has value
;; jc load7 ; c = no number
;; cmp ax,1 ; one byte per char?
;; jne load7 ; ne = no, fail here
;;
;; call readln ; L8 chars/plane (94/96/128)
;; jc load7 ; failure
;; mov dx,offset rdbuf
;; call strlen
;; mov ah,cl
;; mov si,offset rdbuf ; text, ah has char count
;; call atoi ; ax has value
;; jc load7 ; c = no number
;; cmp ax,128 ; too many?
;; ja load7 ; a = yes, fail here
;;
;; call readln ; L9 designator of comms line set
;; jc load8
;; call readln ; L10 Version of comms line set
;; jc load8
;; call readln ; L11 Registration num of comms set
;; jc load8
;; call readln ; L12 direction of writing
;; jc load8
;; call readln ; L13 number of entries in table below
;; jc load7
;; mov dx,offset rdbuf
;; call strlen
;; mov ah,cl
;; mov si,offset rdbuf ; text, ah has char count
;; call atoi ; ax has value
;; jc load7 ; c = no number
;; mov xlines,ax
;;
;; call readln ; L14 count of filler lines before
;; jc load7 ; table below
;; mov dx,offset rdbuf
;; call strlen ; length to cx
;; mov ah,cl
;; mov si,offset rdbuf ; text, ah has char count
;; call atoi ; ax has value
;; jc load7 ; c = no number
;; mov cx,ax ; count of filler lines
;; jcxz load10 ; z = none
;;load9: push cx
;; call readln ; L15 et seq, filler lines
;; pop cx ; read and discard
;; jc loadx
;; loop load9
;;
;;load10: dec xlines ; Translation data lines
;; cmp xlines,0 ; any left?
;; jge load11 ; ge = yes
;; jmp loady
;;load11: call readln ; translation table line(s)
;; jc loadx ; c = failure
;; mov si,offset rdbuf ; the buffer
;; mov dx,si
;; call strlen ; length to cx
;; mov ah,cl ; count for atoi
;; call atoi ; get "from" number
;; jc loadx ; failure
;; test al,80h ; referring to high bit set (GR)?
;; jnz load12 ; nz = yes
;; jmp loadx
;;load12: and ax,not 0ff80h ; strip bit for GR table
;; mov temp,ax ; save here
;; mov dx,si
;; call strlen
;; mov ah,cl ; count
;; call atoi ; get "to" number
;; mov bx,tblptr ; point at table
;; add bx,temp ; locate entry
;; mov [bx],al ; store new value
;; jmp load10 ; repeat til done
;;
;;loadx: mov dx,offset badvalue ; complain
;; mov ah,prstr
;; int dos
;; mov ax,linecnt ; show line number
;; call decout
;; mov ah,conout
;; mov dl,':'
;; int dos
;; mov dx,offset rdbuf ; show the line
;; call prtasz
;;loady: mov bx,diskio.handle
;; mov ah,close2 ; close the file
;; int dos
clc
ret
load endp
;;
;;readln proc near
;; push ax
;; push bx
;; push cx
;; push dx
;; push di
;; inc linecnt ; line counter
;; mov cx,82 ; 82 bytes, including trailer
;; mov temp,0 ; leading whitespace and comment flgs
;; mov di,offset rdbuf ; destination buffer
;; mov bx,diskio.handle ; file handle
;;readln1:push cx ; read from file
;; mov cx,1 ; read 1 char
;; mov dx,di ; place here
;; mov byte ptr [di],0 ; insert terminator
;; mov ah,readf2
;; int dos
;; pop cx
;; jc readlnx ; c = read failure
;; or ax,ax ; count of bytes read
;; jz readlnx ; z means end of file
;; cmp byte ptr [di],LF ; LF?
;; je readln3 ; e = yes, ignore it
;; cmp byte ptr [di],CR ; end of line?
;; je readln4 ; e = yes, exit
;; cmp byte ptr [di],';' ; start of comment?
;; jne readln6 ; ne = no
;; mov byte ptr temp+1,1 ; say comment has started
;; jmp short readln3 ; do not store it
;;readln6:cmp byte ptr temp+1,0 ; seen comment semicolon yet?
;; jne readln3 ; ne = yes, do not store comment
;; cmp byte ptr temp,0 ; seen non-spacing char yet?
;; jne readln2 ; ne = yes
;; cmp byte ptr [di],' ' ; is this a space?
;; je readln3 ; e = yes, skip it
;; cmp byte ptr [di],TAB ; or a tab?
;; je readln3 ; e = yes, skip it
;; mov byte ptr temp,1 ; say have seen non-spacing char
;;readln2:cmp flags.takflg,0 ; echo Take files?
;; je readln2a ; e = no
;; mov ah,conout
;; mov dl,byte ptr [di]
;; int dos
;;readln2a:inc di ; next storage cell
;;readln3:loop readln1 ; loop til end of line
;;readln4:cmp flags.takflg,0 ; echo Take files?
;; je readln4a ; e = no
;; mov ah,prstr
;; mov dx,offset crlf
;; int dos
;;readln4a:clc
;; mov byte ptr [di],0 ; insert final terminator
;; jmp short readlnx
;;
;;readln5:stc ; set carry for failure to read
;;readlnx:pop di
;; pop dx
;; pop cx
;; pop bx
;; pop ax
;; ret
;;readln endp
code ends
end