home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CP/M
/
CPM_CDROM.iso
/
cpm
/
utils
/
squsq
/
fcrnch11.lbr
/
FCRUNCH.MZC
/
FCRUNCH.MAC
Wrap
Text File
|
1986-12-24
|
20KB
|
878 lines
title 'FCRUNCH multi-file cruncher'
;
ver equ 11
;
; Crunch file 1 to file 2. By C.B. Falconer.
;
; d>FCRUNCH [-[c][k][p][q]] [d[u]:]afnin.aft [d[u]:][afnout.aft]
; crunches afnin.aft to afnout.aft
; (with full du addressing, across users, drives)
; the (optional) -c causes confirmation per file crunched
; -k causes no existing files to be erased
; -p causes existing output file erasure
; -q suppresses running messages
; Default output name is input with a middle Z in filetype.
;
; 1.1 (86/12/20) Only version # changed, relinked to CRN v25, which
; allows for trapping of particular output sequences. This now
; traps the sequence <0dh>,<040h> (with possible high bits set)
; and injects a nulcode to output. This avoids problems with
; Telenet/PcPursuit (or so I am told). CRN can be configured
; to trap any 2 byte sequence, by reassembly. - cbf
;
; Created as a modification of FCOPY 1.1. Needs BUFFLIB v1.4 up
;
; ASSEMBLY (rmac is not usable without changes)
; A>m80 fcrunch,=fcrunch
; or
; A>slrmac fcrunch/r (much faster)
;
; CAUTION - nnnn/mmmm numbers below are examples, can change
;
; LINKING with L80 (slowest by far)
;
; A>l80 /p:100,/d:4000,fcrunch,crn,bufflib/s,/u,/r
;
; Link-80 3.44 . . . .
; Data 4000 405A < 90>
; Program 0100 0ADD < dddd>
;
; */p:100,/d:nnnn,fcrunch,crn,bufflib/s,fcrunch/n,/e
; ^ using nnnn = 0ADD from above line (example)
;
; LINKING with SLRNK
;
; A>slrnk /p:100,/d:4000,fcrunch,crn,bufflib/s,/u,/r
;
; Superlinker . . . .
; 0100-0ADC (09DD) 973E left
; Superlinker . . . .
;
; %/p:100,/d:mmmm,fcrunch,crn,bufflib/s,fcrunch/n,/e
; ^ using mmmm = 0ADD, i.e. 0ADC + 1 (example)
;
; LINKING with SLRNK+ (fastest and easiest, no copying numbers)
;
; A>slrnk+ /a:100,/j,fcrunch,crn,bufflib/s,fcrunch/n,/e
; (does it all)
;
; Externals in BUFFLIB. See BUFFERS.DOC
extrn .getusr, .xltusr, .setusr; user parsing
extrn .wildx, .wldck, .pfnmdu; file parsing
extrn .options, .skipblks; command parsing
extrn .fncpy, .nxtout, .nxtfn; fname operations
extrn .dos; bdos(a), save regs
extrn .idiv, .imul, .dcmp
extrn .tdzs, .tfnam, .crlf; utility
extrn .couta, .tdzsf, .blk
extrn .initfcb, .drvlock
extrn .bfwopen, .bfclose; write opens/close
extrn .bfropen; read opens
extrn .bfgetc, .bfputc; buffered file i/o
extrn b.ohead; ext. constants
extrn .bver; library version
extrn .endata; Available memory area
;
extrn crn; crunch package
extrn incnt, outcnt, nxtcod, ttotal; display vars
entry getchr, outbyt; crn i/o
;
buflibver equ 14; minimum to link
stkmargin equ 5*1400h + 256; bytes for crn & stack
;
boot equ 0
bdos equ boot+5
tfcb equ boot+05ch; used to hold outname template
defdma equ boot+080h
;
cr equ 0dh
lf equ 0ah
t equ 09h
crnchid equ 076feh; Standard header
stpmax equ 40; max size (+1) of any stamp
;
; errors
xhelp equ 0; no error, give help
xempty equ 1; file empty
xcrn equ 2; file already crunched/squeezed
xstkovf equ 3; memory overflow
xwild equ 4; incompatible wildcards
xtoself equ 5; copying into self
xnodir equ 6; fcreate failure
xwrterr equ 7; write error
xusrabt equ 8; user abort
xbadlib equ 9; linked to wrong library
xsaved equ 10; Old file not eraseable
xbadnam equ 11; Unable to create new name
xnofile equ 12; input file not found
xok equ 13; done, without errors
;
; Dos function calls
cin equ 1
pstrg equ 9
csta equ 11
@fopen equ 15
@purge equ 19
;
; Initialize
begin: jmp bgn
;
; Option image. Zero locations to pre-set.
; Make letters lower case to forbid setting.
optimg: db '-',optlgh
db 'C'; Confirm "crunch this file" option
db 'K'; Keep pre-existing output files
db 'P'; purge pre-existing output files
db 'Q'; Quiet option.
optlgh equ $-optimg-2
;
; Start up here
bgn: lhld bdos+1
mvi l,0; set stack at top of memory
sphl
call .getusr
sta entryusr
call .bver; This also ensures the lib version
cpi buflibver; module is linked and identified
mvi a,xbadlib
jc exeunt; linked to wrong library
lxi h,0
shld filesdone; zero count of files processed
shld stamp; default empty stamp
lxi d,defdma
call markeol; of input command line
inx d
lxi b,optimg
lxi h,options
call .options; from de^
; " "
; parse in/out file names
lxi h,fcbout
call .initfcb
lxi h,fcbin
call .initfcb; init in and out fcbs
call .pfnmdu
mov a,b; is 0 for default, else usr+1
call usrlok; now 1..max
sta inuser
lxi h,tfcb
call .initfcb
mvi b,0; in case no 2nd file parsed
call .skipblks
cpi '['
cnz .pfnmdu; no 2nd spec, reached the stamp
push d; save input parse pointer
mov a,b
call usrlok; now 1..max, no defaults left
sta outuser
lxi d,fcbin; ensure locked to drive for compare
call .drvlock; else default and specific drives
lxi d,tfcb; may erroneously appear different
call .drvlock
ldax d
sta fcbout; set output drive id
lda fcbin+1
pop d; get input parse pointer back
sui ' '
jz exeunt; a=0, help message
; " "
; Parse the remaining tail into the stamp buffer
call rstamp; from de^
; " "
; Set default output names, check compatible wild cards
lxi h,fcbin
lxi d,tfcb
call sdefault; if no output, make same as input
call .wldck; Check wild cards compatible
mvi a,xwild
jc exeunt; Incompatible wildcards
; " "
; Expand any wild cards
lxi h,.endata
shld fnptr
lda inuser
dcr a
call .setusr
lxi d,fcbin
call .wildx; expand fcbin into wild list
mvi a,xstkovf
jc exeunt; Ran out of memory
shld @outbuff; mark available memory
xchg; de := @outbuff
mov l,c
mov h,b
shld fncount; number of files matched
; " "
; Calculate space available for buffers and allocate them
lxi h,b.ohead+b.ohead
dad d
xchg; adjust base of storage
lxi h,-stkmargin
dad sp
mvi a,0; round down to page boundary
sub e
mov e,a
mov a,h
sbb d
mov d,a; form buffer size available
xchg
lxi d,0; 0 extend
lxi b,3
call .idiv; one third for outbuffer
xchg
mov a,l
ani 080h; round down to multiple of 128
mov l,a
shld bufsize
ora h
mvi a,xstkovf
jz exeunt; 0 size buffers just wont do
lxi d,b.ohead
dad d; space needed for complete buffer
xchg
lhld @outbuff
dad d
shld @inbuff; locate past output buffer
lxi d,b.ohead
dad d
xchg
lhld bufsize
dad h; double, two thirds for input buffer
dad d
shld @freemem; and locate available memory
; " "
; Now tfcb holds output file pattern, fnptr points to next input file
; name, and fncount holds file count to process. @outbuff points just
; above the file list and is allocated, @inbuff is allocated, memory
; from @freemem up, less an allowance for stack use, is available.
copy: lhld fncount
mov a,h
ora l
dcx h
shld fncount
jz done; no more files
call setfiles; setup input/output file names
mvi a,xbadnam
push psw
call showf; file names set up
pop psw
jc exeunt; Can't setup this name
lda confirm
ora a
cz askcfm
jz copy; ignore, try next
lhld outuser; to l
lda inuser
cmp l
lxi h,fcbout
lxi d,fcbin
cz cmpfns; users same, compare file names/drv
mvi a,xtoself
jz exeunt; can't copy to self
lhld bufsize
dad h; * 2 for input
mov c,l
mov b,h
lhld @inbuff
lxi d,fcbin
lda inuser
call .bfropen; open buffered input system
mvi a,xnofile
jc exeunt; input file not found
lxi d,fcbout
lda purge
ora a
lda outuser
cnz chkpurge; Check for erasure of old file
mvi a,xsaved
jnz copy2; and treat NO as an error
call .crlf
lda outuser
lhld bufsize
mov c,l
mov b,h
lhld @outbuff
call .bfwopen; open buffered output file
mvi a,xnodir
jc exeunt; fopen error
call crnch
jc copy1
lhld filesdone
inx h
shld filesdone
jmp copy; no error
;
; error (a). If non-terminal delete output file and continue,
; otherwise abort everything.
copy1: call delout
copy2: cpi xstkovf
jz exeunt; abort everything
call msgptr
call tstr
jmp copy
;
; purge output file
delout: push psw
push d
lda outuser
dcr a
call .setusr
lxi d,fcbout
mvi a,@purge
call .dos; remove the partial file
pop d
pop psw
ret
;
done: lhld filesdone
mov a,h
ora l
mvi a,xnofile
jz exeunt; no files found
call .crlf
call .tdzs
mvi a,xok
; " "
; output message index (a) and exit
exeunt: call msgptr
call tstr
lda entryusr; restore user at entry
call .setusr
jmp boot
;
; convert error index (a) into pointer (de) to error message
; a,f,d,e,h,l
msgptr: lxi h,errtbl
add a
add l
mov l,a; point to msgtable entry (a)
adc h
sub l
mov h,a
mov e,m; get pointer to message
inx h
mov d,m
ret
;
; messages for error codes 0 up
; ERROR MESSAGES ERROR CODES (0 up)
errtbl: dw helpmsg, emptymsg; xhelp, xempty
dw xcrnmsg, nomemsg; xcrn, xstkovf
dw wildmsg, selfmsg; xwild, xtoself
dw nodirmsg, wrterrmsg; xnodir, xwrterr
dw abtmsg, badlibmsg; xusrabt, xbadlib
dw ignoremsg, badnamsg; xsaved, xbadnam
dw nofind, filesmsg; xnofile, xok
;
helpmsg:
db 'FCRUNCH v', ver/10 + '0', '.', ver MOD 10 + '0'
db ' by C.B. Falconer',cr,lf,lf
; 1234567-1234567-1234567-1234567-1234567-1234567-1234567-
db ' keep old quiet input file',t, 'output file',cr,lf
db t, ' \ \',t, t, ' \',t, t, '\',cr,lf
db 'FCRUNCH {-{c}{k}{p}{q}} {d{u}:}afnin.aft {d{u}:}{afout.aft} {[id]}'
db cr,lf
db t, ' / /',t, ' /',t, t, ' /',t, t, ' /'
db cr,lf
db ' confirm purge source',t,'destination',t,t, 'idstring'
db cr,lf,lf
; 1234567-1234567-1234567-1234567-1234567-1234567-1234567-1234567-
db t,'[idstring] is anything enclosed in []',cr,lf
db t,'default destination is source name with modified "typ"',cr,lf,lf
db 'ex: FCRUNCH -p b5:fcopy.* c6:',t,'(crunches to C6: and erases)'
db cr,lf,'$'
xcrnmsg: db 'File already squeezed/crunched',cr,lf,'$'
emptymsg: db 'Empty file',cr,lf,'$'
nomemsg: db cr,lf,'Insufficient memory, '
abtmsg: db '..ABORTED..$'
wildmsg: db 'Incompatible wild cards, from/to$'
selfmsg: db 'Can''t crunch file to itself$'
nodirmsg: db 'Can''t create, directory full?$'
wrterrmsg: db 'Write error, disk full?$'
badlibmsg: db 'Linked to obsolete library$'
ignoremsg: db ' Not erased..',cr,lf,'$'
badnamsg: db ' Rename this input file$'
nofind: db ' Not found, no'
filesmsg: db ' files crunched$'
;
; mark end-of-line with nul, text buffer de^
; a,f,h,l
markeol:
ldax d
mov l,a
xra a
mov h,a
dad d
inx h
mov m,a; mark eol
ret
;
; Check for existance of file de^, user a. If found, query for
; erasure. Return z flag if not found, or if erasure permitted
; a,f
chkpurge:
dcr a; Using buffers variant for user
call .setusr
mvi a,@fopen
call .dos
inr a
rz; not found, all well
lda keepem
ora a
jz chkpg1; 0 is not a Y, no purge
push d
lxi d,query
call tstr
pop d
call cupsft
chkpg1: cpi 'Y'; Z flag for permission
ret
;
query: db ' Exists, ok to purge (y/N) ? $'
qcnfm: db ' Crunch it (Y/n) ? $'
;
; ask to confirm squeezing this file. Z flag for no
; a,f
askcfm: push d
lxi d,qcnfm
call tstr
pop d
; " "
; Console input char and kludgy upshift. Compared to 'N'
; a,f
cupsft: mvi a,cin
call .dos
ani 05fh
cpi 'N'
ret
;
; make file de^ same name as hl^ (name/ext only) if no spec
; a,f
sdefault:
inx d
ldax d
sui ' '
sta outspec; non-zero means output specified
ldax d
dcx d
rnz
jmp .fncpy; no specification, copy it
;
; Column header for noisy display
colhdr: lxi d,colmsg
; " "
; String de^ to console
; a,f
tstr: mvi a,pstrg
jmp .dos
colmsg: db ' in out ratio ca cr',cr,lf
db ' == === ===== == ==',cr,lf,'$'
;
; All files open, and buffers assigned.
; Crunch fcbin to fcbout byte by byte.
crnch: lda quiet
ora a
cnz colhdr
lxi h,0
shld cksum
dad sp
shld savesp; in case of error
call header; Make the standard header
lhld @freemem; Where to put the tables
mvi a,044h; use existing stack assignments &
call crn; allow reset when tbl full & 1024 ca's
rc; error exit
lhld cksum
mov a,l
call outbyt
mov a,h
call outbyt; include the checksum
lhld @outbuff
call .bfclose; close the output file
lhld xtraout
inx h
inx h
shld xtraout; allow for checksum
lda quiet
ora a
rz
call show
call .blk
mvi a,'('
call .couta
call inout; hl := input; de := output rcds
xchg
call .dcmp; flags on hl-de
xchg
cnc chksav; not smaller
jnc crnch8; not saved, de has message ptr.
call dvd8hl; rounding up
call .tdzs; input kbytes
xchg
lxi d,ktok
call tstr
call dvd8hl
call .tdzs; output kbytes
lxi d,kend
crnch8: call tstr
xra a; no error
ret
;
ktok: db 'k --> $'
kend: db 'k)',cr,lf,'$'
nosave: db 'Not smaller, not saved)',cr,lf,'$'
;
; Check for save of output file. Forced to no save here
; Set carry if file to be saved.
; Reset carry if file purged, when de is message pointer.
; a,f (de if no save only)
chksav: call delout
ora a
lxi d,nosave
ret
; setup input/output file names in fcbin/fcbout, using the globals
; fnptr, tfcb. Carry if unable to create a suitable file name.
; a,f,b,c,d,e,h,l
setfiles:
lxi d,fcbin
lhld fnptr
call .nxtfn; load the next file name
lxi d,16
dad d
shld fnptr; advance source name pointer
lxi d,fcbout; setup fcbout by
lxi h,tfcb; copying template
lxi b,fcbin; and replacing wild loc'ns
call .nxtout
lda outspec
ora a
rnz; file specified
; " "
; Now modify the output file type
lxi h,fcbout+9
mov a,m
cpi ' '
jz setf1; no extension, make it ZZZ
inx h
mov a,m
cpi 'Z'
jnz setf2; Revised file type to xZx
mvi m,'Z'
inx h
mov a,m
cpi 'Z'
jnz setf2; xZZ does it
mvi m,'Z'
dcx h
dcx h
mov a,m
cpi 'Z'
jnz setf2; ZZZ does it
stc
ret; Can't rename this file
setf1: mvi m,'Z'
inx h
mvi m,'Z'
inx h
setf2: mvi m,'Z'
ora a; clear any carry
ret
;
; show file to be transferred
; a,f,b,c,d,e,h,l
showf: lda quiet
ora a
cnz .crlf
lda inuser
dcr a; to cpm usage
lxi d,fcbin
call .tfnam; input file id
lxi d,xfrtomsg
call tstr; '==>'
lda outuser
dcr a; to cpm usage
lxi d,fcbout
call .tfnam; output file id
; " "
; Check for user abort
; a,f
ckabt: mvi a,csta
call .dos
rz; no console interrupt
mvi a,cin
call .dos
cpi 3
mvi a,xusrabt
jz exeunt; user abort
ret
;
xfrtomsg: db ' ==> $'
;
; check fcbs de^ and hl^ are different names, else zero flag
; a,f
cmpfns: push b
push d
push h
dcx h; pre-decrement
dcx d
mvi b,12; names and drive ids
cmpfn1: inx h
inx d
ldax d
xra m
ani 07fh; ignore attributes
jnz cmpfn2
dcr b
jnz cmpfn1
cmpfn2: pop h
pop d
pop b
ret
;
; Make a standard crunched file header
header: mvi a,crnchid shr 8
ora a; set nz, no display yet
call outbyt
mvi a,crnchid AND 0ffh
ora a; set nz, no display yet
call outbyt
lxi h,3; 2 already, 0 byte coming
xchg
lxi h,fcbin
call outnm; mark the source file id
lxi h,stamp
call outstg; emit the user stamp
xchg
shld xtraout; save string size etc.
ori 0ffh; reset z flag
mvi a,0; emit the 0 string terminator
; " "
; output a to buffered output file. Savesp initialized.
; Input Z flag triggers display mechanism. CRN module linkage
; a,f,c
outbyt: mov c,a
push h
cz show; display statistics etc.
lhld @outbuff
call .bfputc
pop h
rnc; no error
lhld savesp
sphl
mvi a,xwrterr
jmp exeunt; i/o error
;
; Linkage for crn module
; a,f,h,l
getchr: lhld @inbuff
call .bfgetc; get a byte. Carry for eof.
rc; no checksum update at eof
lhld cksum
push psw
add l
mov l,a
adc h
sub l
mov h,a
shld cksum
pop psw
ret
;
; Output string hl^ until 0 byte. Countem in de
; a,f,c,h,l
outstg: mov a,m
ora a
rz
inx d; count chars
call outbyt; nz flag, will not trip display
inx h
jmp outstg
;
; Output file name hl^. Full blank fill the type field
outnm: push b
mvi b,8; max chars in file name
push h; save start point
outnm1: inx h
mov a,m
inx d; count chars emitted
cpi ' '
jz outnm2; done file name
call outbyt; nz, no display trip
dcr b
jnz outnm1
inx d; for coming '.'
outnm2: mvi a,'.'
ora a; nz, prevent display
call outbyt
pop h; get start point back
lxi b,8; point to type field
dad b
mvi b,3
outnm3: inx h
mov a,m
inx d
ora a; nz, prevent display
call outbyt
dcr b
jnz outnm3
pop b
ret
;
; Get input/output records to hl, de respectively
; a,f,d,e,h,l
inout: lhld incnt+1; LS byte is zero
dad h; double, in records
lda incnt
add a
jnc inout1; not an extra record
inx h
inout1: adi 252; 2 * (127-1). EOF was counted at end.
jnc inout2; no partial record to round up
inx h
inout2: push h
lhld outcnt; only useful at end
mvi h,0
xchg
lhld xtraout
dad d
lxi d,127; round up to records
dad d
dad h; double, records to h
mov a,h; additional
lhld outcnt+1; LS byte is zero
dad h; double, to records
add l
mov l,a; + the extra bits
adc h
sub l
mov h,a; form records emitted (rounded up)
xchg
pop h
ret
;
; Show any statistics etc.
; a,f,h,l
show: call ckabt; check for user abort
lda quiet
ora a
rz; in quiet mode
push b
push d
mvi a,cr
call .couta
call inout; get input/output records
call tdzs6f; show input records
push h
xchg
call tdzs6f; show output records
xchg
lxi b,200; for rounding
call .imul; dehl := de*bc
pop b
call .idiv; de := dehl/bc = input/output*200
xchg
inx h; round result
call dvd2hl; divide / 2 (for 200 above)
mvi a,5
call .tdzsf
mvi a,'%'
call .couta
lhld nxtcod
call tdzs6f
lhld ttotal
call tdzs6f
pop d
pop b
ret
;
; Shift hl right 3 (divide by 8), rounding up
; a,f,h,l
dvd8hl: push d
lxi d,7
dad d
pop d
call dvd2hl
call dvd2hl
; " "
; Shift hl right 1. RH bit to carry
; a,f,h,l
dvd2hl: mov a,h
ora a
rar
mov h,a
mov a,l
rar
mov l,a
ret
;
; Write hl (dec) in 6 char. field. with at least 1 leading blank
; a,f
tdzs6f: mvi a,6
jmp .tdzsf
;
; Parse the command tail into the stamp buffer
; a,f,b,d,e,h,l
rstamp: lxi h,stamp
call .skipblks
rc; EOL, no tail
cpi '['
rnz; not a valid marker
mvi b,stpmax-1
rstp1: dcr b
jz rstp2; max storage used
mov m,a
inx h
cpi ']'
jz rstp3
inx d; (CCP+ can allow lc command tails)
ldax d; not .nextch, don't upshift
cpi ' '
jnc rstp1
rstp2: mvi m,']'; jam in the missing ']'
inx h
rstp3: mvi m,0; default EOL
ret
;
; Lock the user # (0 means default) to an absolute value.
; Returns in range 1..maxuser, and cpm calls use this -1.
; This is because the buffer system can record "default user"
; as distinct from "specified user".
; a,f
usrlok: call .xltusr; now range 0..maxuser
inr a; now 0 is forbidden.
ret
;
dseg; LINK AFTER all code areas
options: ds 2; Standard header
confirm: ds 1; Flog for confirmation per file
keepem: ds 1; Flag to keep old files
purge: ds 1; Flag for copy verification
quiet: ds 1; flag for quiet operation
if ($-options)-2 ne optlgh
+++ Error in option storage assignment +++
endif
;
entryusr: ds 1; User in effect at startup
outspec: ds 1; non-zero if output file specified
;
; inuser/outuser are 0 for current user, user+1 if specified
inuser: ds 1; User # for fcbin
outuser: ds 1; User # for fcbout
;
fcbin: ds 36; Input fcb
fcbout: ds 36; Output fcb
bufsize: ds 2; space available for outbuff
@inbuff: ds 2; pointer to input buffer, 2 * bufsize
@outbuff: ds 2; pointer to output buffer, 1 * bufsize
@freemem: ds 2; pointer to available memory
cksum: ds 2; for checksum accumulation
filesdone: ds 2; count of files processed
fncount: ds 2; count of files to process
fnptr: ds 2; pointer to NEXT file to process
savesp: ds 2; for aborts during writes
xtraout: ds 2; keep track of overhead bytes added
stamp: ds stpmax; User entered stamp
end
hU