; FSPLIT.Z80 ; Vers equ 10 ; version number SubVers equ ' ' ; modification level ; ; Splits a file into several pieces by record count, line count, or a ; marker character. For ZCPR3 only. ; ; USAGE: ; ; FSPLIT {dir:}infile {dir:}{outfile} {{/}options} ; ; If no outfile name is given, it will have the same name as the infile. ; The filetypes of the outfiles will begin with 001 and increment (002, ; 003, etc.). ; ; OPTIONS: ; ; n Output file size in records or lines. (As distributed, the ; default is 320 -- 40 kilobytes by record method.) ; ; K File size is in kilobytes. Automatically sets R option. ; ; L Split file by line count. ; ; M Split file when when tag marker is found. As distributed, ; the tag marker is ^P. ; ; O Object file, split on record boundary and ignore end-of-file ; characters (^Z). Automatically sets R option. ; ; Q Toggles quiet mode. Quiet mode is set by the ZCPR3 quiet ; flag or by a configuration byte (non-zero defaults to ; quiet mode). Option Q toggles the current mode. ; ; R Split file by record (sector) count. (As distributed, this ; is the default.) ; ; T Text file, split only at end of line and observe end-of-file ; character. (As distributed, this is the default.) ; ; For more information, see accompanying documentation file. ; ; Version 1.0 -- January 8, 1991 -- Gene Pizzetta ; Initial release. ; ; Gene Pizzetta ; 481 Revere Street ; Revere, MA 02151 ; ; Newton Centre Z-Node: (617) 965-7259 ; Ladera Z-Node Central: (213) 670-9465 ; GEnie: E.PIZZETTA ; Voice: (617) 284-0891 ; ; System addresses . . . ; CpmFcb equ 5Ch AltFcb equ 6Ch CpmDma equ 80h ; ; ASCII characters . . . ; CtrlC equ 03h ; ^C BS equ 08h ; backspace TAB equ 09h ; tab LF equ 0Ah ; linefeed CR equ 0Dh ; carriage return CpmEof equ 1Ah ; CP/M end-of-file character (^Z) ; ; The following buffer sizes are in sectors (records) of 128 bytes. ; They may may be set to any number of sectors up to a maximum of 255. ; Of course, you can't have two buffers of 32K if you plan to have ; FSPLIT and your operating system in memory at the same time. ; InSiz equ 128 ; input buffer in sectors (128=16K) OutSiz equ 128 ; output buffer in sectors (128=16K) ; ; Following routines are from ZSLIB, VLIB, Z3LIB, and SYSLIB ; .request zslib,vlib,z3lib,syslib1,syslib0 ; ext getstp,setstp ext z3vinit,stndout,stndend ext zsyschk,getquiet,gzmtop,prtname,puter2,inverror ext f$open,f$make,f$close,f$read,f$write ext initfcb,setdma,codend,retud,logud,condin,cout,epstr ext pfn2,pafdc,phldc,phlfdc,isdigit,eval10,comphd,mulhd ; public pstr ; jp Start ; db 'Z3ENV' db 1 Z3EAdr: dw 0FE00h ; address of environment descriptor ; ; Configuration . . . ; dw 0 ; filler db 'FSPLIT' ; filename for ZCNFG CFG file db Vers/10+'0',Vers mod 10+'0' QtFlag: db 0 ; 0=verbose, FFh=quiet DftFmt: db 0 ; default file format: 0=text, FFh=binary DftMth: db 00000001b ; method: b0=records, b1=lines, b2=marker DftSiz: dw 256 ; default file size MkrChr: db 'P'-'@' ; marker character ; ; Messages . . . ; MsgUse: db 'FSPLIT Version ' db Vers/10+'0','.',Vers mod 10+'0',SubVers,CR,LF db 'Splits large files into smaller ones.',CR,LF db 'Usage:',CR,LF,' ',0 MsgUs1: db ' {dir:}infile {dir:}{outfile} {{/}options}',CR,LF db 'An input filename is required.',CR,LF db 'Options:',CR,LF db ' n output file size [default ',0 MsgUs2: db ']',CR,LF db ' L size counted by lines',0 MsgUs3: db CR,LF db ' R size counted by records',0 MsgUs4: db CR,LF db ' M split file at markers (',0 MsgUs6: db CR,LF db ' K file size is in kilobytes',CR,LF db ' O object (binary) file',0 MsgUs7: db CR,LF db ' T text file',0 MsgUs8: db CR,LF db ' Q toggle quiet mode o',0 MsgUs9: db CR,LF db 'Options K and O also set option R.',0 MsgUon: db 'n',0 MsgUof: db 'ff',0 MsgDft: db ' [default]',0 MsgRd: db 'Splitting ',0 MsgRec: db ' by' MsgRe1: db ' records',0 MsgLin: db ' by' MsgLi1: db ' lines',0 MsgMkr: db ' at markers',0 MsgWrt: db CR,LF,' Writing ',0 MsgDot: db ' ..',0 MsgNSr: db ' No source file.',0 MsgFNF: db ' File not found.',0 MsgWEr: db ' Disk full!',0 MsgNSp: db ' No directory space.',0 MsgCEr: db ' Close error.',0 MsgAmb: db ' Ambiguous filename.',0 MsgDir: db ' Invalid directory.',0 MsgBdO: db ' Invalid option.',0 MsgBdN: db ' Invalid file size.',0 MsgMem: db ' Insufficient memory.',0 MsgAbt: db ' Aborted.',0 MsgDne: db ' files created.',0 ; Start: ld hl,(Z3EAdr) ; set up environment call zsyschk ; is this a Z-system? ret nz ; (nope) call z3vinit ld (OldStk),sp ; save old stack pointer call gzmtop ; get top of memory ld sp,hl ; ..and set up new stack push hl ; save top of memory ; call codend ; set buffer addresses ld (InBuf),hl ld de,128*InSiz add hl,de ld (OutBuf),hl ld de,128 ; add stack size and safety buffer add hl,de ex de,hl ; put in DE pop hl ; recover top of memory in HL or a sbc hl,de ; determine memory size ld a,h ; put number of pages in A cp OutSiz/2 ; compare to buffer size jr nc,Start1 ; (TPA okay) ld a,12 ; set error code ld hl,MsgMem ; insufficient memory jp ErExit ; Start1: call getquiet ; is ZCPR quiet flag set? rra ; make it 0 or FF sbc a,a jr nz,Start2 ; (yes) ld a,(QtFlag) ; no, get quiet config byte Start2: ld (OpQFlg),a ; ..and store in Q option flag ld hl,(DftFmt) ; set default format and method ld (FmtFlg),hl ld hl,(DftSiz) ; get default file limit ld (FilLmt),hl ; ..and store it ld hl,0 ld (FilCnt),hl ; clear counters ld (TypCnt),hl ld (OpKFlg),hl ; clear OpKFlg and FSFlag ld hl,CpmDma ; see if there's a tail ld a,(hl) or a jp z,Usage ; (no) call GetOpt ; get options ; Check for input file specification ld a,(FSFlag) ; any filespec? or a jp z,Usage ; (nope) ld a,(CpmFcb+1) ; check input filename cp ' ' ; is there one? jp nz,Start3 ; (yep) ld hl,MsgNSr ; source file required ld a,8 ; set error code jp ErExit ; Start3: ld hl,CpmFcb+1 ; check for ambiguous name call ChkAmb MovInp: ld hl,CpmFcb+1 ; move filename to input fcb ld de,InFcb+1 ld bc,11 ldir ld a,(CpmFcb+15) ; check for valid directory or a jp nz,InvDir ; (nope) ld a,(CpmFcb) ; get drive (A=1) or a ; is there one? call z,GetDft ; (no, get default) dec a ; make A=0 ld b,a ; put drive in B ld a,(CpmFcb+13) ; get user ld c,a ; put user in C ld (InUsr),bc ; store user and drive ; Check for output file specification ld a,(FSFlag) dec a jr z,MovOut ; (no output filespec) ld a,(AltFcb+1) cp ' ' ; do we have an output filename? jr z,MovOut ; (no) ld hl,AltFcb+1 ; check for ambiguous name call ChkAmb ld hl,AltFcb+1 ; okay, move filename jr MovFn ; MovOut: ld hl,CpmFcb+1 ; move input filename to output fcb MovFn: ld de,OutFcb+1 ld bc,11 ldir ld a,(AltFcb+15) ; check for valid directory or a jp nz,InvDir ; (nope) ld a,(AltFcb) ; get drive (A=1) or a ; is there one? call z,GetDft ; (no, get default) dec a ; make A=0 ld b,a ; put drive in B ld a,(AltFcb+13) ; get user ld c,a ; put user in C ld (OutUsr),bc ; store user and drive ; ld a,(OpQFlg) ; quiet option? or a jr nz,NoPrt ld hl,MsgRd ; print the file we're reading call epstr ld bc,(InUsr) ; B=drive, C=user ld de,InFcb+1 call PrtFn ld a,(MthFlg) bit 1,a ld hl,MsgLin jr nz,PrtMod bit 2,a ld hl,MsgMkr jr nz,PrtMod ld hl,MsgRec PrtMod: call epstr ld hl,MsgDot call epstr NoPrt: call OpnInp ; open input file call GetIni ; initialize GetC call OpnOut ; open first output file ; call RdLoop ; read and write files ; call ClsInp ; close input file call WrLast ; close output file call DatStp ; get date stamp, if any call PrtSiz ; print final file size ; Finish: ld a,(OpQFlg) ; quiet option? or a ld a,0 ; reset error flag ; jr nz,Exit ; (yes) ld a,CR call cout ld a,LF call cout ld hl,(TypCnt) ; get file type count call phlfdc ld hl,MsgDne xor a ; reset error flag ErExit: call epstr ; print message Exit: call puter2 ; set error code ld b,a ; put error code in B or a ; do we have one? call nz,inverror ; (yes, call error handler) ld sp,(OldStk) ; restore old stack pointer ret ; ..and return to CCP ; UAbort: cp CtrlC ; control-C? ret nz ; (nope, continue) ld a,4 ld hl,MsgAbt Abort: push af ; save error code call OutDU ld de,OutFcb call f$close ; close output file pop af ; restore error code jr ErExit ; InvDir: ld a,2 ; invalid directory ld hl,MsgDir jr ErExit ; ; Subroutines . . . ; ; OpnInp -- open input file ; OpnInp: ld de,InFcb call initfcb call InDU ; set drive/user for input call f$open ret z ; (all okay) ld a,10 ; set error flag ld hl,MsgFNF ; file not found jr ErExit ; ; OpnOut -- open output file ; OpnOut: ld hl,(TypCnt) inc hl ld (TypCnt),hl ld de,OutFcb+9 call mhl3dc ld a,(OpQFlg) ; quiet option? or a ld hl,MsgWrt ; ..and the file we're writing call z,epstr ld bc,(OutUsr) ; B=drive, C=user ld de,OutFcb+1 call z,PrtFn ; ld de,OutFcb call initfcb ; initialize FCB call OutDU call f$make ; create and open file inc a jr nz,OpnOu2 ; (okay) ld a,11 ; set error flag ld hl,MsgNSp ; no directory space jp ErExit ; OpnOu2: call PutIni ; initialize PutC ld a,(OpQFlg) ; quiet? or a ld hl,MsgDot call z,epstr ret ; ; RdLoop -- reads and writes until end of file ; RdLoop: ld a,(FmtFlg) ; check file format or a jr nz,RdObj ; (object format) RdLp1: call GetC ; get a character ret z ; (end of file) cp CpmEof ; end of file? ret z ; (yes) ; ld b,a ; save character in B ld a,(MthFlg) ; check method flag bit 2,a jr nz,RdLp5 ; split by marker location ; else, split by record or line count ld a,b ; recover character call PutC ; output character jr c,WrtErr ; (write error) and 7Fh ; reset high bit cp LF ; is it a line feed? jr nz,RdLp1 ; (no) ld hl,(FilLmt) ; are we at record or line limit? ex de,hl ld hl,(FilCnt) ld a,(MthFlg) ; if not record method bit 0,a jr nz,RdLp2 inc hl ; ..increment count first ld (FilCnt),hl ; ..and store it RdLp2: call comphd jr c,RdLp4 RdLp3: call WrLast call DatStp call PrtSiz call OpnOut call PutIni ld hl,0 ld (FilCnt),hl RdLp4: call condin ; user aborting? jr z,RdLp1 ; (nope) cp CtrlC jr nz,RdLp1 ld a,4 ; we're aborting ld hl,MsgAbt jp Abort ; RdLp5: ld a,(MkrChr) ; have we found a marker character? cp b jr z,RdLp3 ; (yep) ld a,b ; no, so recover character call PutC ; output it jr c,WrtErr ; (write error) cp LF jr z,RdLp4 ; (check for abort) jr RdLp1 ; WrtErr: ld a,11 ; set error flag ld hl,MsgWEr ; no disk space jp Abort ; ; RdObj -- Reads and writes binary file sectors, ignoring end-of-file ; characters. Assumes file has been successfully opened. ; RdObj: call InDU ld hl,(GetPtr) RdObj1: call condin call nz,UAbort ; check for abort request call RdSec ; read a sector jr nz,RdObj5 ; (end of file) ld a,(GetSec) ; get sector count inc a ; ..increment it ld (GetSec),a ; ..store it ld b,a ; ..and move it to B ; ld hl,(FilLmt) ; are we at record or line limit? ex de,hl ld hl,(FilCnt) inc hl ; increment count ld (FilCnt),hl ; ..and store it call comphd ; done with this file? jr nc,RdObj2 ; (yes) ld a,b ; recover sector count cp InSiz-1 ; end of buffer? jr z,RdObj3 ; (yes, we need to write it) ld hl,(GetPtr) ; get current sector pointer ld de,128 ; ..add 128 to it add hl,de ld (GetPtr),hl ; ..and store it jr RdObj1 ; RdObj2: call WrObj ; write rest of file jp nz,WrtErr call ClsOut call DatStp call PrtSiz call OpnOut ; ..and open a new one ld hl,0 ld (FilCnt),hl ; reset record/line counter jr RdObj4 ; RdObj3: call WrObj ; write buffer to disk jp nz,WrtErr RdObj4: ld hl,(InBuf) ; reset buffer pointer ld (GetPtr),hl xor a ; reset sector counter ld (GetSec),a jr RdObj ; RdObj5: call WrObj ; write rest of file jp nz,WrtErr ret ; ; WrObj -- write output buffer to disk ; WrObj: call OutDU ld a,(GetSec) ; get buffer sector count ld b,a ; put it in B ld hl,(InBuf) ; point to beginning of buffer WrObj1: xor a ; check sector count cp b ret z ; (we're through) push bc ; save sector count push hl ; save DMA address call WrtSec ; write the sector pop hl ; recover DMA address pop bc ; get back sector count ret nz ; (write error) dec b ; decrement sector count ld de,128 ; increment DMA address add hl,de jr WrObj1 ; ; ClsInp -- close input file ; ClsInp: call InDU ; close input file ld de,InFcb call f$close ret z ; (okay) ld a,4 ; set error flag ld hl,MsgCEr ; close error jp Abort ; ; GetDft -- gets default drive and user ; GetDft: call retud ; C=user, B=drive (A=0) ld a,b ; A=drive (A=0) inc a ; A=drive (A=1) ret ; ; PrtFn -- Prints drive/user and filename on console ; PrtFn: call stndout ld a,b ; get drive add a,'A' ; make it printable call cout ; ..and print it ld a,c ; get user call pafdc ; ..and print it ld a,':' call cout call pfn2 ; print filename call stndend ret ; ; PrtSiz -- prints size of file in records or lines ; PrtSiz: ld a,(OpQFlg) or a ret nz ; (quiet, print nothing) ld hl,(FilCnt) ; get record/line count ld a,(FmtFlg) ; object format? or a ld a,(MthFlg) jr nz,PrtSz1 ; (yes) bit 1,a ; line method? jr nz,PrtSz1 ; (yes) inc hl ; no, increment record count PrtSz1: call phldc ; print count bit 1,a ; ..and correct method label ld hl,MsgRe1 jr z,PrtSz2 ld hl,MsgLi1 PrtSz2: call epstr ret ; ; EatSpc -- gobbles up spaces and tabs ; EatSpc: ld a,(hl) or a ret z inc hl cp ' ' ; is it a space? jr z,EatSpc ; (yes) cp TAB ; is it a tab? jr z,EatSpc ; (yes) dec hl ret ; ; OutDU -- sets default drive and user for output file ; OutDU: push bc ld bc,(OutUsr) ; B=drive, C=user call logud pop bc ret ; ; InDU -- sets default drive and user for input file ; InDU: push bc ld bc,(InUsr) ; B=drive, C=user call logud pop bc ret ; ; GetC -- returns character from file. Assumes file has been ; successfully opened and GetIni has been called. Returns character ; or ^Z (end-of-file) in A. Zero set (Z) on end of file. ; Affected: AF ; GetC: push bc push de push hl ld a,(GetCnt) ; get counter cp 128 ; done with buffer? jr nc,GetC1 ; (yes, get next sector) GetChr: ld hl,(GetPtr) ; point to current DMA buffer ld e,a ; move counter to DE ld d,0 add hl,de ; ..and add it to HL inc a ; increment counter ld (GetCnt),a ld a,(hl) ; get next character cp CpmEof GetEof: pop hl pop de pop bc ret ; GetC1: call condin call nz,UAbort ; (check for abort) ld a,(GetMax) ld d,a ld a,(GetSec) ; get sector count cp d ; end of buffer? jr z,GetC2 ; (yes, we need to read more) inc a ; increment sector count ld (GetSec),a ; ..and store it ld hl,(GetPtr) ; get current sector pointer ld de,128 ; ..add 128 to it add hl,de ld (GetPtr),hl ; ..and store it xor a jr GetChr ; GetC2: ld a,(GetFlg) ; check end-of-file flag cp CpmEof jr z,GetEof ; (end of file) call InDU call ReadF ld hl,(InBuf) ld (GetPtr),hl xor a ld (GetSec),a jr GetChr ; ; GetIni -- must be called before first call to GetC. ; GetIni: ld hl,0 ; initialize flags ld (GetMax),hl ld (GetFlg),hl ; and GetSec ld a,128 ld (GetCnt),a ld hl,(InBuf) ; initialize pointer ld (GetPtr),hl ret ; ; ReadF -- read disk into input buffer ; ReadF: ld a,InSiz ld b,a dec a ld (GetMax),a ld hl,(InBuf) ReadF2: call RdSec jr nz,ReadF3 ld de,128 add hl,de djnz ReadF2 ret ; ReadF3: inc b ; we didn't read that last sector ld a,CpmEof ld (GetFlg),a ld a,InSiz ; store number of sectors read sub b ld (GetMax),a ret ; RdSec: call setdma ; set DMA address ld de,InFcb ; ..and read sector call f$read ret ; ; PutC -- Writes character to file. Assumes file has been successfully ; opened and PutIni has been called. Expects character in A. Returns ; carry set (C) on error (disk or directory full). ; Affected: Flags. ; PutC: push bc push de push hl ld c,a ; save character in C ld a,(PutCnt) ; get counter cp 128 ; buffer full? jr nc,PutC1 PutChr: ld hl,(PutPtr) ; point to current DMA buffer ld e,a ; move counter to DE ld d,0 add hl,de ; ..and add it to HL ld (hl),c ; write character inc a ; increment counter ld (PutCnt),a sub a ; clear carry PutEnd: ld a,c ; recover character pop hl pop de pop bc ret ; PutC1: ld a,(MthFlg) ; line method? bit 1,a jr nz,PutC1a ; (yes, don't touch FilCnt) ld hl,(FilCnt) ; increment record count inc hl ld (FilCnt),hl PutC1a: ld a,(PutSec) ; get sector count inc a ; increment it cp OutSiz ; end of buffer? jr z,PutC2 ; (yes, we need to write it) ld (PutSec),a ; store new sector count ld hl,(PutPtr) ; get current sector pointer ld de,128 ; ..add 128 to it add hl,de ld (PutPtr),hl ; ..and store it xor a ; make A = 0 jr PutChr ; PutC2: call OutDU call WrtF ; write buffer to disk jr nz,PutErr ; (disk full) ld hl,(OutBuf) ; reset buffer pointer ld (PutPtr),hl xor a ; reset sector counter ld (PutSec),a jr PutChr ; PutErr: scf ; set carry jr PutEnd ; ; PutIni -- must be called before first call to PutC. ; PutIni: ld hl,0 ; initialize counters ld (PutCnt),hl ; and PutSec ld hl,(OutBuf) ; initialize buffer pointer ld (PutPtr),hl ret ; ; WrtF -- write output buffer to disk ; WrtF: ld a,(PutSec) ; get buffer sector count ld b,a ; put it in B inc b ld hl,(OutBuf) ; point to beginning of buffer WrtF2: call WrtSec ; write the sector ret nz ; (write error) ld de,128 ; increment DMA address add hl,de djnz WrtF2 ret ; WrtSec: call setdma ; set DMA address ld de,OutFcb ; ..and write sector call f$write ret ; ; WrLast -- writes remaining buffer contents and closes output file. ; WrLast: ld a,(FmtFlg) ; object format? or a jr nz,ClsOut ; (yes, just close file) ld a,CpmEof ; put end-of-file character call PutC jp c,WrtErr ld hl,PutCnt ; point to current sector count ld a,128 sub (hl) jr z,WrLst1 ; (at end of sector) ld b,a ld a,CpmEof ; fill rest of sector with ^Z FillZ: call PutC jp c,WrtErr djnz FillZ WrLst1: ld de,(OutBuf) ; get beginning buffer address to DE ld hl,PutPtr ; HL -> buffer pointer ld a,e ; is pointer at zero? cp (hl) jr nz,WrLst2 ; (no) ld a,d inc hl cp (hl) jr nz,WrLst2 ; (no) ld a,(PutCnt) ; is counter at zero? or a jr nz,WrLst2 ; (no) jr ClsOut ; nothing to write, so close it ; WrLst2: call OutDU call WrtF ; write what's left jp nz,WrtErr ; (disk full, abort) ; ClsOut: call OutDU ; close output file ld de,OutFcb call f$close ret z ; (okay) ld a,4 ; set error flag ld hl,MsgCEr ; close error jp Abort ; ; MHL3DC -- Store HL as 3 decimal characters at DE (based on Carson Wilson's ; SMHL5DC module in ZSLIB 2.1). ; MHL3DC: push af ; save regs push bc push hl push ix push de ; for output pop ix ld b,0 ; B=0 for no leading spaces ld de,100 ; store 100's call MHDC1 MHDC6: ld de,10 ; store 10's call MHDC1 ld a,l ; store 1's add '0' ; convert to ASCII call MHDC8 pop ix ; restore regs pop hl pop bc pop af ret ; ; Divide HL by DE and store quotient with leading spaces ; MHDC1: xor a ; set count MHDC2: or a ; clear carry sbc hl,de jr c,MHDC3 ; done if carry set (further borrow) inc a ; increment count jr MHDC2 MHDC3: add hl,de and a ; check for zero jr nz,MHDC4 or b ; 0 = no leading spaces (A=0, A or B = 0 if B=0) jr z,MHDC4 ld a,' ' ; store space jr MHDC8 MHDC4: ld b,0 ; turn off leading spaces for rest of output MHDC7: add '0' ; convert to ASCII MHDC8: push ix ; get storage address pop de inc ix call MOUT ret ; ; MOUT - Store A to memory at DE (from Carson Wilson's ZSLIB 2.1) ; Entry: A = value to store ; DE = address of memory buffer (1 byte) ; Exit: DE = address of byte after output ; Uses: DE ; MOUT: ld (de),a inc de ret ; ; GetOpt -- checks command tail for user supplied options and sets ; appropriate option flags. Also sets FSFlag to number of filespecs ; found (which must have previously been initialized to zero). ; GetOpt: ld hl,CpmDma ; point to command tail ld a,(hl) ; anything there? or a ret z ; (no) inc hl call EatSpc or a ret z ; (end of tail) cp '/' jr z,IsSlsh ld a,(FSFlag) ; increment number of filespecs inc a ld (FSFlag),a FnLp1: inc hl ; move past first filename ld a,(hl) or a jr z,OptChk ; (end of tail) cp ' ' jr z,GetOp1 cp TAB jr nz,FnLp1 ; GetOp1: call EatSpc or a jr z,OptChk ; (end of tail) cp '/' ; is it a slash? jr z,IsSlsh ; (yes) ld a,(FSFlag) ; increment number of filespecs inc a ld (FSFlag),a FnLp2: inc hl ; move past second filename ld a,(hl) or a jr z,OptChk ; (end of tail) cp ' ' jr z,GetOp2 cp TAB jr nz,FnLp2 ; GetOp2: call EatSpc or a jr z,OptChk ; (end of tail) cp '/' ; a slash? jr nz,GotOpt ; (no, get options) IsSlsh: inc hl ; move past slash GotOpt: ld a,(hl) ; get option inc hl or a jr z,OptChk ; (end of tail) cp ' ' ; space? jr z,GotOpt ; (skip it) cp '/' ; usage request? jp z,Usage ; (yes) cp 'K' ; use kilobytes? jr z,OptK ; (yes) cp 'L' ; use lines? jr z,OptL ; (yes) cp 'M' ; use marker? jr z,OptM ; (yes) cp 'O' ; object file? jr z,OptO ; (yes) cp 'Q' ; quiet flag? jr z,OptQ ; (yes) cp 'R' ; use records? jr z,OptR ; (yes) cp 'T' ; text file? jr z,OptT ; (yes) call isdigit ; check for digit? jr z,OptI ; (yes) ld a,19 ; set invalid option error ld hl,MsgBdO jp ErExit ; OptChk: ld a,(OpKFlg) ; kilobytes? or a jr nz,OptCh1 ; (yes) ld a,(FmtFlg) ; object format? or a jr nz,OptCh3 ; (yes) ret ; OptCh1: ld hl,(FilLmt) ; multiply output file size by 8 ld de,8 call mulhd ld a,(FmtFlg) ; text format? or a jr nz,OptCh2 ; (no) dec hl ; yes, lower file size by 1 record OptCh2: ld (FilLmt),hl OptCh3: ld a,00000001b ; yes, so we size by record count ld (MthFlg),a ret ; ; Option setting routines ; OptQ: ld a,(OpQFlg) ; get Q flag cpl ; flip it ld (OpQFlg),a ; store it jr GotOpt ; OptK: ld a,0FFh ld (OpKFlg),a jr GotOpt ; OptL: ld a,00000010b jr SetMod ; OptM: ld a,00000100b jr SetMod ; OptR: ld a,00000001b ; SetMod: ld (MthFlg),a jr GotOpt ; OptO: xor a dec a jr SetFil ; OptT: xor a ; SetFil: ld (FmtFlg),a jp GotOpt ; OptI: dec hl ; point HL to number string call eval10 ; convert to binary ld a,d ; is it greater than 0? or a jr nz,OptI1 ; (yes) ld a,e ; it it greater than 0? or a jr z,OptI2 ; (no) OptI1: ld (FilLmt),de ; store it jp GotOpt ; OptI2: ld a,9 ; it's a bad number ld hl,MsgBdN jp ErExit ; Usage: ld hl,MsgUse ; version call epstr call prtname ; program name ld hl,MsgUs1 ; syntax and option n call epstr ld hl,(DftSiz) ; option n default call phlfdc ld hl,MsgUs2 ; option L call epstr ld a,(DftMth) bit 1,a ; is L the default? call nz,PrtDft ld hl,MsgUs3 ; option R call epstr bit 0,a ; is R the default? call nz,PrtDft ld hl,MsgUs4 ; option M call epstr ld b,a ; save flag ld a,(MkrChr) ; get marker character cp ' ' ; control character? jr nc,Usage1 ; (no) ld c,a ; save marker ld a,'^' call cout ; if control, print caret ld a,c ; get back tag character add a,'@' ; make it printable Usage1: call cout ld a,')' call cout bit 2,b ; is M the default? call nz,PrtDft ld hl,MsgUs6 ; option O call epstr ld a,(DftFmt) or a ; is O the default? call nz,PrtDft ld hl,MsgUs7 ; option T call epstr call z,PrtDft ; is T the default? ld hl,MsgUs8 ; option Q call epstr ld a,(OpQFlg) ; default to quiet mode? or a ld hl,MsgUof jp nz,Usage3 ; (yes) Usage2: ld hl,MsgUon Usage3: call epstr xor a ; reset error flag ld hl,MsgUs9 jp ErExit ; PrtDft: ld hl,MsgDft jp epstr ; ; DatStp -- Get create stamp from original file, if available, and ; transfer it to new file. ; DatStp: call InDU ; setup for input file ld de,InFcb ld hl,CpmDma ; point to DMA buffer call getstp ; get ZSDOS file stamp ret nz ; (error) ld a,(CpmDma+1) ; check for create date or a jr nz,DatSt1 ; (we've got a create date) ld a,(CpmDma+11) ; none, so check for modify date or a ret z ; (no date stamp) ld hl,CpmDma+10 ; point to modify date jr DatSt2 DatSt1: ld hl,CpmDma ; point to create date DatSt2: ld de,StpTmp ; move date to storage ld bc,5 ldir call OutDU ; setup for output file ld de,OutFcb ld hl,CpmDma ; point to DMA buffer call getstp ; get file stamp ret nz ; (error) ld hl,StpTmp ld de,CpmDma ; move old create stamp to date string ld bc,5 ldir ld de,OutFcb ; setup for file stamping ld hl,CpmDma call setstp ; set file stamp ret ; ; ChkAmb -- checks for ambiguous filename. Expects address of filename ; in HL. ; ChkAmb: ld bc,11 ld a,'?' cpir ret nz ; (no question marks) ld a,8 ; ambiguous filename ld hl,MsgAmb jp ErExit ; ; PSTR -- forces ZSYSCHK to use EPSTR ; pstr: jp epstr ; DSEG ; ; Uninitialized storage . . . ; InFcb: ds 36 ; input file fcb OutFcb: ds 36 ; output file fcb StpTmp: ds 5 ; temporary create date storage TypCnt: ds 2 ; count of files for file type FilCnt: ds 2 ; current record or line count FilLmt: ds 2 ; output file size in lines or records FmtFlg: ds 1 ; 0=text file, FFh=binary file MthFlg: ds 1 ; b0=records, b1=lines, b2=markers OpQFlg: ds 1 ; FFh=quiet mode OpKFlg: ds 1 ; FFh=file size in kilobytes FSFlag: ds 1 ; number of filespecs (set by GetOpt) GetMax: ds 1 ; number of sectors read into input buffer GetFlg: ds 1 ; GetC end-of-file flag GetSec: ds 1 ; GetC sector counter GetCnt: ds 1 ; GetC counter GetPtr: ds 2 ; GetC pointer PutCnt: ds 1 ; PutC counter PutSec: ds 1 ; PutC sector counter PutPtr: ds 2 ; PutC pointer InUsr: ds 1 ; input file user InDrv: ds 1 ; input file drive OutUsr: ds 1 ; output file user OutDrv: ds 1 ; output file drive OldStk: ds 2 ; old stack pointer InBuf: ds 2 ; input buffer address OutBuf: ds 2 ; output buffer address ; end