; ; WHEREIS ; ; Horn Engineering Associates ; 1714 Patricia Lane ; Garland, Texas 75042 ; ; 11/20/85 ; ; ---------------------------------------- ; ; WHEREIS basically performs the same function as FILEFIND, but ; with some nice added features that are discussed in WISxxx.DOC ; It's worth noting that the WHEREIS code is in no way related to ; the operating code of FILEFIND, but is instead an original ; program. ; ; WHEREIS searches all of the available drives/user-areas online ; (using the ZCPR maxdrive and maxuser bytes or, optionally, ; hardcoded values as guides) for a specified file. If a match is ; found, the filename(s) are displayed along with its/their ; location(s). ; ; If you have any questions or suggestions, please call B-RCP/M at ; (214) 278-3870 and use the CP/M NOTE command to leave me a ; message, or write: ; ; Bob Horn ; c/o Horn Engineering Associates ; 1714 Patricia Lane ; Garland, Texas 75042 ; ; TRUE EQU 0FFH FALSE EQU NOT TRUE ; ; CP/M Equates ; BOOT EQU 0 ;org zero CP/M BDOS EQU BOOT+5 ;bdos entry DEFDMA EQU 80H ;normal default DMA address DFCB EQU 5CH TPA EQU BOOT+100H ;ORG address CONIN EQU 1 ;BDOS console input function CONOUT EQU 2 ;console output function DIRCON EQU 6 PBUF EQU 9 ;print buffer function RDCON EQU 10 ;read console buffer function CONSTAT EQU 11 ;console status function RESDISK EQU 13 ;reset disk system function SELDISK EQU 14 ;select default disk function OPENF EQU 15 ;open file function CLOSEF EQU 16 ;close file function SRCHF EQU 17 ;search for first dir file function SRCHN EQU 18 ;search for next file function DELF EQU 19 ;delete file function READF EQU 20 ;read file function WRITEF EQU 21 ;write file function MAKEF EQU 22 ;make file function GETDISK EQU 25 ;get default disk function SETDMA EQU 26 ;set DMA address function SETATTR EQU 30 ;set file attributes USRSTAT EQU 32 ;get/set user number ; ; Misc Equates ; BELL EQU 07H ;bell character BS EQU 08H ;backspace character LF EQU 0AH ;line feed CR EQU 0DH ;carriage return BLANK EQU 20H ;space character ; ; Program Equates ; VERS EQU 1 ;version REV EQU 05 ;revision # ;if you make any changes, please ;change these accordingly ; ; NOSYS EQU TRUE ;true, don't display system files ZCPR EQU FALSE ;true if using ZCPR for MXDRV/USR ; ;if false, see IF NOT ZCPR area below ZCPR3 EQU FALSE ;if true, adjust ZCPR3 MAXD and MAXU ; ;.... as required SHOWLBL EQU TRUE ;true to diaplay -*.* labels as well ;...as du: MAPDU EQU TRUE ;true to use du map ; ; NOTE: The reason for the MAPDU EQUate is that the program ; uses two Z-80 op-codes to decipher the drive map. If ; you're not using a Z-80 or compatible (NSC-800, etc.) ; CPU, set this equate to FALSE. In addition, if this ; equate is true, a macro assembler (i.e. MAC) must be ; used to assemble this program. ; IF MAPDU ; ; Initialize Z-80 macros used ; RLAR MACRO ?R DB 0CBH, 10H + ?R ENDM ; SLAR MACRO ?R DB 0CBH, 20H + ?R ENDM ; ENDIF ; IF ZCPR MXDRV EQU 0FA2CH ;set to location of ZCPR MAXDRV MXUSR EQU 0FA2DH ; " MAXUSER ;if ZCPR3, set to Z3ENV locations ENDIF ; ORG TPA ;program runs here ; ; Main program ; START: JMP START1 ;jump over fixed data ; IF MAPDU AMAP: DW 0FFFFH ;usermap for drive A: BMAP: DW 0FFFFH ; B: CMAP: DW 0FFFFH ; C: DMAP: DW 0FFFFH ; D: EMAP: DW 0FFFFH ; E: FMAP: DW 0FFFFH ; F: GMAP: DW 0FFFFH ; G: HMAP: DW 0FFFFH ; H: IMAP: DW 0FFFFH ; I: JMAP: DW 0FFFFH ; J: KMAP: DW 0FFFFH ; K: LMAP: DW 0FFFFH ; L: MMAP: DW 0FFFFH ; M: NMAP: DW 0FFFFH ; N: OMAP: DW 0FFFFH ; O: PMAP: DW 0FFFFH ; P: ENDIF ; IF NOT ZCPR MXDRV: DB 1 ;max drive to search (A:=0, B:=1, etc.) MXUSR: DB 7 ;max user to search +1 ENDIF ; START1: LXI H,0 ;find CP/M stack pointer DAD SP ;/ SHLD OLDSP ;save old stack pointer LXI SP,STACK ;set up our local stack ; LXI H,SIGNON ;point to signon message CALL PBA ;and show it ; LDA DFCB+1 ;see if anything on the command line CPI ' ' ;blank? JZ ERROR ;then present instructions ; LXI H,DFCB+1 ;don't allow whereis *.* MVI B,0 ;wildcard (?) count MVI C,11 ;# of bytes in filename CLOOP: MOV A,C ;see if we're done ORA A ;/ JZ CLEND ;yes, see if legal filename DCR C ;bump down byte count MOV A,M ;get filename byte INX H ;increment pointer CPI '?' ;is it a wildcard? JNZ CLOOP ;no, look at the next byte INR B ;yes, increment wildcard count JMP CLOOP ;...and check the next byte CLEND: MOV A,B ;get wildcard count in A CPI 11 ;was filename *.*? JZ WCERR ;yes, error out ; ; MVI C,GETDISK ;get the default drive CALL BDOS ;/ STA DEFDRV ;save it ; MVI C,USRSTAT ;get the default user MVI E,0FFH ; / CALL BDOS ;/ STA DEFUSR ;save it ; ; Here we set up the DMA and initialize some values ; LXI D,DEFDMA ;set the CP/M DMA address MVI C,SETDMA ; / CALL BDOS ;/ ; ; Check next drive against map/MAXDR, if OK, then log onto it ; else try the next higher drive... ; ; (On the first time around, current drive and user area are negative) ; NDRIVE: LDA CURDRV ;get current drive MOV B,A ;to B for CMP LDA MXDRV ;get max drive ; IF ZCPR3 DCR A ;Adjust ZCPR3 value ENDIF ; CMP B ;same? JZ EXIT ;if so, we're done MOV A,B ;if not, get CURDRV back in A INR A ;...bump up one STA CURDRV ;...and save it ; IF MAPDU ; ; Now, check drive to be logged against drive map ; ADD A ;multiply drive x2 MVI D,0 MOV E,A ;put in DE LXI H,AMAP ;point to DU map DAD D ;point to user map MOV A,M ;zero? INX H ; / MOV B,M ; / ORA B ;/ JZ NDRIVE ;...then go to next drive ; ENDIF ; LDA CURDRV ;get current drive MOV E,A ;log onto the next drive MVI C,SELDISK ; / CALL BDOS ;/ MVI A,-1 ;reset user area count STA CURUSR ;/ ; ; Check next user-area against map and MAXUSR, if user OK, ; then log into said area else try the next higher area... ; NUSER: LDA CURUSR ;get the current user MOV B,A ;to B for CMP LDA MXUSR ;and the max user ; IF ZCPR3 INR A ;Adjust ZCPR3 value ENDIF ; INR B ;bump the current user CMP B ;same as (MXUSR)? JZ NDRIVE ;if so, go to the next drive MOV A,B ;and if not, store new current user STA CURUSR ;/ ; IF MAPDU ; ; Check new user against DU map ; LDA CURDRV ;get current drive CPI 0FFH ;negative? ADD A ;x2 MVI D,0 ;into DE MOV E,A ;/ LXI H,AMAP ;point to du map DAD D ;point to user map for cur drive MOV E,M ;move user map to DE INX H ; / MOV D,M ;/ XCHG ;and finally to HL LDA CURUSR ;get current user CALL CMPVEC ;ok user? JNZ NUSER ;no, next... ; ENDIF ; LDA CURUSR ;get new user MVI C,USRSTAT ;and log it MOV E,A ; / CALL BDOS ;/ ; JMP LFORF ;look for first file on new du: ; ; Here we set up the DMA and initialize some values ; LXI D,DEFDMA ;set the CP/M DMA address MVI C,SETDMA ; / CALL BDOS ;/ ; ; Now start the directory search. ; LFORF: CALL ZFCB ;zero the FCB ; IF SHOWLBL LXI B,11 ;11 char in filename LXI H,LFCB ;the wildcard label filename LXI D,FCB+1 ;move the filename in CALL MOVE ;/ ; LXI D,FCB ;find first match MVI C,SRCHF ; / CALL BDOS ;/ INR A ;found match? JNZ LFORF1 ;yes, handle accordingly LXI B,9 ;no, fill section data area with spaces LXI H,SFILL ; / LXI D,LBLMSG ; / CALL MOVE ;/ JMP LFORF2 ;continue ; LFORF1: DCR A ;set A back to where it was LXI H,DEFDMA ;point to default DMA CALL FINDFN ;find the filename in the DMA INX H ;point past drive INX H ;and "-" LXI B,7 ;store it LXI D,LBLMSG+1 ; / CALL MOVE ;/ MVI A,'(' ;and put parentheses in the message to STA LBLMSG ;...make it look good MVI A,')' ; / STA LBLMSG+8 ;/ ; ENDIF ;SHOWLBL ; LFORF2: MVI A,CR ;go to beginning of line CALL PCHAR ;/ LXI H,SRCSTR ;print "Searching drive" CALL PBA ;/ LDA CURDRV ;get current du:, convert to ASCII ADI 'A' ;and print it CALL PCHAR ; / LDA CURUSR ; / CALL PASC ; / MVI A,' ' ; / CALL PCHAR ;/ ; IF SHOWLBL LDA CURUSR ;get current user-area CPI 10 ;less than 10? JNC LFORF3 ;no, go ahead MVI A,' ' ;yes, print extra space to pad things CALL PCHAR ;...out LFORF3: LXI H,LBLMSG ;print the section name CALL PBA ;/ ENDIF ; CALL ZFCB ;zero the FCB LXI B,11 ;11 char in file name LXI H,DFCB+1 ;the wild card file name LXI D,FCB+1 ;point to FCB file name space CALL MOVE ;move the file name in ; LXI D,FCB ;find first match MVI C,SRCHF ; / CALL BDOS ;/ INR A ;returns 0ffh if not found JZ NUSER ;None there DCR A ;set A back to normal LXI H,DEFDMA ;point to DMA buffer CALL FINDFN ;find the file name in the DMA space ; CALL PRINTFN ;print the filename with pertinent data ; LFORFL: CALL ZFCB ;zero the FCB LXI B,11 ;11 char in file name LXI H,DFCB+1 ;the wild card file name LXI D,FCB+1 ;point to FCB file name space CALL MOVE ;move the file name in ; LXI D,FCB ;find next match MVI C,SRCHN ; / CALL BDOS ;/ INR A ;returns 0ffh if not found JZ NUSER ;none there, next drive or user-area DCR A ;set A back to normal LXI H,DEFDMA ;point to DMA buffer CALL FINDFN ;find the file name in the DMA space ; CALL PRINTFN ;print the filename with pertinent data ; JMP LFORFL ;look for another match ; ; EXIT: LDA FFLAG ;at least one match? ORA A ;/ JNZ EXIT0 ;yes, don't say "file not found" LXI H,FNFMSG ;no, print "not found" and exit CALL PBA ; / JMP EXIT1 ;/ ; EXIT0: LXI H,CLRSTR ;clear the current line CALL PBA ;/ CALL CRLF ;new line ; EXIT1: LDA DEFUSR ;get default user area back MOV E,A ;set it MVI C,USRSTAT ; / CALL BDOS ;/ ; LDA DEFDRV ;get default drive back MOV E,A ;set it MVI C,SELDISK ; / CALL BDOS ;/ ; LHLD OLDSP ;recover CP/M SP SPHL ;set it RET ;and exit quietly to CP/M ; ABORT: MVI C,PBUF ;here on abort/BDOS print string LXI D,AMSG ;print abort message CALL BDOS ;/ JMP EXIT1 ;exit to system ; ERROR: LXI H,ERRMSG ;print instructions CALL PBA ;/ JMP EXIT1 ;exit to system ; WCERR: LXI H,WCEMSG ;print "too many wildcards" CALL PBA ;/ JMP EXIT1 ;exit to system ; ;************************ ;*** CONSOLE MESSAGES *** ;************************ ; SIGNON: DB CR,LF,'WHEREIS v',VERS+'0','.',(REV/10)+'0',(REV MOD 10)+'0' DB ', 1986' DB CR,LF,'from Horn Engineering Associates',CR,LF,LF DB 'Ctrl-C aborts, Ctrl-S pauses...',CR,LF,LF,'$' SRCSTR: DB 'Searching $' LBLMSG: DS 9 DB '$' SFILL: DB ' ' CLRSTR: DB CR,' ',CR,'$' AMSG: DB CR,LF,LF,'++ Aborted ++',CR,LF,'$' FNFMSG: DB CR,'File(s) not found... ',CR,LF,LF,'$' ERRMSG: DB 'Proper syntax is:',CR,LF,LF DB 'WHEREIS ',CR,LF,LF DB 'where is any valid CP/M file name (wildcards' DB CR,LF,'* and ? are OK.)',CR,LF,LF,'$' WCEMSG: DB 'Too many wildcards...',CR,LF,LF,'$' ; ;************************************** ;*** THE PRIVATE FILE CONTROL BLOCK *** ;************************************** ; FCB: FCB$DISK: DB 0 ;preset default drive FCB$NAME: DS 8 ;file name FCB$TYP DS 3 ;file type FCB$EXTENT: DB 0 ;preset extent FCB$RESV: DB 0,0 ;reserved by CP/M FCB$RECUSED: DB 0 ;records used FCB$ABUSED: DB 0,0,0,0,0,0,0,0 ;assigned blocks DB 0,0,0,0,0,0,0,0 FCB$SEQREC: DB 0 ;sequential record number FCB$RANREC: DW 0 ;random record number FCB$RANRECO: DB 0 ;record overflow ; LFCB: DB '-???????' ;label filename DB '???' ; " filetype ; ;******************* ;*** SUBROUTINES *** ;******************* ; ; PRINTFN - Presents all pertinent section data ; PRINTFN: INX H ;bump past drive indicator PUSH H ;save it for later ; IF NOSYS LXI D,9 ;point to SYS flag byte DAD D ;/ MOV A,M ;is it set? ANI 128 ;/ JZ PCON ;no, go ahead POP H ;yes, clear stack RET ;...and go home ENDIF ; PCON: MVI A,0FFH ;set FFLAG so we won't get STA FFLAG ;..."file not found" ; MVI A,CR ;cursor to beginning of line CALL PCHAR ;/ ; IF SHOWLBL ; ; Ok, now, where is the section? ; LDA LBLMSG ;is there a section name? CPI '(' ; / JZ PCON1 ;yes, print it out CPI '[' ;"[" is ok too JZ PCON1 ;/ JMP PCON2 ;no, don't bother with it ; PCON1: MVI A,'[' ;enclose section name in brackets STA LBLMSG ; / MVI A,']' ; / STA LBLMSG+8 ;/ LXI H,LBLMSG ;print it CALL PBA ;/ MVI A,' ' ;...and two spaces CALL PCHAR ; / CALL PCHAR ;/ ; ENDIF ; PCON2: LDA CURDRV ;get current drive ; ADI 'A' ;make drive ASCII CALL PCHAR ;print it LDA CURUSR ;get current user CALL PASC ;make # ASCII ; ; ; Now, print the filename ; POP H ;get old H back PUSH H ;save it again MVI C,8 ;# of characters to print CALL PSTRING ;do it MVI A,'.' ;print the period delimeter CALL PCHAR ;/ POP H ;get H back for the last time LXI D,8 ;point to extension DAD D ;/ MVI C,3 ;print it CALL PSTRING ;/ CALL CRLF ;new line ; RET ;to caller ; ; ZFCB - Zero the 36 bytes in the designated FCB ; ZFCB: MVI C,36 ;# of bytes in FCB LXI H,FCB ;point to FCB ZLOOP: MVI M,0 ;enter a zero INX H ;bump pointer DCR C ;bump down counter JNZ ZLOOP ;loop for more RET ; ; FINDFN - Locates directory file name in DMA after directory ; search. Returns pointer in HL. Entry with directory code in A. ; FINDFN: ADD A ;*2 ADD A ;*4 ADD A ;*8 ADD A ;*16 ADD A ;*32 MOV E,A ;offset to DE MVI D,0 ;/ DAD D ;add to HL RET ; ; MOVE - Moves the number of characters in BC from (HL) to (DE) ; MOVE: MOV A,M ;get char from (HL) STAX D ;put in (DE) INX H ;point to next character/position INX D ;/ DCX B ;decrement counter MOV A,C ;get LS count byte ORA B ;both B & C zero? JNZ MOVE ;loop til done RET ; ; PSTRING - Prints string pointed to by HL. ; Number of characters to print in C ; PSTRING: PUSH H ;save string pointer PUSH B ;save count MOV A,M ;get a character CALL PCHAR ;print it POP B ;restore count POP H ;restore pointer INX H ;bump it DCR C ;done? JNZ PSTRING ;if not RET ; ; PBA - Identical to BDOS PBUF, but checks for ctrl-c abort ; PBA: PUSH H ;save string pointer MOV A,M ;get a character CPI '$' ;end of string? JZ PBEND ;yes, end routine CALL PCHAR ;no, print it POP H ;get string pointer back INX H ;next character JMP PBA ;/ PBEND: POP H ;restore stack RET ; ; ; CRLF - Puts a CR and LF out to console ; CRLF: MVI A,CR ;print CR CALL PCHAR ;/ MVI A,LF ;print LF CALL PCHAR ;/ RET ; ; PCHAR - Prints the character in A ; PCHAR: PUSH PSW ;save all registers PUSH B ; / PUSH D ; / PUSH H ;/ ; MVI C,DIRCON ;BDOS direct console I/O MVI E,0FFH ;input CALL BDOS ;do it CPI 3 ;CTRL-C returned? JZ ABORT ;yes, abort CPI 'S'-'@' ;CTRL-S returned? CZ PAUSE ;yes, pause ; POP H ;restore registers POP B ; / POP D ; / POP PSW ;/ ; MOV E,A ;to E for BDOS MVI C,DIRCON ;direct console I/O output CALL BDOS ;do it RET ; ; PASC - Unpacks two ascii decimal digits from value in A ; displays them on the console with no leading 0's. ; PASC: MVI C,0 ;initialize quotient PASC1: SUI 10 ;repeatedly subtract 10 JC PASC2 ;if underflow INR C ;else increment the quotient JMP PASC1 ;and subtract again ; PASC2: ADI 10 ;Correct the underflow PUSH PSW ;save the remainder MOV A,C ;get the quotient ORA A ;set flags JZ ONENUM ;only one number to display ADI 030H ;adjust to ascii CALL PCHAR ;print it POP PSW ;get remainder ADI 030H ;make ascii CALL PCHAR ;print it ; MVI A,':' ;print a ":" after the drive/user CALL PCHAR ;/ ; RET ; ONENUM: POP PSW ;get the # ADI 030H ;make ASCII CALL PCHAR ;print it MVI A,':' ;and a colon CALL PCHAR ;/ ; RET ;go home ; PAUSE: MVI C,DIRCON ;wait for a key to be pressed, then MVI E,0FFH ;...return CALL BDOS ; / ORA A ; / JZ PAUSE ; / RET ;/ ; IF MAPDU ; ; ; CMPVEC - compare drive or user number contained in least ; significant nibble of ac to 16 bit vector contained ; in hl. Sets flags upon return, z = equal, nz = not equal ; CMPVEC: PUSH D ;save out working vector register ANI 0FH ;mask for lo nibble INR A ;add 1 for decrement LXI D,1 ;set up for drive A:/user 0 CVLP1: DCR A ;start decrementing JZ CVCMP ;if 0, do compare SLAR E ;(cy) <- E <- 0 JNC CVLP1 ;if no carry, keep working with lo vec byte CVLP2: RLAR D ;(cy) <- D <- (cy) DCR A ;now work with hi nibble JNZ CVLP2 ;until ac = 0 CVCMP: MOV A,L ;now compare de -> hl ANA E ;first isolate bit to test XRA E ;now test it JNZ CVRET ;if nz, that's all MOV A,H ;else try hi bytes ANA D ;same as above XRA D ; CVRET: POP D ;restore the scratch reg. RET ;return with flags set ; ENDIF ; ;************************ ;*** UNITIALIZED AREA *** ;************************ ; DEFUSR: DB 0 ;storage for default user area DEFDRV: DB 0 ;default drive CURUSR: DB -1 ;current user area CURDRV: DB -1 ;current drive ; FFLAG: DB 0 ;flag for file found ; OLDSP: DW 0 DS 64 ;our private stack area STACK: EQU $ ; END