; XFOR.Z80 ; ; Z-System Extended FOR utility for searching and displaying "----" ; delimited file catalogs. ; Vers equ 15 SubVers equ ' ' ; modification level ; ; Version 1.5 -- December 1, 1991 -- Gene Pizzetta ; One small operational change: Now prints "[searching]" only if a ; search string is given. Other minor changes: uses ZSLIB GCOMNAM ; instead of Z3LIB PRTNAME to more reliably obtain program's name, ; and uses ZSLIB EATSPC and EATNSPC to save a few bytes. ; ; Version 1.4 -- November 10, 1991 -- Gene Pizzetta ; Finally implemented a couple of suggestions made months ago. Bob ; Dean wanted a "searching" message so the user would know something ; was happening while XFOR was looking for a match, so it's here. ; Bill Tishey wanted to be able to search crunched files, so that's ; here also. Unfortunately, neither KMD nor ZMD can handle crunched ; files, but this XFOR feature could be useful for extended FOR file ; listings and for Bill Tishey's ZFILES.LST. About 38 kilobytes of ; TPA is required for uncrunching. "Nolan" FOR file header now ; built-in as alternate header. ; ; Version 1.3 -- April 7, 1991 -- Gene Pizzetta ; A problem with previous versions was the mixing of console input ; and output via BDOS and BIOS. That problem has been solved by ; Adding a TABIT routine to expand tabs in the FOR file and eliminate ; the use of the SYSLIB BOUT routine. All console I/O is now via the ; BIOS. ; ; Version 1.2 -- December 23, 1990 -- Gene Pizzetta ; Changed command line syntax at the request of Jay Sage: Now ; an option list, preceded by a slash, can be included in the ; command line, just before the match string. Options are: ; H=display header; A=use alternate header; S=double-space between ; entries; L=echo to printer (LST); V=turn off all screen attributes; ; P=use screen paging; and N=no screen paging. The last two will ; suppress the paging "ASK" configuration option. The L option will ; suppress screen paging. ; ; Version 1.1 -- December 18, 1990 -- Gene Pizzetta ; Added CR, LF after paging question. At the suggestion of Al ; Hawley, now uses BOUT instead of COUT in print loop, so tabs are ; expanded. Added printer output and "+" command line option ; (must be last token, preceded by a space). Made video attributes ; used for header and first line of entry configurable options. ; ; Version 1.0 -- December 15, 1990 -- Gene Pizzetta ; Variable screen overlap and clearing screen before each page are ; now configurable options. Changed method of making leading ; spaces significant; now requires "|" at beginning of match string ; if leading spaces are to be significant. Uses direct cursor ; addressing and clear-to-end-of-screen string, if available and if ; header is being displayed. Fixed bug found by Bill Tishey that ; in some cases caused highlighting not to be properly terminated ; on his Apple II+ (STNDEND must be called before sending a line ; feed on that machine). Fixed bug reported by Bob Dean that sent ; the program into never-never-land if the Kaypro 4/10 TCAP from ; Z3TCAP27 was used. (This was actually a bug in the SETATR ; routine in VLIB versions 42 and 43, but I have compensated for ; it.) Source filename parameter omitted from syntax message for ; non-wheels, unless configured to always be omitted. ; ; Version 0.2 -- December 8, 1990 -- Gene Pizzetta ; A second beta release. Name changed to XFOR to avoid conflict ; with ZMD utilities, as suggested by Jay Sage and Chris McEwen. ; Can be configured to page or not page output, or to ask the user ; which he wants. No longer responds to quiet flag, but quiet ; configuration still works. Highlights first line of each entry ; if available from TCAP, as suggested by Chris McEwen. Uses ; reverse video for header line, if available. Sets correct Z34 ; error codes in program error flag, except no string match is ; FFh. Configurable to allow blank line between entries or not ; if you want more entries on screen, per suggestion by Bob Dean ; and Bill Tishey. Satisfies Bob's suggestion for an additional ; header type by providing for an additional roll-your-own header. ; Leading spaces now significant in search string. Adopted Jay ; Sage's suggested command line syntax: if there's a colon in the ; first token, it's a filename; otherwise, use the internal ; filename. In addition, XFOR will use the internal filename if ; the colon is not followed by one, and will use the internal DU ; if the colon is not preceded by one. Now properly handles ; entries more than a screen-length. Entry buffer now handles ; single entries of up to 8K. ; ; Version 0.1 -- December 2, 1990 -- Gene Pizzetta ; A beta release, based on Carson Wilson's FORZ 1.0 (8/5/87), ; which was a revised disassembly of Irv Hoff's FOR.COM. Sets the ; ZCPR program error flag if a matching string is not found. The ; "end of listing" and "aborted" messages suppressed if ZCPR quiet ; flag is set or if configured to default to quiet mode. Responds ; to "//" help option on command line. Re-initializes its data ; buffers so it can be re-invoked with GO command. Added command ; line source file specification. If no DU or DIR spec is given, ; an internally configured default directory is used or, if not ; configured, the current logged directory. If no command tail is ; given, defaults to configured internal filename. If reading an ; improperly formatted file, FORZ kept adding to the OutBuf until ; it overwrote the system. ZFOR instead aborts with an error ; message. Configurable with ZCNFG. ; ; Report bugs or suggestions to: ; ; Gene Pizzetta ; 481 Revere St. ; Revere, MA 02151 ; ; Voice: (617) 284-0891 ; Newton Centre Z-Node: (617) 965-7259 ; Ladera Z-Node Central: (213) 670-9465 ; ; System addresses ; CpmFcb equ 5Ch ; default file control block CpmDma equ 80h ; default DMA buffer LstSt equ 15 ; Bios list status ; ; BDOS Functions ; FOpen equ 15 ; open file FClose equ 16 ; close file FRead equ 20 ; read sequential SetDma equ 26 ; set DMA address ; ; ASCII characters ; CtrlC equ 03h ; ^C CtrlD equ 04h ; ^D BEL equ 07h ; bell BS equ 08h ; backspace TAB equ 09h ; horizontal tab CtrlS equ 13h ; ^S LF equ 0Ah ; line feed CtrlK equ 0Bh ; ^K FF equ 0Ch ; form feed CR equ 0Dh ; carriage return CtrlX equ 18h ; ^X CpmEof equ 1Ah ; end-of-file flag ; .request zslib,vlib,z3lib,syslib,unc ; ext eatspc,eatnspc,gcomnam,comnam ; ZSLIB ext gz3init,tinit,cls,at,clreos,stndout,stndend ; VLIB ext setatr,dinit ext z3log,puter2,getwhl ; Z3LIB ext bdos,bios,cin,cout,lout,condin ; SYSLIB ext uncrel,endu ; UNC ; public getbyt,uncout ; for UNC ; Entry: jp Start db 'Z3ENV' db 1 Z3EAdr: dw 0 ; environment address ; ; Configuration . . . ; dw 0 ; filler db 'XFOR' ; for ZCNFG db Vers/10+'0',Vers mod 10+'0',' ' HdrFlg: db 0 ; FFh=print header HdrTag: db 0 ; 0=use ZFILES header, FFh=special header HdrAtr: db 2 ; video attributes for header EntAtr: db 8 ; video attributes for entry QtFlag: db 0 ; FFh=default to quiet mode SCFlag: db 1 ; 1=paging, 2=no paging, 4=ask SpcFlg: db 0 ; FFh=space between entries ClsFlg: db 0FFh ; FFh=clear screen OlpFlg: db 0FFh ; FFh=variable page overlap SynFlg: db 0FFh ; 0=no fn.ft in syntax message, FFh=use wheel DftDrv: db 0 ; default drive (A=1..P=16, current=0) DftUsr: db 0 ; default user (0-31) DftFn: db ' ' ; default filename PrgNam: db 'FOR ' ; program name for usage screen SplHdr: db ' filename catagory ' db ' where size uploaded ',0 ZFHdr: db ' filename vers sys/sus kb rec crc library/size ' db 'issued author ',0 ; VerMsg: db '[later version needed]',0 NCrMsg: db '[not crunched]',0 CrpMsg: db '[corrupt file]',0 MemMsg: db '[insufficient memory]',0 ; ; Start of program . . . ; Start: ld hl,(Z3EAdr) ; set up environment call gz3init ld (ExtFlg),a ; store flags ld (Stack),sp ; save old stack pointer ld sp,Stack ; ..and set up new stack ld hl,endu ld (OutBuf),hl ; main output buffer ld a,h ; set buffer limit (high byte only) add 32 ; 8K entry buffer ld (BufLim),a inc a ; set input buffer for crunched files ld h,a ld l,0 ; on page boundary ld (InBuf),hl inc h ; set buffer for UNC.REL ld (CrBuf),hl ld hl,(HdrFlg) ; set header display default ld (UseHdr),hl ld hl,(SCFlag) ; set paging and spacing default ld (PagFlg),hl ld hl,(HdrAtr) ; set video attributes ld (HdrVid),hl xor a ld (ErCode),a ; zero error code, ld (LinCnt),a ; ..line count, ld (CrnFlg),a ; ..crunched flag ld (FSFlag),a ; ..and filespec flag call tinit ; initialize terminal ld a,(SynFlg) ; syntax flag set? or a jr z,SetUse ; (no, set usage flag) call getwhl ; no, set according to wheel SetUse: ld (UseFlg),a ; set usage flag ; ld hl,DftNam ; get disk name, if available call gcomnam ld a,(CpmFcb+1) cp '/' jr nz,Start1 ld a,(CpmFcb+2) cp '/' jp z,Usage ; Start1: ld hl,InFcb ; initialize FCB ld b,36 ; length to fill xor a ; zero out IniFcb: ld (hl),a inc hl djnz IniFcb ; ld hl,CpmDma ; is there a tail? ld a,(hl) or a jr z,UseInt ; (no) inc hl call eatspc ; anything in tail? jr z,UseInt ; (no) cp ':' ; first character a colon? jr nz,Start2 ; (no) ld a,(CpmFcb+1) ; yes, is a filename given? cp ' ' jr z,UseIn1 ; (no) jr Start3 ; ; No initial colon, so we check for a DU spec. If we have a DU spec but ; no filename, we use the internal filename. If we have both, we move on. ; Start2: ld hl,CpmFcb ; was a DU or DIR given? ld a,(hl) or a jr z,UseInt ; (no) inc hl ; yes, so check for a filename ld a,(hl) cp ' ' jr z,UseIn2 ; (none, so use internal name) jr MovFn ; we have DU:filename, so move it ; ; We have an initial colon and a filename, so we use internal DU and ; given filename. ; Start3: call MovDU ; get internal DU ld hl,CpmFcb+1 jr MovFn ; ..and move filename ; ; We have no filespec. ; UseInt: ld a,0FFh ; set flag for GetStr ld (FSFlag),a ; ; We have a colon, but nothing else. ; UseIn1: call MovDU ; get internal DU ; ; We have a DU, but no filename. ; UseIn2: ld hl,DftFn ; no, use default filename ld a,(hl) cp ' ' ; is one there? jp z,NoInt ; (no) MovFn: ld de,InFcb+1 ; move filename to FCB ld bc,11 ldir ; LogDU: ld a,(CpmFcb+15) ; valid directory specification? inc a jp z,InvDir ; (no, invalid) ld a,(CpmFcb+10) ; check filetype cp 'Z' jr nz,LogDU1 ; (not crunched) ld (CrnFlg),a LogDU1: ld de,CpmFcb ; point to filespec call z3log ; log into file directory ; ld de,InFcb ; open file ld c,FOpen call bdos inc a jp z,NoFile ; file not found ; ld hl,(Z3EAdr) ; point to environment ld de,32h ; offset to CRT lines add hl,de ld a,(hl) ; get CRT lines dec a ; make it one less ld (CrtLin),a xor a ; initialize data ld (LinCnt),a ld (StrLen),a ld (LstFlg),a dec a ld (EntFlg),a ; first entry is FFh ; call GetStr ; get match string, if any ; ld a,(PagFlg) ; do we ask about paging? cp 1 jr z,PagOn cp 2 jr z,PagOff cp 4 jr nz,NoAsk ; (no) call ILPrt ; we'll have to ask db 'Do you want screen paging? Y',BS,0 call cin and 5Fh cp 'N' ; no paging? call z,cout ; (yes, print N) ld a,CR ; down a line call cout ld a,LF call cout PagOff: ld a,0FFh jr z,PgStat ; (yes, turn paging off) PagOn: xor a ; no, page output PgStat: ld (PagFlg),a ; NoAsk: call SetErr ; set error code for no match as default ld a,(ClsFlg) ; clear screen? or a call nz,cls ; (yes, clear screen) call PrtHdr ; print header if required call PrSrch ld de,(OutBuf) ld a,(CrnFlg) or a jr z,Read ; (not crunched) exx ; save buffer addresses ld hl,CpmDma ; initialize pointer ld (DmaPtr),hl ld hl,127 ; set buffer pointer ld (InPtr),hl ; ..to force a read ld hl,(CrBuf) ; point to UNC buffer call uncrel ; and dump it exx jr c,UncErr call TstChr ; do any last partial sector jp Close UncErr: cp 1 jr nz,UncEr2 ld hl,VerMsg jr UnkErr ; UncEr2: cp 2 jr nz,UncEr3 ld hl,NCrMsg jr UnkErr ; UncEr3: cp 3 jr nz,UncEr4 ld hl,CrpMsg UnkErr: ld a,4 ; error code jr PrErr ; UncEr4: ld a,12 ; error code ld hl,MemMsg PrErr: push af ; save error code call PrtStr pop af jp ErExit ; ; Main loop -- read file and test characters ; Read: ld a,(CrnFlg) ; check crunched flag or a ret nz ; (it's crunched) push de ; save OutBuf address ld de,CpmDma ld c,SetDma ; set DMA to 80h call bdos ld de,InFcb ld c,FRead ; read file call bdos pop de ; recover OutBuf address or a jp nz,RdErr ; read error or end-of-file ld hl,CpmDma ; TstChr: ld a,(LinBeg) ; start of new line? or a jr z,NotEnd ; (no, keep reading) xor a ; yes, reset flag ld (LinBeg),a ld a,(hl) ; get next character from file and 7fh ; mask high bit cp '-' ; is it a dash? jr nz,NotEnd ; (no, not end of entry) PutEnd: ld a,CtrlC ; insert ^C as end of entry ld (de),a dec de ld a,(de) cp LF jr z,PutEnd cp CR jr z,PutEnd cp ' ' jr z,PutEnd jp Match ; ..and see if there's a match ; NotEnd: ld a,(hl) ; get next character and 7fh ; mask high bit cp 7fh ; delete mark? (*** what for? ***) jr z,RdChk ; (yes, check for end of buffer) cp CpmEof ; end of file? jp z,GotEof ; (yes) ; MovChr: ld (de),a ; move character to OutBuf inc de ld b,a ; save character in B ld a,(BufLim) cp d jr z,BufOvf ; (buffer overflow) ld a,b ; recover character CkLine: cp LF ; end of line? jr nz,RdChk ; (no) ld a,(StrLen) ; ..and set flag ld (LinBeg),a call CkCon ; check for abort RdChk: inc l ; end of input buffer? jr z,Read ; (yes, read more file) jr TstChr ; no, test next character ; ; CkCon -- check console for pause or abort. ; CkCon: call condin ; check keyboard ret z ; (no input) cp CtrlS ; ^S? call z,cin ; (yes, wait for character) CkCon1: and 5Fh cp CtrlC ; ^C? jr z,Abort cp CtrlK ; ^K? jr z,Abort cp CtrlX ; ^X? jr z,Abort cp 'C' ; C? jr z,Abort cp 'K' ; K? jr z,Abort cp 'X' ; X? ret nz ; Abort: ld a,(QtFlag) or a jp nz,Exit ld a,(EntVid) or a call nz,stndout call ILPrt db '[aborted] ',0 ld a,(EntVid) or a call nz,stndend jr Exit ; ; BufOvf -- buffer is filled without reaching the end of an entry. ; BufOvf: ld a,(EntVid) or a call nz,stndout call ILPrt db BEL,'[incorrect format]',0 ld a,(EntVid) or a call nz,stndend ld a,12 ; set error code jr ErExit ; ; NoFile -- source file was not found. ; NoFile: call ILPrt db BEL,'[file not found]',0 ld a,10 ; set error code jr ErExit ; ; InvDir -- an invalid DU spec was given. ; InvDir: call ILPrt db BEL,'[invalid directory]',0 ld a,2 ; set error code jr ErExit ; ; NoInt -- no internal filename configured. ; NoInt: call ILPrt db BEL,'[no filename]',0 ld a,8 ; set error code jr ErExit ; ; Exit -- reset stack and return ; Exit: ld a,(ErCode) ; set error flag ErExit: call puter2 call dinit ld sp,(Stack) ; point to old stack ret ; ; Usage -- message varies depending on UseFlg. Syntax includes source ; file name (fn.ft) if non-zero; otherwise, omitted. ; Usage: call ILPrt DftNam: db 'XFOR Version ',Vers/10+'0','.',Vers mod 10+'0',SubVers,CR,LF db 'Usage:',CR,LF,' ',0 call PName ld a,(UseFlg) or a jr z,Usage1 call ILPrt db ' {{dir}:{fn.ft}}',0 Usage1: call getwhl jr z,Usage2 call ILPrt db ' {/options}',0 Usage2: call ILPrt db ' {string{|string{|...}}}',CR,LF,0 call ILPrt db 'If no string is given, all entries are displayed.',CR,LF db ' "|" separates multiple search strings',CR,LF db ' "?" matches any character',CR,LF db ' "\" matches only the beginning of the filename line',0 call getwhl jp z,Usage6 call ILPrt db CR,LF db 'Options:',CR,LF db ' H ',0 ld a,(HdrFlg) or a jr z,Usage4 call ILPrt db 'No ',0 Usage4: call ILPrt db 'Header display',CR,LF db ' A Use alternate header',CR,LF db ' S ',0 ld a,(SpcFlg) or a jr z,Usage5 call ILPrt db 'No ',0 Usage5: call ILPrt db 'Space between entries',CR,LF db ' P Screen page pause',CR,LF db ' N No screen page pause',CR,LF db ' L Echo to printer',CR,LF db ' V No video highlighting',0 Usage6: ld a,(UseFlg) ; syntax flag set? or a jp nz,Exit ; (yes, omit examples) call ILPrt db CR,LF db 'Examples:',CR,LF,' ',0 call PName call ILPrt db ' MOD ' db '; display entries containing "MOD"',CR,LF,' ',0 call PName call ILPrt db ' MOD|BYE ' db '; display entries with "MOD" or "BYE"',CR,LF,' ',0 call PName call ILPrt db ' \M7 ' db '; display filename beginning with "M7"',CR,LF,' ',0 call PName call ILPrt db ' | MOD ' db '; display only when "MOD" is preceded by space',CR,LF,' ',0 call PName call ILPrt db ' .A?M ; wild card string',0 jp Exit ; ; ILPrt -- prints null-terminated in-line string. Expects address of ; string on stack. ; ILPrt: ex (sp),hl ; print inline chars up to 0 call PrtStr ex (sp),hl ret ; ; PrtStr -- prints null-terminated string. Expects address of string ; in HL. Returns HL pointing to null. Each line feed increments line ; count. ; PrtStr: ld a,(hl) or a ; end of string? ret z ; (yes) call cout ; send character cp LF ; was it a line feed? call z,IsLine ; (yes, end of line) inc hl ; increment string pointer jr PrtStr ; ; Match -- find match in current entry to match-string or strings. ; Match: push hl ; save input buffer pointer ld hl,StrBuf ; point to string to match Match1: ld (StrPtr),hl ; save it ld hl,(OutBuf) ; point to start of OutBuf Match2: ex de,hl ; DE = start of OutBuf ld hl,(StrPtr) ; HL = start of StrBuf ex de,hl ; DE = StrBuf push hl ; HL = OutBuf ld a,(de) ; check first character cp '|' ; string delimiter? jr nz,Match3 ; (no) inc de ; yes, skip it Match3: ld a,(de) ; get first character of StrBuf cp '\' ; is it a slash? jr nz,Match4 ; (no) ld a,LF ; yes, look only at start of filename line Match4: inc de ; point to next StrBuf character or a ; end of string (and buffer)? jr z,PrtEnt ; (yes) cp '|' ; end of string? jr z,PrtEnt ; (yes, start of next string (| = or)) ld b,a ; save match character in B ld a,(hl) ; get file character cp 'a' ; lower-case? jr c,Match5 ; (no) cp '{' jr nc,Match5 ; (no) and 5Fh ; yes, make it upper-case Match5: ld c,a inc hl ld a,b cp '?' jr z,Match3 cp c jr z,Match3 pop hl inc hl ld b,0 ld a,(hl) cp CtrlC ; end of entry? jr z,Match6 ; (yes) cp CtrlD ; end of file? jr nz,Match2 ; (no, continue) inc b Match6: ld hl,(StrPtr) Match7: ld a,(hl) inc hl cp '|' jr z,Match1 or a jr nz,Match7 ld a,b or a jp nz,Close ld de,(OutBuf) pop hl jp RdChk ; ; PrtEnt -- print entry in OutBuf (beginning at PrtBuf) ; PrtEnt: pop hl ; adjust stack ld hl,(OutBuf) ; HL = start of OutBuf dec hl call AttOn ld a,CR ; so TabIt knows we're in column 1 call TabIt SkpLp: inc hl ; skip past leading dashes, CR, and LF ld a,(hl) and 7Fh cp '-' jr z,SkpLp cp CR jr z,SkpLp cp LF jr z,SkpLp ld (PrtBuf),hl PrtLp: ld a,(hl) ; print until terminator cp CtrlC ; end of entry? jr z,PrtEnd ; (yes) cp CtrlD ; end of file? jr z,PrtEof ; (yes) cp LF ; line feed? push af ; save character and flags call z,AttOff pop af ; recover character and flags call TabIt ; ..print character, expanding tabs call LPrt ; (check for printer output) inc hl ; increment pointer call z,MLine ; (line feed, so count line) jr PrtLp ; PrtEof: call ResErr ; zero error code (match printed) jr Close ; PrtEnd: call AttOff ld a,CR call cout call LPrt ld a,LF call cout call LPrt xor a ; reset entry-in-progress flag ld (EntFlg),a call MLine ; count line ld a,(UseSpc) ; double-space? or a ld a,LF call nz,cout ; (yes, send extra line feed) call LPrt call nz,MLine ; (..and count line) PrtEn2: call ResErr ; zero error code (match printed) call PrSrch ; [searching] pop hl ; recover input buffer pointer ld de,(OutBuf) ; point to print buffer jp RdChk ; RdErr: cp 1 ; end of file? jr z,GotEof ; (yes) call ILPrt db BEL,CR,LF,'[read error]',0 GotEof: ld a,CtrlD ; mark end of file ld (de),a jp Match ; Close: ld de,InFcb ld c,FClose ; close file call bdos ld a,(QtFlag) or a jp nz,Exit ld a,(EntVid) or a call nz,stndout call ILPrt db '[end of listing]',0 ld a,(EntVid) or a call nz,stndend jp Exit ; ; MLine -- paging for string search mode ; MLine: call IsLine ; end of screen? ret nz ; (no) ld a,(UseHdr) ; are we printing a header or a jr z,MLine1 ; (no) ld a,(ClsFlg) ; clear screen? or a jr z,MLine2 ; (no) call at ; set cursor to column 1, row 2 db 2,1 call clreos ; clear to end of screen jr z,MLine1 ld a,(LinCnt) inc a ld (LinCnt),a jr MLine3 ; MLine1: ld a,(ClsFlg) or a call nz,cls ; (yes, clear screen) MLine2: call PrtHdr ; print header, if required MLine3: ld a,(OlpFlg) ; variable overlap? or a ret z ; (no) ld a,(LstFlg) ; are we listing on printer? or a ret nz ld a,(EntFlg) ; first entry on page? or a ret nz ; (yes) ld a,0FFh ld (EntFlg),a ld hl,(PrtBuf) ; point back to beginning of entry call AttOn ret ; ; IsLine -- screen paging ; IsLine: ld a,(PagFlg) or a ret nz ld a,(LinCnt) ; increment line count inc a ld (LinCnt),a ld b,a ; put it in B ld a,(CrtLin) ; get maximum console lines cp b ; end of screen? ret nz ; (no) ld a,(EntVid) or a call nz,stndout call ILPrt db '[more]',0 ld a,(EntVid) or a call nz,stndend call cin ; wait for response push af call ILPrt db CR,' ',CR,0 pop af call CkCon1 ; check for abort xor a ld (LinCnt),a ret ; ; Reset ZCPR error flag (clear it) ; ResErr: ld a,0 ; set error code to 0 (no error) jr SetEr2 ; ; Set ZCPR program error flag ; SetErr: ld a,0FFh ; set error code to FFh (no match) SetEr2: ld (ErCode),a ; ..and store it ret ; ; GetStr -- skips filename and gets address and length of string. ; GetStr: ld hl,CpmDma ; point to command tail ld a,(hl) ; anything there? or a jp z,GetSt2 ; (no) inc hl ; point to first character ld a,(FSFlag) ; is there a filespec? or a jr nz,GetOpt ; (no, so it's options or the match string) call eatspc ; yes, skip leading spaces and tabs jp z,GetSt2 ; (end of command line) call eatnspc ; move past filename jp z,GetSt2 ; (end of command line) ; GetOpt: call eatspc ; skip spaces jr z,GetSt2 ; (end of command line) cp '/' ; options? jr nz,GetSt1 ; (no, must be match string) GetOp1: inc hl ; it's options, increment pointer ld a,(hl) ; get option character or a jr z,GetOp2 ; (end of command line) cp ' ' jr z,GetOp2 ; (end of options) cp 'A' ; toggle header selection? jr z,OptA ; (yes) cp 'H' ; toggle header display? jr z,OptH ; (yes) cp 'L' ; printer output? jr z,OptL ; (yes) cp 'N' ; no paging? jp z,OptN ; (yes) cp 'P' ; paging? jp z,OptP ; (yes) cp 'S' ; toggle inter-entry spacing? jp z,OptS ; (yes) cp 'V' ; cancel attributes? jp z,OptV ; (yes) ; call ILPrt ; invalid option db BEL,'[invalid option]',0 ld a,19 ; set error code jp ErExit ; GetOp2: ld a,(LstFlg) ; printer output? or a jr z,GetSt1 ; (no) ld a,0FFh ; yes, turn screen paging off ld (PagFlg),a ; GetSt1: call eatspc ; skip spaces jr z,GetSt2 ; (end of command line) push hl ; save pointer ld de,CpmDma+1 sbc hl,de ; number of chars skipped in L ld a,(CpmDma) ; tail length in A sub l ; length of string in A inc a ld (StrLen),a ; store it pop hl ; recover pointer ld de,StrBuf ; copy string into buffer ld b,0 ld c,a ldir ret ; GetSt2: ld a,'?' ; no match string, so find everything ld (StrBuf),a xor a ld (StrBuf+1),a inc a ld (StrLen),a ret ; ; Option setting routines ; OptA: ld a,(UseAlt) ; flip UseAlt flag cpl ld (UseAlt),a jp GetOp1 ; OptH: ld a,(UseHdr) ; flip UseHdr flag cpl ld (UseHdr),a jp GetOp1 ; OptL: call getwhl ; wheel on? jp z,GetOp1 ; (no, no printer output) ld a,0FFh ld (LstFlg),a ; set printer flag ld (PagFlg),a ; turn off screen paging ld a,LstSt ; check LST status push hl ; save pointer call bios pop hl ; restore pointer jp nz,GetOp1 ; (printer is working) call ILPrt db BEL,'[printer off line]',0 ld a,4 ; set error code jp ErExit ; OptN: ld a,0FFh ; no paging jr SetPag ; OptP: xor a ; page output SetPag: ld (PagFlg),a jp GetOp1 ; OptS: ld a,(UseSpc) ; flip UseSpc flag cpl ld (UseSpc),a jp GetOp1 ; OptV: xor a ; zero attribute flags ld (HdrVid),a ld (EntVid),a jp GetOp1 ; ; MovDU -- move internal DU to CpmFcb ; MovDU: ld a,(DftDrv) ; move configured drive ld (CpmFcb),a or a ; is it current drive? ret z ; (yes, don't move user) ld a,(DftUsr) ld (CpmFcb+13),a ret ; ; PName -- print program name ; PName: ld a,(UseFlg) or a ld hl,comnam ; use disk name jr nz,PName1 ld hl,PrgNam ; use configured name PName1: ld b,8 PNamLp: ld a,(hl) or a ret z ; (end on a null..) cp ' ' ret z ; (..or a space) call cout inc hl djnz PNamLp ret ; ; PrtHdr -- prints header for ZFILES.LST display or SPECIAL header ; PrtHdr: ld a,(UseHdr) ; do we print a header? or a ret z ; (no) ld a,(HdrVid) ; check attribute byte cp 8 ; standout? jr z,PrtHd1 ; (yes) or a ; no attributes? jr z,PrtHdA ; (yes) ld a,(ExtFlg) ; extended TCAP? or a jr z,PrtHd1 ; (no) ld a,(HdrVid) ; get header attributes call setatr ; use reverse video if available PrtHd1: call z,stndout ; (not available, use standout) PrtHdA: push hl ; save pointer ld hl,ZFHdr ld a,(UseAlt) ; which header? or a jr z,PrtHd2 ld hl,SplHdr PrtHd2: call PrtStr ld a,(HdrVid) ; get header attributes cp 8 ; standout? jr z,PrtHd3 ; (yes) or a ; no attribute? jr z,PrtHdB ; (yes) ld a,(ExtFlg) ; extended TCAP? or a jr z,PrtHd3 ; (no) xor a call setatr ; turn off screen attributes PrtHd3: call z,stndend jr nz,PrtHd4 PrtHdB: call ILPrt ; no highlighting, so bracket header db ']',CR,'[',0 PrtHd4: call ILPrt db CR,LF,0 pop hl ; recover pointer ret ; ; LPrt -- send character in A to printer (LST) if LstFlg is set. Uses B. ; LPrt: push af ; save character and flags ld b,a ; ..and save it in B ld a,(LstFlg) ; do we print it? or a jr z,LPrtE ; (no) ld a,b ; recover character call lout LPrtE: pop af ret ; ; AttOn -- turns on attributes for first line of entry. ; AttOn: ld a,(EntVid) ; check attribute byte or a ; any attributes? ret z ; (no) cp 8 ; standout? jr z,AttOn1 ; (yes) ld a,(ExtFlg) ; extended TCAP? or a jr z,AttOn1 ; (no) ld a,(EntVid) ; get header attributes call setatr ; use reverse video if available AttOn1: call z,stndout ; (not available, use standout) ret ; ; AttOff -- turns off attributes for first line of entry. ; AttOff: ld a,(EntVid) ; get header attributes or a ; any attributes? ret z ; (no) cp 8 ; standout? jr z,AttOf1 ; (yes) ld a,(ExtFlg) ; extended TCAP? or a jr z,AttOf1 ; (no) xor a call setatr ; turn off screen attributes AttOf1: call z,stndend ret ; ; TabIt -- Prints character in A on console, expanding tabs. Preserves ; all registers. ; TabIt: push hl push bc push af ld hl,ScrCol ; point to current column count and 7Fh ; mask high bit cp ' ' jr nc,NotCtl ; count all printables cp CR jr nz,NotCR ld (hl),0 ; CR, so reset column count jp OutChr ; print carriage return ; NotCR: cp TAB jr nz,NotTab ; adjust col count assuming tabs 0,8,16... ld a,(hl) ; get current column push af ; save it on stack and 0F8h ; mask off lower 3 bits add a,8 ; to next tab stop ld (hl),a ; store it back to column count pop af ; recover original count ld b,a ; put it in B ld a,(hl) ; get new count sub b ; ..find the difference ld b,a ; put count in B ld a,' ' ; ..and pad it with spaces TabLp: call cout djnz TabLp jr TabEnd ; NotTab: cp BS ; is it a backspace? jr nz,OutChr ; (no, print it and return dec (hl) ; yes, so decrement column count jr OutChr ; ..print it ; NotCtl: inc (hl) ; increment column OutChr: call cout ; print character in A TabEnd: pop af pop bc pop hl ret ; ; PrSrch -- Tell 'em we haven't crashed! ; PrSrch: ld a,(StrLen) ; print "searching" only if search string dec a ; ..is longer than one character ret z ; ..(which matches just about everything) ld a,(QtFlag) or a ret nz ; (also skip it if quiet flag is set) ld a,(EntVid) or a call nz,stndout call ILPrt db CR,'[searching]',CR,0 ld a,(EntVid) or a call nz,stndend ret ; ; GetByt -- Returns next byte from input stream in A. ; GetByt: ld de,(InPtr) inc de ld (InPtr),de ld a,e cp 128 call z,RdSec ; if 0, read another sector ld a,(de) ; get byte to return ret ; ; RdSec -- Read a sector from disk. Return carry set on end of file. ; RdSec: ld de,(InBuf) ; re-initialize pointer ld (InPtr),de push de ; save pointer ld c,SetDma ; set DMA to 80h call bdos ld de,InFcb ld c,FRead ; read file call bdos pop de ; recover pointer or a ret z ; (okay) scf ; end of file, return carry ret ; ; UncOut -- Called by UNCREL with uncrunched character in A. Load characters ; into default DMA buffer until it fills, then call search and display ; routine. ; UncOut: ld de,(DmaPtr) and 7Fh ld (de),a inc e ld (DmaPtr),de ret nz exx ld hl,CpmDma call TstChr exx ld hl,CpmDma ld (DmaPtr),hl ret ; ; Uninitialized data . . . ; DSEG ; UseHdr: ds 1 ; FFh=use header UseAlt: ds 1 ; FFh=use alternate header PagFlg: ds 1 ; 0=page, FFh=don't page, 4=ask UseSpc: ds 1 ; FFh=double space between entries HdrVid: ds 1 ; header video attributes EntVid: ds 1 ; entry video attributes ErCode: ds 1 ; error code ScrCol: ds 1 ; current screen column (for TabIt) LinCnt: ds 1 ; current line count CrnFlg: ds 1 ; non-zero=crunched file FSFlag: ds 1 ; FFh=no filespec ExtFlg: ds 1 ; non-zero=extended TCAP EntFlg: ds 1 ; FFh=first entry on screen CrtLin: ds 1 ; lines on CRT LstFlg: ds 1 ; FFh=printer output LinBeg: ds 1 ; flag: non-zero=beginning of line UseFlg: ds 1 ; 0=no fn.ft in usage message StrLen: ds 1 ; length of match string StrPtr: ds 2 ; match string buffer pointer StrBuf: ds 128 ; string to match storage OutBuf: ds 2 ; output buffer address BufLim: ds 1 ; output buffer limit InBuf: ds 2 ; address of read buffer for crunched files CrBuf: ds 2 ; address of 24K buffer for UNC.REL PrtBuf: ds 2 ; print buffer address InPtr: ds 2 ; pointer to input (read) buffer for UNC DmaPtr: ds 2 ; pointer to output buffer for UNC InFcb: ds 36 ; file control block ds 100 ; stack Stack: ds 2 ; old stack pointer storage ; end