; SFILE31.ASM - SuperFILE v31 for CP/M-80 - October 4, 1986 ; ; ; NOTE: Read the SFILE.HIS file to follow ; the ongoing history of this pgm. ; ; ; NOTE: This version assembles with ; ASM, LASM, MAC, M80 or SLRMAC ; ; ; ASEG ; Needed by the M80 assembler, ignore for others ; VER: EQU 31 ; Version 3.1 86/09/04 ; ; This program allows full wildcard searches of the directories and all ; library files on a CP/M system for a requested file, starting at A0: ; The user can optionally specify a single drive to be searched by in- ; cluding the drive name as a prefix to the search file. This is based ; on SD-81, so credit is given to the MANY people that have worked on it ; in the past. ; ; This program is particularly beneficial on a RCPM with a large disk ; system. You may wish to do the following: ; ; FILE.COM - set CKLBR option to NO ; SFILE.COM - set CKLBR option to YES ; ; This gives the users two separate programs to use - on large systems, ; it may take as long as 5-6 minutes to find a program if using SFILE, ; while searching for the same program may only take 30-40 seconds with ; FILE. ; ; Entering SFILE or SFILE ? will display a brief help message. ; ; The USER AREA PATCH TABLE is the same as in SD - if 0FFH is placed in ; an user location, that drive will be skipped. This makes it possible ; to use the program on multi-disk systems where the drive numbers are ; not necessarily sequential. ; ; The program can now be optionally assembled to support named directories. ; If the RCPM uses 'CD ' (or something similar) to change areas, ; then the program will report the name of the area rather than d/u. The ; list of directoriy names is currently 'hard wired' into the program and ; must be updated each time the area names are changed. Name tables begin ; at ATABLE:; there is one table for each drive available and pointers to ; these tables must be inserted at PTRTBL:. ;======================================================================= ; current revision ; ; 86/03/12 Added option to display area names instead of d/u. Many ; v30 RCPM's now use CD.COM or similar utilities to change areas ; on the hard disk. This makes d/u display of found files ; rather useless. Names must be hardwired into code at ; locations ATABLE:, BTABLE:, etc and pointers to each table ; at PTRTBL:. Also expanded 'ck' to 'checking'; too many ; users asking "What does ck mean?" ; - Ian Cottrell ; ICBBS ; 613-990-9774 ; ;======================================================================= ; ; NO EQU 0 YES EQU NOT NO ; (Cannot be 0FFH for some assemblers) ; CR EQU 0DH LF EQU 0AH ESC EQU 1BH ; ; ; To skip or include library searches ; CKLBR EQU YES ; YES to include .LBR searches ; NO to skip looking in .LBR files ; (then name that version FILE.COM) ; ; ZCPR Compatibility - disregard MAXD and MAXU if ZCPR is NO ; ZCPR EQU NO ; YES = ZCPR/BYE used for MAX D/U MAXD EQU 3DH ; Set to max drive location _/ / MAXU EQU 3FH ; Set to max user location ___/ ; ; ; To skip or include $SYS search and/or WHEEL check ; CKSYS EQU NO ; YES to include system files CKWHL EQU NO ; YES if you use the WHEEL WHEEL EQU 3EH ; Normal WHEEL byte location ; ; ; To display $SYS or R/O files that have attributes set, in lower-case. ; USELC EQU YES ; YES to show attribute(s) in lower case ; ; ; To use area names instead of DU: ; ; NAMDIR EQU YES ; YES to use directory names ; Be sure to change ATABLE:, BTABLE:, etc ; to reflect the area names on your system ; ; BDOS equates ; BDOS EQU 0005H FCB EQU 005CH TBUF EQU 0080H ; RDCHR EQU 1 ; Read character from console WRCHR EQU 2 ; Write character to console PRINTS EQU 9 ; Print string CONST EQU 11 ; Check console status RESET EQU 13 ; Reset disk system SELDSK EQU 14 ; Select disk OPEN EQU 15 ; 0FFH = not found CLOSE EQU 16 ; " " " SEARCH EQU 17 ; " " " NEXT EQU 18 ; " " " READ EQU 20 ; Not 0 = EOF WRITE EQU 21 ; Not 0 = disk full MAKE EQU 22 ; 0FFH = directory full CURDSK EQU 25 ; Get currently logged disk name SETDMA EQU 26 ; Set current DMA GALLOC EQU 27 ; Get address of allocation vector CURDPB EQU 31 ; Get current disk parameters CURUSR EQU 32 ; Get currently logged user number READRN EQU 33 ; Get random read RECORD EQU 36 ; Set random record number ; ARCMAR EQU 26 ; Archive header marker byte HDRSIZ EQU 27 ; Header size for archive (-4 if version = 1) FCR EQU 32 FRN EQU 33 ; ; ORG 0100H ; JMP START ; ; ;----------------------------------------------------------------------- ; ; Drive/user area lookup table ; ; Configure the following table for your specific needs. CP/M v2.2 can ; have 16 user areas (0-15), but ZCPR3 extends this to 32 user areas ; (0-31). If the ZCPR equate is set YES, you can totally disregard the ; following table, if the CLWHL is also set YES. ; ; Assuming ZCPR is set NO, then insert the maximum user area allowed for ; each drive. Put a 0FFH for all drives that are not available. This ; allows use of non-sequential drive systems. ; ; With the CKWHL equate set YES, all user areas available will then be ; searched, regardless what is placed into the following table, when the ; WHEEL byte is set high by ZCPR. ; LODRV EQU $ ; Mark beginning of drive/user table ; DB 1 ; 1) A: drive maximum user area DB 0FFH ; 2) B: drive maximum user area DB 0FFH ; 2) C: drive maximum user area DB 0FFH ; 2) D: drive maximum user area DB 0FFH ; 2) E: drive maximum user area DB 0FFH ; 2) F: drive maximum user area DB 0FFH ; 2) G: drive maximum user area DB 0FFH ; 2) H: drive maximum user area DB 0FFH ; 2) I: drive maximum user area DB 0FFH ; 2) J: drive maximum user area DB 0FFH ; 2) K: drive maximum user area DB 0FFH ; 2) L: drive maximum user area DB 0FFH ; 2) M: drive maximum user area DB 0FFH ; 2) N: drive maximum user area DB 0FFH ; 2) O: drive maximum user area DB 15 ; 2) P: drive maximum user area ; HIDRV EQU $ ; Mark end of drive/user table ; ; ;----------------------------------------------------------------------- ; ; Program starts here ; ;----------------------------------------------------------------------- ; ; START: LXI H,0 DAD SP ; HL=old stack SHLD STACK ; Save it LXI SP,STACK ; Get new stack ; XRA A STA FNDFLG ; Clear file found flag STA NEWUSR ; Make new user = 0 STA BASUSR ; Duplicate it if multi-disk mode MVI C,48 ; Get ZRDOS version CALL BDOS MOV A,L STA ZRDFLG ; Save it MVI C,12 ; Get and save the CP/M version # CALL BDOS MOV A,L STA VERFLG STA DOPFLG ; Do not allow multi-drive yet CPI 20H ; Set carry if CP/M 1.4 JC VERERR ; Exit on earlier than 2.0 LXI H,FCB+1 ; Point to name MOV A,M ; Any specified? CPI ' ' JZ GUIDE ; So print help guide CPI '?' JNZ START1 LDA FCB+2 ; Question mark by itself? CPI ' ' JZ GUIDE ; If yes, print help guide ; START1: PUSH H ; Save FCB address LXI D,SEARN ; Point to search name holding area MVI B,11 ; Size of file name, type CALL MOVE ; Move it POP H ; Restore fcb address MVI E,0FFH ; Get current user number MVI C,CURUSR CALL CPM STA OLDUSR ; Initialize startup user number ; CLNON: MVI C,CURDSK CALL CPM ; Get current disk number STA OLDDSK ; Save for reset if needed LXI H,FCB MOV A,M ; Get drive name for directory search ORA A ; Any specified? JNZ START2 ; Yes skip next routine XRA A STA DOPFLG ; Ok let multi-drive in MVI A,1 ; Otherwise, get disk 'A:' ; START2: MOV M,A ; Put the absolute drive code in FCB ; CKREST: LXI D,SIGNON CALL PRINT ; IF CKWHL LDA WHEEL ; WHEEL set? ORA A JZ CKRST1 ; NO - don't bother with $SYS files ENDIF ; CKWHL ; IF CKSYS OR CKWHL LXI D,SIGN1 CALL PRINT ENDIF ; CKSYS OR CKWHL CKRST1: LXI D,SIGN2 CALL PRINT ; LDA DOPFLG ORA A CZ SWAPEM ; Swap BDOS error vector tables ; ; ; Validate drive code and user area numbers from the drive table ; NOOPT: LXI D,DRVMSG ; Get the drive/user error message PUSH D LDA FCB ; Get directory drive code DCR A ; Normalize to range of 0-15 drives ; IF NOT ZCPR CPI HIDRV-LODRV ; Compare with maximum drives on-line JNC ERXIT ; Take drive error exit if out of range ENDIF ; NOT ZCPR ; IF ZCPR LXI H,MAXD ; Adddress to HL MOV L,M ; MAXD to L INX H ; Add one CMP L ; Check it JNC EX0 ; Exit if out of range ENDIF ; ZCPR ; LXI H,USRMSG ; Switch to user # error message XTHL MOV E,A ; Use drive code as index into table MVI D,0 ; IF NOT ZCPR USRCK: LXI H,LODRV ; Point to base of drive/user table DAD D MOV A,M ; Get the maximum user # for this drive CPI 0FFH ; Check for skip drive JZ ERXIT ; Exit if not wanted ENDIF ; NOT ZCPR ; IF ZCPR LDA MAXU SUI 1 ENDIF ; ZCPR ; USRCK2: ANI 1FH ; Make sure its in range 0-31 STA MAXUSR ; Save it for later LXI H,NEWUSR ; Point to the directory user area CMP M ; Compare it with the maximum JC ERXIT ; Take error exit if user number illegal POP D ; Destroy error message pointer LXI H,FCB+1 ; Point to name ; ; ; Make FCB all '?' to search for every file ; WCD: MVI B,11 ; Filename + filetype count ; QLOOP: MVI M,'?' ; Store '?' in FCB INX H DCR B JNZ QLOOP ; GOTFCB: MVI A,'?' ; Force wild extent STA FCB+12 CALL SETSRC ; Set DMA for BDOS media change check LXI H,FCB ; Point to fcb drive code for directory MOV E,M ; Get the drive code out of the FCB DCR E ; Normalize drive code for select MVI C,SELDSK ; Select the directory drive to retrieve CALL CPM ; The proper allocation vector MVI C,CURDPB ; It is 2.x or MP/M...request DPB CALL BDOS INX H INX H MOV A,M ; Get block shift STA BLKSHF INX H ; Bump to block mask MOV A,M STA BLKMSK ; Get it INX H INX H MOV E,M ; Get max block # INX H MOV D,M XCHG SHLD BLKMAX ; Save it XCHG INX H MOV E,M ; Get directory size INX H MOV D,M XCHG SHLD DIRMAX ; Save max # of entries in directory ; ; ; Re-enter here on subsequent passes while in the all-users mode ; SETTBL: LDA FCB IF NOT NAMDIR ADI 'A'-1 STA PROC1 LXI D,PROCES ; Show the user what area is being CALL PRINT ; worked on LDA NEWUSR STA LSTUSR CALL TYPUSR LXI D,PROC2 CALL PRINT ENDIF ; NOT NAMDIR IF NAMDIR CALL PRTNAM LXI D,PROCES CALL PRINT ENDIF ; NAMDIR ; SETTB1: LHLD DIRMAX ; Get directory maximum again INX H ; Directory size is DIRMAX+1 DAD H ; Double directory size LXI D,ORDER ; To get size of order table DAD D ; Allocate order table SHLD TBLOC ; Name table begins after order table SHLD NEXTT XCHG LHLD BDOS+1 ; Make sure we have room to continue MOV A,E SUB L MOV A,D SBB H JNC OUTMEM LDA NEWUSR ; Get user area for directory MOV E,A MVI C,CURUSR ; Get the user function CALL CPM ; And set new user number ; ; ; Look up the FCB in the directory ; MVI A,'?' LXI H,FCB+12 MOV M,A ; Match all extents INX H MOV M,A ; Match all S1 bytes INX H MOV M,A ; Match all S2 bytes LXI H,0 SHLD COUNT ; Initialize match counter CALL SETSRC ; Set DMA for directory search MVI C,SEARCH ; Get 'SEARCH FIRST' function JMP LOOK ; And go search for 1st match ;..... ; ; ; Read more directory entries ; MORDIR: MVI C,NEXT ; Search next ; LOOK: LXI D,FCB CALL CPM ; Read directory entry INR A ; Check for end (0FFH) JZ SPRINT ; If no more, sort & print what we have ; ; ; Point to directory entry ; SOME: DCR A ; Undo prev 'INR A' ANI 3 ; Make modulus 4 ADD A ; Multiply by 32 as each entry is 32 ADD A ; bytes long ADD A ADD A ADD A LXI H,TBUF+1 ; Point to buffer (skip to filename) ADD L ; Point to entry ADI 9 ; Point to .SYS byte MOV L,A ; Save (can't carry to 'H') ; IF CKWHL LDA WHEEL ; WHEEL set? ORA A JNZ SYSFOK ; YES - show $SYS files, too ENDIF ; CKWHL ; IF CKSYS AND (NOT CKWHL) JMP SYSFOK ; Show system files too ENDIF ; CKSYS AND (NOT CKWHL) ; MOV A,M ; Get .SYS byte ORA A ; Check bit 7 JM MORDIR ; Skip that file ; SYSFOK: MOV A,L ; Go back now SUI 10 ; Back to user number (allocation flag) MOV L,A ; Hl points to entry now LDA NEWUSR ; Get current user CMP M JNZ MORDIR ; Ignore if different INX H ; ; ; Move entry to table ; XCHG ; Entry to DE LHLD NEXTT ; Next table entry to HL MVI B,11 ; Entry length (name, type, extent) ; TMOVE: LDAX D ; Get entry character ; IF NOT USELC ANI 7FH ; Remove attributes ENDIF ; NOT USELC ; MOV M,A ; Store in table INX D INX H DCR B ; More? JNZ TMOVE INX D ; DE->> S1 INX D ; DE->> S2 LDAX D ; Get S2 byte, overflow=int(extents/32) PUSH H ; Save HL MOV L,A ; Set up 16-bit multiply MVI H,0 MVI B,5 CALL SHLL ; HL is now # of overflow extents DCX D ; DE->> S1 DCX D ; DE->> extent LDAX D ; Get extent ADD L MOV L,A MOV A,H ACI 0 MOV H,A ; HL now has total extents MVI B,7 CALL SHLL ; HL now has total records less last ext INX D ; DE->> S1 INX D ; DE->> S2 INX D ; Point to record count LDAX D ; Get it ADD L MOV L,A MOV A,H ACI 0 MOV H,A ; HL now has total records XTHL ; Do some fancy shuffling XCHG XTHL XCHG MOV M,D INX H MOV M,E POP D ; All back to normal INX H SHLD NEXTT ; Save updated table address XCHG LHLD COUNT ; Bump the # of matches made INX H SHLD COUNT LXI H,13 ; Size of next entry DAD D XCHG ; Future NEXTT is in DE LHLD BDOS+1 ; Pick up TPA end MOV A,E SUB L ; Compare NEXTT-TPA end MOV A,D SBB H JC MORDIR ; If TPA end > NEXTT, loop back for more ; OUTMEM: CALL ERXIT ; Exit if directory too large DB 'Memory',0 ;..... ; ; ;----------------------------------------------------------------------- ; s u b r o u t i n e s ;----------------------------------------------------------------------- ; ; ; Fetch character from console (without echo) ; CINPUT: LHLD 0001H MVI L,9 CALL GOHL ANI 7FH RET ;..... ; ; ; Check for a CTL-C or CTL-S entered from the keyboard. Jump to exit ; if CTL-C, pause on CTL-S. ; CKABRT: LHLD 0001H MVI L,6 ; Check status of keyboard CALL GOHL ; Any key pressed? ORA A RZ ; No, return to caller CALL CINPUT ; Get character CPI 'C'-40H ; CTL-C? JZ EX0 ; If yes then quit CPI 'X'-40H ; CTL-X? JZ EX0 ; If yes then quit CPI 'S'-40H ; CTL-S? RNZ ; No, return to caller CALL CINPUT ; Yes, wait for another char. CPI 'C'-40H ; Might be CTL-C JZ EX0 ; If yes then quit CPI 'X'-40H ; Might be CTL-X JZ EX0 ; If yes fall through and continue RET ;..... ; ; ; Test file extent for LBR ; CKLBRY: PUSH H PUSH D PUSH B XCHG LXI H,LBRTYP MVI C,3 ; CKLBL: LDAX D ANI 7FH CMP M JNZ CKLBX INX H INX D DCR C JNZ CKLBL CKLBX: POP B POP D POP H RET ;..... ; ; ; Test file extent for ARC ; CKARC: PUSH H PUSH D PUSH B XCHG LXI H,ARCTYP MVI C,3 ; CKARL: LDAX D ANI 7FH CMP M JNZ CKARX INX H INX D DCR C JNZ CKARL ; CKARX: POP B POP D POP H RET ARCTYP: DB 'ARC' ;..... ; ; ; Check to see if there indeed is a library file directory ; CKLDIR: MVI B,11 ; Length of file name MVI A,' ' ; Space INX H ; CKDLP: CMP M JNZ LMLEXI DCR B INX H JNZ CKDLP ; ; ; The first entry in the LBR directory is indeed blank. Now see if the ; directory size is >0 ; MOV E,M ; File starting location low INX H ; Must be zero here MOV A,M ; File starting location high ORA E ; Must be zero here also JNZ LMLEXI INX H MOV E,M ; Get library size low INX H ; Point to library size high MOV D,M ; Get library size high MOV A,D ORA E ; Library must have some size JZ LMLEXI DCX D XCHG SHLD SLFILE MVI B,3 LXI H,17 DAD D PUSH H LHLD TLIBRA INX H SHLD TLIBRA POP H JMP LMTEST ;..... ; ; ; New compare routine ; COMPARE:LXI B,ORDER-2 DAD H DAD B XCHG DAD H DAD B XCHG MOV C,M INX H MOV B,M XCHG MOV E,M INX H MOV D,M XCHG MOV E,A ; Count ; CMPLPE: MOV A,M ANI 7FH MOV D,A LDAX B ANI 7FH CMP D INX B INX H RNZ DCR E JNZ CMPLPE RET ;..... ; ; ; Compare routine for sort ; COMPR: PUSH H ; Save table address MOV E,M ; Load low order INX H MOV D,M ; Load high order INX H MOV C,M INX H MOV B,M ; ; ; BC, DE now point to entries to be compared ; XCHG MOV E,A ; Get count ; CMPLP: MOV A,M ANI 7FH MOV D,A LDAX B ANI 7FH CMP D INX H INX B JNZ NOTEQL ; Quit on mismatch DCR E ; Or end of count JNZ CMPLP ; NOTEQL: POP H RET ; Cond code tells all ;..... ; ; ; Entry to BDOS saving all extended registers ; CPM: PUSH B PUSH D PUSH H LDA ZRDFLG ; ZRDOS running? ORA A JNZ ZRD ; ZRDOS error trap and DOSs call CALL BDOS MOV B,A ; Save return code LDA VERFLG ; Is this 3.0? CPI 30H MOV A,B JC CPM20 ; No, exit normally CPI 0FFH ; It is 3.0 - was return code ff? JNZ CPM20 ; No, exit normally MOV A,H ; 3.0 and A=FF - check for error code ORA A JNZ DSKERR ; Trap out if we got a physical error MOV A,B ; Else continue normally ; CPM20: POP H POP D POP B RET ;..... ; ; ; Start a new line ; CRLF: MVI A,CR ; Send CR CALL TYPE MVI A,LF ; Send LF JMP TYPE ; Exit to caller from TYPE ;..... ; ; ; Print HL in decimal with leading zero suppression ; DECPRT: XRA A ; Clear leading zero flag STA LZFLG LXI D,-1000 ; Print 1000'S DIGIT CALL DIGIT LXI D,-100 ; Etc. CALL DIGIT LXI D,-10 CALL DIGIT MVI A,'0' ; Get 1'S DIGIT ADD L JMP TYPE ; DIGIT: MVI B,'0' ; Start off with ASCII 0 ; DIGLP: PUSH H ; Save current remainder DAD D ; Subtract JNC DIGEX ; Quit on overflow POP PSW ; Throw away remainder INR B ; Bump digit JMP DIGLP ; Loop back ; DIGEX: POP H ; Restore pointer MOV A,B CPI '0' ; Zero digit? JNZ DIGNZ ; No, type it LDA LZFLG ; Leading zero? ORA A MVI A,'0' JNZ TYPE ; Print digit LDA SUPSPC ; Get space suppression flag ORA A ; See if printing file totals RZ ; Yes, don't give leading spaces MVI A,' ' JMP TYPE ; Leading zero, so print space ; DIGNZ: STA LZFLG ; Leading zero flag so next zero prints JMP TYPE ; And print digit ;..... ; ; ; Compute the size of the file/library and update our summary datum. ; This has been changed into a subroutine so that both the file size ; computation and a library size (when printing out library members) ; can be computed in k. ; DOIT: MOV E,M ; Get extent # MVI D,0 INX H MOV A,M ; Get record count of last extent XCHG DAD H ; # of extents times 16k DAD H DAD H DAD H XCHG ; Save in DE LXI H,BLKMSK ADD M ; Round last extent to block size RRC RRC ; Convert from records to k RRC ANI 1FH MOV L,A ; Add to total k MVI H,0 DAD D LDA BLKMSK ; Get records/blk-1 RRC RRC ; Convert to k/blk RRC ANI 1FH CMA ; Use to finish rounding ANA L MOV L,A RET ;..... ; ; ; Recovery point from intercepted BDOS select and bad sector errors. ; DSKERR: LXI SP,STACK ; Get out of BDOS' STACK JMP EXIT ; And exit back to CCP ;..... ; ; ; Output the directory files we've matched. ; ENTRY: LHLD COUNT DCX H ; Dock file count SHLD COUNT MOV A,H ; Is this the last file? ORA L JZ OKPRNT ; If count=0, last file so skip compare ; ; ; Compare each entry to make sure that it isn't part of a multiple ex- ; tent file. Go only when we have the last extent of the file. ; CALL CKABRT ; Check for abort code from keyboard LHLD NEXTT MVI A,11 CALL COMPR ; Does this entry match next one? JNZ OKPRNT ; No, print it INX H INX H ; Skip since highest extent last in list SHLD NEXTT JMP ENTRY ; Loop back for next lowest extent ;..... ; ; ENTRYL: LHLD LCOUNT ; Get FCB count DCX H ; Decrement it SHLD LCOUNT MOV A,H ; Is this the last file? ORA L JZ LBRTST ; If count=0, last file skip compare PUSH B CALL CKABRT ; Check for abort code from keyboard LHLD NEXTL MVI A,11 CALL COMPR ; Does this entry match next one? POP B JNZ LBRTST ; No, print it INX H INX H ; Skip, highest extent comes last in list SHLD NEXTL JMP ENTRYL ; Loop back for next lowest extent ;..... ; ; ; Error exit ; ERXIT: CALL CRLF ; Space down POP D ; Get pointer to message string CALL PRINT ; Print it LXI D,ERRMS1 ; Print " error" CALL PRINT CALL CRLF ; Space down ; ; ; Exit - all done restore stack ; EXIT: LDA DOPFLG ; Check multi disk mode ORA A JNZ EX0 CALL CKABRT ; Check for user abort first ; IF NOT ZCPR MVI A,HIDRV-LODRV ; Get maximum drive code to search ENDIF ; NOT ZCPR ; IF ZCPR LDA MAXD ENDIF ; ZCPR ; LXI H,FCB ; Bump directory fcb drive code INR M CMP M ; Does next disk exceed maximum? JC EX0 JMP NOOPT ; Search next disk if MAXDR not true ;..... ; ; ; Prints the ending results ; EX0: LXI D,CLEAR CALL PRINT IF NAMDIR LXI D,AREA ; Show the last area searched CALL PRINT ENDIF ; NAMDIR IF NOT NAMDIR LXI D,PROC1 ; Show the last drive searched CALL PRINT LDA LSTUSR STA NEWUSR CALL TYPUSR ; Show the last user area searched LXI D,PROC2 CALL PRINT ENDIF ; NOT NAMDIR XRA A ; Be sure space suppress flag is set STA SUPSPC ; IF CKLBR LXI D,TLMSG CALL PRINT LHLD TLIBRA CALL DECPRT ENDIF ; CKLBR ; LXI D,TMMSG CALL PRINT LHLD TMATCH CALL DECPRT LXI D,TCMSG CALL PRINT LHLD TFILES CALL DECPRT ; CALL CRLF ; Just for neatness MVI C,CONST ; Check console status CALL CPM ORA A ; Char waiting? MVI C,RDCHR CNZ CPM ; Gobble up character LDA VERFLG ; Or error mode, depending on version CPI 30H JC EXIT0 MVI C,45 MVI E,0 ; Set error mode back to default CALL CPM JMP EXIT1 ; EXIT0: LDA DOPFLG ; If they were swapped ORA A CZ SWAPEM ; EXIT1: LHLD STACK ; Get old stack pointer SPHL ; Move back to old stack RET ; And return to CCP ;..... ; ; ; Kludge to allow call to address in HL ; GOHL: PCHL JMP CPM ;..... ; ; GUIDE: LXI D,HELP ; Print help information CALL PRINT ; IF CKWHL LDA WHEEL ; WHEEL set? ORA A JZ GUIDE1 ; NO - don't bother with $SYS files ENDIF ; CKWHL ; IF CKSYS OR CKWHL LXI D,HELP1 CALL PRINT ENDIF ; CKSYS OR CKWHL ; GUIDE1: LXI D,HELP2 JMP VERER1 ;..... ; ; ; Close the library file ; LBCLOSE:LXI D,LBRFCB MVI C,CLOSE CALL CPM RET ;..... ; ; ; Exit library member printing ; LBEXIT: XRA A ; Get a zero to... STA SUPSPC ; Suppress leading spaces in totals RET ;..... ; ; ; At least one more file to output - can we put it on the current line? ; LBGNXT: POP B POP H JMP LMTESA ; And go output another file ; COMPS: PUSH H PUSH D PUSH B LXI B,SEARN MVI E,11 ; COMPS1: MOV A,M ANI 7FH MOV D,A LDAX B INX B INX H ANI 7FH CPI '?' JZ COMPS2 CMP D JNZ COMPS3 ; COMPS2: DCR E JNZ COMPS1 ; COMPS3: POP B POP D POP H RET ;..... ; ; ; Valid entry obtained - spit it out ; LBRTST: MVI A,1 ; Set not an .ARC file as default STA ISARC ; in type of file flag. LHLD NEXTL ; Get order table pointer MOV E,M ; Get low order address INX H MOV D,M ; Get high order address INX H SHLD NEXTL ; Save updated table pointer LXI H,8 DAD D CALL CKLBRY JZ LBRSET ; It's a library so skip .ARC test CALL CKARC ; Check if current file is a .ARC JNZ LBRNEX XRA A STA ISARC ; Save current file type is arc LBRSET: PUSH D POP H ; ; ; Saves the library file name into LBRFCB ; LDA FCB LXI D,LBRFCB ; To STAX D INX D MVI B,11 ; Length CALL MOVE ; Do the move XCHG MVI B,25 ; CLMFCB: MVI M,0 INX H DCR B JNZ CLMFCB CALL SETLDMA LXI D,LBRFCB ; Point to file MVI C,OPEN ; Get function CALL CPM ; Open it MVI C,READ LXI D,LBRFCB CALL CPM CALL SETFOP LXI H,LBBUF MOV A,M ORA A JZ CKLDIR ; Check directory present? LDA ISARC ; Was file a .ARC file ORA A JNZ LMLEXI ; No so error MOV A,M ; Get buffer byte again CPI ARCMAR ; is an arc mark ? JZ CKADIR ; Yep so Check directory present? ; LMLEXI: CALL LBCLOSE ; ; ; Do next library file ; LBRNEX: LHLD LCOUNT ; Check count MOV A,H ORA L JZ LBEXIT ; No more, all done JMP ENTRYL ; Else, get next .lbr file ;..... ; ; LFMLOP: LHLD SLFILE ; Get MOV A,L ORA H JZ LMLEXI DCX H SHLD SLFILE CALL SETLDMA MVI C,READ LXI D,LBRFCB CALL CPM CALL SETFOP MVI B,4 ; Get file count per record LXI H,LBBUF ; Get buffer starting address ; LMTEST: MOV A,M ; Get member open flag ORA A ; Test for open JZ PRMNAM ; LMTESA: LDA ISARC ; Test if we are doing an arc file ORA A RZ ; Just return if .arc LXI D,32 ; Member not open get offset DAD D ; To next and add it in. DCR B ; Is buffer empty ? JNZ LMTEST ; No so test next entry JMP LFMLOP ; Yes get next buffer... ; ;..... ; ; ;------------------------------------------------ ; Archive file subroutines ;------------------------------------------------ ; CKADIR: XRA A DCR A STA GETABL ; Say buffer is full (first read by lbr test) LHLD TLIBRA ; Bump library count total INX H SHLD TLIBRA ARCLP: CALL GET ; Get the next character from buffer CPI ARCMAR ; Is it archive header marker? JNZ LMLEXI ; and abort if not CALL GET ; Get header version ORA A ; If zero, that's logical end of file, JZ LMLEXI ; and we're done LXI D,ANAME ; Set to fill header buffer MVI B,HDRSIZ ; Setup normal header size less file name CPI 1 ; But test if version 1 JNZ GETHD1 ; Skip if not version 1 LXI B,HDRSIZ-4 ; Else, header is 4 bytes less GETHD1: CALL GET ; Get header byte STAX D ; Store in buffer INX D DCR B JNZ GETHD1 ; Loop for all bytes LXI H,ARCFIL ; Prefill dummy arc fcb name with spaces MVI B,11 FIXAN: MVI M,' ' INX H DCR B JNZ FIXAN MVI B,5 ; Prefill rest of dummy fcb with zero FIXAE: MVI M,0 INX H DCR B JNZ FIXAE LXI H,ANAME ; Get pointer to archive header buffer LXI D,ARCFIL ; Point to our dummy fcb MVI B,8 ; Get name length MANAME: MOV A,M ; Get character from header INX H ORA A JZ AEDONE ; Nothing in buffer so we're done CPI 02EH ; Is the char a point JZ DAEXT ; DO FILE EXTENT STAX D INX D DCR B JNZ MANAME DAEXT: LXI D,ARCFIL+8 ; Get dummy file extent address MVI B,3 MOV A,M CPI 2EH JNZ AELOP INX H AELOP: MOV A,M ; Fill in the file extent ORA A JZ AEDONE STAX D INX H INX D DCR B JNZ AELOP AEDONE: LXI H,ASIZE MOV E,M ; Fetch BCDE from (HL) INX H MOV D,M INX H MOV C,M XRA A ; Clear flags MOV A,E ; Convert file length count in bytes RAL ; to length in records for output MOV A,D RAL MOV E,A MOV A,C RAL MOV D,A XCHG SHLD ARCFIL+13 ; Save file length LXI H,ARCFIL-1 ; Point to dummy fcb CALL PRMNAM ; List the file info LXI H,ASIZE ; Get remaining file size MOV A,M ANI 7FH LHLD ARCFIL+13 ; Save file length XCHG ; Save record offset LXI H,GETABL ; Point to offset of last byte read ADD M ; Add byte offsets CPI 80H ; Does it overflow current record? JC NRAD SUI 80H ; Adjust pointer INX D ; Bump record number NRAD: MOV M,A ; Update buffer ptr for new position MOV A,D ; Check record offset ORA E JZ LEXIT ; Return if none (still in same record) SEEK2: PUSH D ; Save record offset LXI D,LBRFCB MVI C,RECORD ; Compute current "random" record no. CALL CPM ; (I.e. next sequential record to read) LHLD LBRFCB+FRN ; Get result DCX H ; Adjust next record to current record POP D ; Restore record offset DAD D ; Compute new record no. JC LMLEXI ; If >64k, it's past largest (8 Mb) file SHLD LBRFCB+FRN ; Save new record no. MVI C,READRN ; Read the random record CALL GETREC ORA A JNZ LMLEXI ; File read error LXI H,LBRFCB+FCR ; Point to current record in extent INR M ; Bump for subsequent sequential read LEXIT: JMP ARCLP ; Loop for next file ;..... ; ; ; Get next sequential byte from archive file ; GET: PUSH B ; Save registers PUSH D PUSH H LDA GETABL ; Point to last byte read INR A ; At end of buffer? CPI 80H CNC GETNXT ; Yes, read next record and reset ptr STA GETABL ; Save new buffer ptr MOV L,A MVI H,0 LXI D,LBBUF DAD D MOV A,M ; Fetch byte from there POP H ; Restore registers POP D POP B RET ; Return ;..... ; ; ; Get next sequential record from archive file ; GETNXT: MVI C,READ ; Setup read-sequential function code CALL GETREC ORA A JNZ RDERR PUSH PSW XRA A DCR A STA GETABL POP PSW RET RDERR: POP H ; Strip getnxt return POP H ; Clean up the get stack POP D POP B POP H ; strip get calling address JMP LMLEXI ; Show error ;..... ; ; ; Get record (sequential or random) from archive file ; GETREC: PUSH H PUSH B CALL SETLDMA ; Set library DMA address LXI D,LBRFCB ; Setup FCB address POP B ; Restore read function CALL CPM ; Do it PUSH PSW ; Save read status CALL SETFOP ; Reset Print file DMA address POP PSW ; Restore read status POP H ; Restore buffer ptr RET ;..... ; ; ; Move characters from 'HL' to 'DE' length in 'B' ; MOVE: MOV A,M ; Get a character STAX D ; Store it INX H ; To next 'FROM' INX D ; To next 'TO' DCR B ; More? JNZ MOVE ; Yes, loop RET ; No, return ;..... ; ; ; Sort is all done - print entries that compare ; NOOUT: LHLD COUNT SHLD LCOUNT LXI H,ORDER ; Initialize order table pointer SHLD NEXTL SHLD NEXTT JMP ENTRY ;..... ; ; ; Directory for one user area completed. If 'ALL USERS' option is se- ; lected, then go do another directory on the next user number until we ; exceed the maximum user # for the selected drive. ; NXTUSR: CALL CKABRT ; Check for user abort first LDA MAXUSR ; No abort - get maximum user number LXI H,NEWUSR ; Bump directory user number INR M CMP M ; Does next user # exceed maximum? JNC SETTBL ; Continue if more user areas to go LDA BASUSR ; Reset base user number for the MOV M,A ; Next directory search ; ; ; Directory for all user areas completed. If the multi-disk option is ; enabled and selected, reset to the base user area and repeat the di- ; rectory for next drive on-line until we either exceed the drives in ; our LODRV-HIDRV table, or the BDOS shuts us down with a select or bad ; sector error, which will be intercepted back to the exit module. ; NXTDSK: LXI H,FNDFLG ; Get file found flag MVI M,0 ; Clear file found flag for next drive ; NDSK: LDA DOPFLG ; See if the flag is set now ORA A JNZ EXIT ; If yes, all done CALL CKABRT ; Check for user abort first MVI A,HIDRV-LODRV ; Get maximum drive code to search LXI H,FCB ; Bump directory FCB drive code INR M CMP M ; Does next disk exceed maximum? JC EXIT MOV E,M MVI D,0 DCR E LXI H,LODRV DAD D MOV A,M CPI 0FFH JZ NDSK ; Search next disk if MAXDR not true JMP NOOPT ;..... ; ; OKPRNT: LHLD NEXTT ; Get order table pointer MOV E,M ; Get low order address INX H MOV D,M ; Get high order address INX H SHLD NEXTT ; Save updated table pointer XCHG ; Table entry to HL ; ; ; Put in user and drive printout here ; PUSH H ; Save the current address LHLD TFILES INX H SHLD TFILES POP H CALL COMPS ; Match what we are looking for ? JNZ OKEXIT ; No, so don't print it PUSH H LHLD TMATCH INX H SHLD TMATCH POP H MVI A,CR CALL TYPE LDA FCB ; Precede new line with drive name IF NAMDIR CALL PRTNAM ; Type area name LXI D,AREA CALL PRINT ENDIF ; NAMDIR IF NOT NAMDIR ADI 'A'-1 CALL TYPE CALL TYPUSR ENDIF ; NOT NAMDIR MVI A,':' ; Tag header with a colon and a space CALL TYPE ; And exit back to entry MVI A,' ' CALL TYPE IF NOT NAMDIR LDA NEWUSR CPI 10 JNC OVER9 MVI A,' ' CALL TYPE ENDIF ; NOT NAMDIR ; OVER9: MVI B,8 ; File name length CALL TYPENM ; Type filename MVI A,'.' ; Period after filename CALL TYPE MVI B,3 ; Display 3 characters of filetype CALL TYPEXT MOV D,M INX H MOV E,M ; Size in DE (records) LDA BLKMSK PUSH PSW ADD E MOV E,A MOV A,D ACI 0 MOV D,A POP PSW CMA ANA E MOV E,A ; Size in DE MVI B,3 ; SHRR: MOV A,D ORA A RAR MOV D,A MOV A,E RAR MOV E,A DCR B JNZ SHRR XCHG ; Get file size ; ; ; Output the size of the individual file. ; CALL DECPRT ; Go print it MVI A,'k' ; And follow with k size CALL TYPE CALL CRLF MVI A,0FFH STA FNDFLG ; Set file found flag ; ; ; One file output - test to see if we have to output another one. ; OKEXIT: LHLD COUNT ; Get current file counter and test it MOV A,H ORA L JZ PRTOTL ; If no more files exit to summary output JMP ENTRY ;..... ; ; OVER91: MVI B,8 ; File name length CALL TYPENM MVI A,'.' ; Period after file name CALL TYPE MVI B,3 ; Display 3 characters of filetype CALL TYPEXT INX H INX H MOV E,M INX H MOV D,M XCHG ; ; ; Output the size of the individual file. ; PUSH D PUSH H PUSH H LHLD LLENLOC PUSH H POP D POP H DAD D SHLD LLENLOC POP H ; ; ; New code added to convert .LIB members from records to 'k'. Upon ; entry, member's size in records is in HL ; XCHG ; Put it in DE LXI H,0 ; Zero out HL MOV A,E ; Put low byte of record count in a ADI 7 ; Add seven to always round up 1k RRC ; Convert it to k RRC RRC ANI 1FH MOV E,A ; And put it back MOV L,D ; Get the high byte if any MVI D,0 ; Clean out the old resting place DAD H ; Multiply it by 32 to convert to DAD H ; Number DAD H ; Of DAD H ; k DAD H ; Bytes DAD D ; And add in the low byte POP D CALL DECPRT ; Go print it MVI A,'k' ; And follow with size CALL TYPE LXI H,INLBF MVI B,6 CALL TYPENM LXI H,LBRFCB+1 MVI B,8 ; File name length CALL TYPENM MVI A,'.' ; Period after file name CALL TYPE MVI B,3 ; Display 3 characters of filetype CALL TYPEXT CALL CRLF ; So we can still see it! MVI A,0FFH STA FNDFLG ; Set file found flag JMP LBGNXT ;..... ; ; ; Print string terminated with '0' character ; PRINT: LDAX D ORA A RZ ; If zero, finished CALL TYPE ; Display on CRT INX D JMP PRINT ;..... ; ; PRTLMEM: IF NOT CKLBR XRA A RET ; Skip library checks ENDIF ; NOT CKLBR ; LXI H,SEARN+8 CALL CKLBRY RZ LXI H,ORDER ; Initialize order table pointer SHLD NEXTL JMP ENTRYL ;..... ; ; PRMNAM: PUSH H ; Print member name and size PUSH B CALL CKABRT ; Check for abort code from keyboard ; PRMNA1: POP B POP H PUSH H PUSH B INX H PUSH H LHLD TFILES INX H SHLD TFILES POP H CALL COMPS ; Match what we are looking for ? JNZ LBGNXT PUSH H LHLD TMATCH INX H SHLD TMATCH POP H MVI A,CR CALL TYPE LDA FCB ; Precede new line with drive name IF NAMDIR CALL PRTNAM ; Print area name LXI D,AREA CALL PRINT ENDIF ; NAMDIR IF NOT NAMDIR ADI 'A'-1 CALL TYPE CALL TYPUSR ENDIF ; NOT NAMDIR MVI A,':' ; Tag header with a colon and a space CALL TYPE ; And exit back to entry MVI A,' ' CALL TYPE IF NOT NAMDIR LDA NEWUSR CPI 10 JNC OVER91 MVI A,' ' CALL TYPE ENDIF ; NOT NAMDIR JMP OVER91 ;..... ; ; PRTNAM prints the name of the area being searched ; IF NAMDIR PRTNAM: PUSH H ; Save regs PUSH B DCR A ; Adjust - 0=A, 1=B, etc LXI H,PTRTBL ; Point to table of pointers ADD A ; Calculate offset into table MOV C,A MVI B,0 DAD B MOV A,M INX H MOV H,M MOV L,A ; HL now points to name table for drive LDA NEWUSR ; Now calc offset into that table STA LSTUSR ADD A ; *2 ADD A ; *4 ADD A ; *8 MOV C,A ; To BC MVI B,0 DAD B MVI B,8 ; 8 characters in each name LXI D,AREA ; Point to storage buffer AREALP: MOV A,M ; Move name STAX D INX H INX D DCR B JNZ AREALP XRA A STAX D ; Terminator POP B POP H RET ENDIF ; NAMDIR ;..... ; ; ; Now check for libraries ; PRTOTL: LHLD LCOUNT ; How many files did we see? MOV A,H ORA L CNZ PRTLMEM ; Skip the .lbr check if none found XRA A ; Get a zero to... STA SUPSPC ; Suppress leading spaces in totals JMP NXTUSR ;..... ; ; ; Reset Warm Boot Trap in ZRDOS ; RESTRAP:PUSH H PUSH D PUSH B PUSH PSW MVI C,52 ; Reset warm boot trap CALL BDOS POP PSW POP B POP D POP H RET ;..... ; ; ; For file output mode, return to old user area and set dma for the file ; output buffer. ; SETFOP: LDA OLDUSR ; Get user number at startup MOV E,A MVI C,CURUSR CALL CPM ; Reset the old user number RET ;..... ; ; ; Set the library file DMA address ; SETLDMA:LDA NEWUSR ; Get user area for directory MOV E,A MVI C,CURUSR ; Get the user function CALL CPM ; And set new user number LXI D,LBBUF MVI C,SETDMA CALL CPM RET ;..... ; ; ; Move disk buffer dma to default buffer for directory search operations ; and BDOS media change routines (necessary for pre-CP/M 2 systems while ; in file output mode with an active buffer). ; SETSRC: LXI D,TBUF ; SET2: MVI C,SETDMA JMP CPM ;..... ; ; ; Set Warm Boot Trap in ZRDOS ; SETTRAP:PUSH H PUSH D PUSH B MVI C,50 ; Set warm boot trap to come here LXI D,WBTRAP CALL BDOS POP B POP D POP H RET ;..... ; ; ; Shift HL left by B bits ; SHLL: DAD H DCR B RZ JMP SHLL ;..... ; ; ; This sort routine is adapted from Software Tools by Kernigan and ; Plaugher. ; SORT: LHLD SCOUNT ; Number of entries ; L0: ORA A ; Clear carry MOV A,H ; GAP=GAP/2 RAR MOV H,A MOV A,L RAR MOV L,A ORA H ; Is it zero? JZ NOOUT ; Then none left MOV A,L ; Make GAP odd ORI 1 MOV L,A SHLD GAP INX H ; I=GAP+1 ; L2: SHLD I XCHG LHLD GAP MOV A,E ; J=I-GAP SUB L MOV L,A MOV A,D SBB H MOV H,A ; L3: SHLD J XCHG LHLD GAP ; JG=J+GAP DAD D SHLD JG MVI A,13 ; Compare 13 characters CALL COMPARE ; Compare (J) and (JG) JP L5 ; If A(J)<=A(JG) LHLD J XCHG LHLD JG CALL SWAP ; Exchange A(J) and A(JG) LHLD J ; J=J-GAP XCHG LHLD GAP MOV A,E SUB L MOV L,A MOV A,D SBB H MOV H,A JM L5 ; If J>0 goto l3 ORA L ; Check for zero JZ L5 JMP L3 ; L5: LHLD SCOUNT ; For later XCHG LHLD I ; I=I+1 INX H MOV A,E ; If I<=N goto l2 SUB L MOV A,D SBB H JP L2 LHLD GAP JMP L0 ;..... ; ; ; Sort ; SPRINT: CALL SETFOP ; Return to file output DMA & user # LHLD COUNT ; Get file name count MOV A,L ORA H ; Any found? JZ PRTOTL ; Exit if no files found PUSH H ; Save file count STA SUPSPC ; Enable leading zero suppression ; ; ; Initialize the order table ; LHLD TBLOC ; Get start of name table XCHG ; Into DE LXI H,ORDER ; Point to order table LXI B,13 ; Entry length ; BLDORD: MOV M,E ; Save low order address INX H MOV M,D ; Save high order address INX H XCHG ; Table address to HL DAD B ; Point to next entry XCHG XTHL ; Save table addr, fetch loop counter DCX H ; Count down loop MOV A,L ORA H ; More? XTHL ; (restore table address, save counter) JNZ BLDORD ; Yes, go do another one POP H ; Clean loop counter off stack LHLD COUNT ; Get count SHLD SCOUNT ; Save as # to sort DCX H ; Only 1 entry? MOV A,L ORA H JZ NOOUT ; Yes, so skip sort JMP SORT ;..... ; ; ; Swap entries in the order table ; SWAP: LXI B,ORDER-2 ; Table base DAD H ; *2 DAD B ; + base XCHG DAD H ; *2 DAD B ; + base MOV C,M LDAX D XCHG MOV M,C STAX D INX H INX D MOV C,M LDAX D XCHG MOV M,C STAX D RET ;..... ; ; SWAP20: LHLD BDOS+1 ; Get pointer to base of BDOS INX H ; Swap in the new pointer if running a MOV E,M ; Program below the CCP INX H MOV D,M XCHG ; Now HL points to the proper vector MVI L,9 ; Point to record error vector LXI D,VECTBL ; Exchanging with our own vector table MVI A,4 ; 4 bytes to swap ; SWAPLP: MOV B,M ; Get byte from HL XCHG MOV C,M ; Get byte from DE MOV M,B ; Put byte from HL XCHG MOV M,C ; Put byte from DE INX H ; Bump exchange pointers INX D DCR A ; Dock counter JNZ SWAPLP ; Continue swapping til done RET ;..... ; ; ; Trap BDOS select and sector error vectors to our own intercept routine ; so we can catch a reference to an illegal drive. ; SWAPEM: LDA ZRDFLG ; See if ZRDOS running ORA A RNZ ; Yes, quit this LDA VERFLG ; Check version CPI 30H ; See if error mode call is available JC SWAP20 ; If not, use BDOS error vectors MVI C,2DH MVI E,0FFH ; Use set error mode call CALL CPM ; Set "return code only" mode RET ;..... ; ; ; Output character in a to console, and optionally to printer and/or the ; output file. ; TYPE: PUSH B PUSH D PUSH H PUSH PSW ; Save the character to output CALL TYPE1 ; Send it to console POP PSW ; Restore the output character ; TYPRET: POP H ; Exit from type POP D POP B RET ;..... ; ; ; Print a string at HL of length B, retains any high bits set in the ; file extent - can be changed to lower case if USELC option is set YES. ; TYPEXT: MOV A,M CALL TYPE INX H DCR B JNZ TYPEXT RET ;..... ; ; ; Print a string at HL of length B, removes any high bits set. ; TYPENM: MOV A,M ANI 7FH CALL TYPE INX H DCR B JNZ TYPENM RET ;..... ; ; ; Output character ; TYPE1: IF USELC AND CKWHL OR (NOT CKWHL AND NOT ZCPR) ORA A ; Check for attributes not set JP TYPE2 ANI 7FH ; Delete the attribute bit now CPI 'A' ; Change only from A-Z JC TYPE2 CPI 'Z'+1 JNC TYPE2 ; Punctuation can change so leave it ORI 20H ; If attribute, make lower case ENDIF ; USELC AND CKWHL, etc. ; TYPE2: MOV E,A ; Get character into BDOS entry register MVI C,WRCHR JMP BDOS ; Call CONOUT via the BDOS ;..... ; ; ; Print the user number of the directory in decimal ; TYPUSR: LDA NEWUSR CPI 10 ; If user no. < 10, skip tens digit JC DUX PUSH B MVI C,'0'-1 ; DUY: INR C ; Get tens digit SUI 10 JNC DUY ; Loop until we've gone too far ADI 10 MOV B,A ; Save units digit MOV A,C ; Print tens digit CALL TYPE MOV A,B ; Get units back POP B ; DUX: ADI '0' JMP TYPE ;..... ; ; VERERR: LXI D,VERBAD ; Abort, bum CP/M version ; VERER1: CALL PRINT JMP EXIT1 ;..... ; ; ; WBTRAP is where the ZRDOS returns control on warm boot (error) ; WBTRAP: LXI H,DSKERR ; Return here after reseeting the trap PUSH H ; Save DSKERR on stack JMP RESTRAP ;..... ; ; ; ZRDOS Error Trap and System Call exits to CPM20 ; ZRD: CALL SETTRAP ; Set the warm boot trap CALL BDOS ; Do what we're told CALL RESTRAP ; Reset the trap JMP CPM20 ; Error free exit ;..... ; ; ;----------------------------------------------------------------------- ; ; END OF PROGRAM CODE ; ;----------------------------------------------------------------------- ; ; SIGNON: DB CR,LF,'SuperFILE ' DB VER/10+'0','.',VER MOD 10+'0',CR,LF,0 ; IF CKSYS OR CKWHL SIGN1: DB 'includes $SYS files',CR,LF,0 ENDIF ; CKSYS OR CKWHL ; SIGN2: IF CKLBR DB '(also searches ' ENDIF ; CKLBR ; IF NOT CKLBR DB '(does not search ' ENDIF ; NOT CKLBR ; DB 'lbr / arc) - ^X to abort',CR,LF,CR,LF,0 ;..... ; ; HELP: DB CR,LF,' SuperFILE v' DB VER/10+'0','.',VER MOD 10+'0',CR,LF DB CR,LF,' A FILE search program ',0 ; IF CKSYS OR CKWHL HELP1: DB 'that includes $SYS files',CR,LF DB ' ',0 ENDIF ; CKSYS ; HELP2: IF CKLBR DB '(also searches ' ENDIF ; CKLBR ; IF NOT CKLBR DB '(does not search ' ENDIF ; NOT CKLBR ; DB 'lbr / arc) - ^X to abort',CR,LF,CR,LF ; IF CKLBR DB ' (Use FILE.COM to skip lbr/arc checks)' ENDIF ; CKLBR ; IF NOT CKLBR DB ' (Use SFILE.COM to include lbr/arc checks)' ENDIF ; NOT CKLBR ; DB CR,LF,CR,LF,CR,LF DB ' Examples to search all drive and user areas:',CR,LF DB CR,LF,' A>' ; IF CKLBR DB 'S' ENDIF ; CKLBR ; DB 'FILE *.AQM',CR,LF,' A>' ; IF CKLBR DB 'S' ENDIF ; CKLBR ; DB 'FILE IMP*.*',CR,LF DB CR,LF,' Examples to search a single drive and all ' DB 'user areas:',CR,LF DB CR,LF,' A>' ; IF CKLBR DB 'S' ENDIF ; CKLBR ; DB 'FILE B:BYE5??.*',CR,LF,' A>' ; IF CKLBR DB 'S' ENDIF ; CKLBR ; DB 'FILE D:KMD*.*' DB CR,LF,CR,LF,CR,LF,CR,LF,0 IF NAMDIR PTRTBL: DW ATABLE ; Location of name table for drive A DW BTABLE ; Location of name table for drive B DW CTABLE ; Location of name table for drive C DW DTABLE ; Location of name table for drive D DW ETABLE ; Location of name table for drive E DW FTABLE ; Location of name table for drive F DW GTABLE ; Location of name table for drive G DW HTABLE ; Location of name table for drive H DW ITABLE ; Location of name table for drive I DW JTABLE ; Location of name table for drive J DW KTABLE ; Location of name table for drive K DW LTABLE ; Location of name table for drive L DW MTABLE ; Location of name table for drive M ; ; Table of area names for each drive. Each entry must be 8 characters ; long. Number of entries must be equal to or greater than the ; maximum user area shown in HIDRV: ; ATABLE: DB 'FLOPPY ' ; Eight characters/entry ; Users only access to A1: BTABLE: CTABLE: DTABLE: ETABLE: FTABLE: GTABLE: HTABLE: ITABLE: JTABLE: KTABLE: LTABLE: MTABLE: DB 'BASE ' DB 'ASSEM ' DB 'WSTAR ' DB 'COMM ' DB 'EMPTY ' DB 'BASIC ' DB 'SCALC ' DB 'DBASE2 ' DB 'RBBS ' DB 'MEXPLUS ' DB 'GAMES ' DB 'NEWSOFT ' DB ' ' DB 'ZCPR3 ' DB 'DEVELOP ' DB 'XFER ' ; Users access to M15: ENDIF ; NAMDIR ;..... ; ; ; Message area ; DRVMSG: DB '+++ Drive',0 ERRMS1: DB ' ' ERRMS2: DB 'Error',0 INLBF: DB ' in ' LBRTYP: DB 'LBR' PROCES: DB CR,'Checking ' IF NAMDIR AREA: DB ' ',0 ENDIF ; NAMDIR PROC1: DB ' ',0 PROC2: DB ': ',0 USRMSG: DB 'User #',0 CLEAR: DB CR,' ' IF NAMDIR TUMSG: DB CR,LF,' Finished after area ',0 ENDIF ; NAMDIR IF NOT NAMDIR TUMSG: DB CR,LF,' Finished after d/u = ',0 ENDIF ; NOT NAMDIR TLMSG: DB CR,LF,' Lbr / Arc searched = ',0 TMMSG: DB CR,LF,' Files that matched = ',0 TCMSG: DB CR,LF,' # of files checked = ',0 VERBAD: DB '+++ Needs CP/M 2.0 or Newer to RUN',0 ; ; ;======================================================================= ; ; UNINITIALIZED DATA AREA ; ;======================================================================= ; BASUSR: DB 0 ; Dupe of original dir. user # to search BLKMSK: DB 0 ; Records/blk - 1 BLKSHF: DB 0 ; # shifts to mult by sec/blk DOPFLG: DB 0 ; FNDFLG: DB 0 ; File found flag HITRAP: DB 0 ; Highlit trap (previously typed char) LSTUSR: DB 0 ; To show last user area checked LZFLG: DB 0 ; 0 when printing leading zeros MAXUSR: DB 0 ; Max user # for drive from lookup table NEWUSR: DB 0 ; User # selected by "$U" option OLDDSK: DB 0 ; Holder for currently logged-in drive OLDUSR: DB 0 ; Contains user number upon invocation SUPSPC: DB 0 ; Leading space flag for decimal routine VERFLG: DB 0 ; CP/M version number (0=pre-CP/M 2) ZRDFLG: DB 0 ; ZRDOS version ; BLKMAX: DW 0 ; Highest block # on drive COUNT: DW 0 ; Entry count DIRMAX: DW 0 ; Highest file # in directory GAP: DW 0 ; Sort routine storage I: DW 0 ; Sort routine storage J: DW 0 ; Sort routine storage JG: DW 0 ; Sort routine storage LCOUNT: DW 0 LLENLOC:DW 0 ; Running total of .LBR length NEXTL: DW 0 NEXTT: DW 0 ; Next table entry SCOUNT: DW 0 ; # to sort SLFILE: DW 0 TBLOC: DW 0 ; Pointer to start of name table TEMP: DW 0 ; Save dir entry TFILES: DW 0 TLIBRA: DW 0 TMATCH: DW 0 VECTBL: DW DSKERR ; BDOS sector error intercept vector DW DSKERR ; BDOS select error intercept vector ; ISARC DS 1 ; Current file type flag for .arc GETABL DS 1 ANAME: DS 13 ; Name string ASIZE: DS 14 ; Compressed bytes ARCFIL DS 16 ; Dummy archive fcb ; SEARN: DS 11 ; Holding area for search name LBRFCB: DS 36 LBBUF: DS 80H ; DS 100 ; Stack area STACK: DS 2 ; Save old stack pointer here ; ORDER EQU $ ; Order table starts here ; ; END