
; FILE.ASM
;
; v14 - 01 JUNE 83 - IRV HOFF
;
; ORIGINALLY WRITTEN BY R. RODMAN.  RENAMED TO 'FILEFIND' BY ANOTHER
; PERSON IN APRIL 1981.  NOW RESTORED TO ORIGINAL INTENDED NAME.
;
; THIS PROGRAM WILL SEARCH ALL USER AREAS OF ALL DRIVES (CAN BE LIMITED
; BY CHANGING THE 'MAXUSR' EQUATE) FOR ANY FILES MATCHING THE REQUEST ON
; THE COMMAND LINE.  IT THEN DISPLAYS THOSE FILES.  ALLOWABLE USER AREAS
; FOR CP/M ARE 0-15.
;
;
; EXAMPLE:  FILE *.COM  LISTS ALL .COM FILES ON ALL DRIVES AND ALL AREAS
;
;
; THIS PROGRAM MAKES A DIRECT CALL TO THE 'SELDSK' ROUTINE OF THE BIOS
; TO DETERMINE A DRIVE'S EXISTENCE WITHOUT CAUSING A BDOS ERROR.
;
; NOTE:	 THIS PROGRAM ASSUMES THAT ANY BIOS 'ILLEGAL DRIVE SELECT' TRAPS
;	 WILL CAUSE THE SYSTEM TO EXECUTE A WARM-BOOT BY JUMPING TO AD-
;	 DRESS 0.  THIS OCCURS ON THE FIRST NON-EXISTANT DRIVE IT TRIES
;	 TO ACESS WHILE ATTEMPTING TO CHECK 0-15 DRIVES.  IF A SELECT
;	 ERROR BYPASSES THE WARM-BOOT JUMP AT ADDRESS 0, THEN  THE TRAP
;	 IN THIS PROGRAM WILL NOT WORK.  IN THAT CASE, SET 'DRVTYPE' TO
;	 FALSE AND 'MAXDRV' TO THE NUMBER OF DRIVES YOU HAVE.
;
;
; PLEASE RETURN ANY UPDATES TO TECHNICAL CBBS DEARBORN MI (313) 846-6127
; SO THE FILE WILL BE AVAILABLE TO ALL.
;
;
;=======================================================================
;
;
; 06/01/83  ADDED "searching..." TO SHOW THE REASON FOR NO ACTIVITY ON
;	    LONGER SEARCHES.  REVISED THE ONE OF THE EXIT ROUTINES.
;	    OTHER MINOR CHANGES.	-Irv Hoff
;        
; 02/13/83  NOW PRINTS A NORMAL DISPLAY FOR DRIVE/USER AREA WHILE KEEP-
;	    ING NORMAL COLUMN WIDTH FOR JUSTIFICATION.  SEVERAL OTHER
;           MINOR CHANGES.  ALWAYS STARTS AT FIRST DISK, USER 0, REGARD-
;	    LESS OF THE CURRENT DISK OR USER NUMBER.  IT THEN RETURNS TO
;	    THE PRESENT DRIVE AND USER AREA.
;					- Irv Hoff
;
; 02/02/82  ENABLED PROGRAM TO LOOK AT A SPECIFIC NUMBER OF DRIVES IN
;	    THE EVENT THE BIOS 'ILLEGAL DRIVE SELECT' IS NOT INCLUDED.
;					- Larry Clive
;
; 08/02/81  CLEANED UP FILE AND REMOVED UNNECESSARY CODE.  THANKS TO TOM
;	    AND SHAWN FOR ADDING SOME MORE GOODIES.
;					- Dave Hardy
;
; 07/31/81  MODIFIED 'AVAIL' ROUTINE TO ABORT ONLY ON CTL-C FROM THE
;	    CONSOLE.  CLEANED UP THE FILE, RESTORED ORIGINAL AUTHOR'S
;	    NAME TO THE HEADING.  ADDED TUTORIAL TO BE PRINTED IF FILE-
;	    NAME (FCB) FIELD (FN.FT TAIL OF THE COMMAND LINE) IS BLANK
;	    (OMITTED BY THE INEXPERIENCED USER).  SUBSTITUTED IN-LINE
;	    PRINT ROUTINE WHERE APPROPRIATE FOR ALL PRINTED MESSAGES.
;	    PRINTS MESSAGE ON EXIT IF NO FILES WERE FOUND (MATCHED).
;					- Thomas V. Churbuck
;
; 07/30/81  MODIFIED 'AVAIL' ROUTINE TO ABORT PROGRAM IF ANY CHARACTER
;	    IS TYPED FROM THE CONSOLE.  MODIFED USER NUMBER ROUTINE TO
;	    INCLUDE LEADING 0 WHEN PRINTING USER #'S 0-9 TO LINE UP
;	    PRINTOUT.			- Shawn Everson
;
;
;=======================================================================
;
;
;  DEFINE TRUE AND FALSE
;
YES:	  EQU	0FFH
NO:	  EQU	0
;.....
;
;
; SET THE FOLLOWING AS DESIRED:
;
SHOWSYS:  EQU	YES		;'YES' IF WANT TO SHOW SYSTEM FILES
DRVTYP:	  EQU	YES		;'YES' IF BIOS HAS 'ILLEGAL DRIVE SELECT'
				;TRAP.  SET 'NO' IF NO TRAP IN BIOS,
				;THEN SET 'MAXDRV' TO NUMBER OF DRIVES TO
				;SEARCH THROUGH FOR THE REQUESTED FILE.
MAXDRV:	  EQU	2		;NUMBER OF DRIVES TO SEARCH THROUGH
MAXCOL:	  EQU	4		;MAX NUMBER OF COLUMNS DESIRED IN DISPLAY
MAXUSR:	  EQU	15		;MAX USER # TO BE CHECKED (0-15 POSSIBLE)
;.....
;
;
;  DEFINE SOME MISCELLANEOUS VALUES:
;
BASE:	  EQU	0		;SET TO BASE ADDRESS OF YOUR CP/M
BDOS:	  EQU	BASE+5		;CP/M BDOS ENTRY POINT
CR:	  EQU	0DH		;ASCII RETURN
FCB:	  EQU	BASE+5CH	;CP/M FILE CONTROL BLOCK ADDRESS
LF:	  EQU	0AH		;ASCII LINEFEED
TBUF:	  EQU	BASE+80H	;DMA BUFFER ADDRESS
;.....
;
;
;  DEFINE SOME BDOS FUNCTIONS:
;
CONIN:	  EQU	1		;CONSOLE INPUT FUNCTION
CONOUT:	  EQU	2		;CONSOLE OUTPUT FUNCTION
PRINT:	  EQU	9		;PRINT STRING AT CONSOLE FUNCTION
CONSTAT:  EQU	11		;GET CONSOLE STATUS FUNCTION
RTNVER:	  EQU	12		;RETURN VERSION NUMBER FUNCTION
SRCHFST:  EQU	17		;SEARCH FOR FIRST FUNCTION
SRCHNXT:  EQU	18		;SEARCH FOR NEXT FUNCTION
SETIOB:	  EQU	24		;SET I/O BYTE
SETDMA:	  EQU	26		;SET DMA ADDRESS FUNCTION
SETUSR:	  EQU	32		;SET/GET USER CODE FUNCTION
;.....
;
;
	  ORG	BASE+100H
;
;
	  LXI	H,0		;SET 'HL' TO ZERO
	  DAD	SP		;GET STACK POINTER INTO 'HL'
	  SHLD	STACK		;SAVE FOR EXIT TO 'CCP' STACK
	  LXI	SP,STACK	;SET UP LOCAL STACK
	  CALL	ILPRT		;PRINT SIGN-ON MESSAGE
	  DB	CR,LF,'FILE v14 - CTL-X to abort',CR,LF,0
	  LDA	FCB+1		;CHECK FOR FILENAME ON COMMAND LINE
	  CPI	' '
	  JZ	NONAME
	  CALL	ILPRT
	  DB	'searching...',0
;
SETUP:	  LDA	0004H		;SAVE USER/DRIVE #
	  STA	UDNUM
	  RRC			;1ST 4 BITS GIVE CURRENT USER #
	  RRC
	  RRC
	  RRC
	  ANI	0FH		;'AND' OFF THE DRIVE BITS
	  STA	CUN		;SAVE CURRENT USER #
	  STA	CTU		;SAVE AS CURRENT TRY #,TOO
	  MOV	B,A
	  MVI	A,MAXUSR
	  CMP	B
	  JC	OUTSIDE
	  XRA	A
	  STA	CTU		;SET CURRENT TRY USER TO 0:
	  STA	ORIGCTU		;SET ORIGINAL 'CTU' TO SAME
	  MVI	A,MAXUSR
	  STA	MAXTEMP		;SET MAXIMUM USER NUMBER TO 'MAXUSR'
;
SBOOT:	  LHLD	0000H+1		;GET WARM-BOOT ADDRESS
	  SHLD	WBOOT		;SAVE WARM-BOOT ADDRESS
	  LXI	D,SETIOB	;GET ADDRESS FOR 'SET I/O BYTE'
	  DAD	D		;INDEX INTO BIOS
	  SHLD	DSKSEL+1	;GET JUMP TO BIOS 'DSKSEL' ROUTINE
;
;
; THE FOLLOWING CODE SETS A TRAP AT THE WARM-BOOT JUMP, SO THAT
; ANY 'ILLEGAL DRIVE SELECT' TRAPS IN THE BIOS WILL BE DEFEATED.
;
	  LXI	H,DONE		;REPLACE WARM-BOOT POINTER WITH TRAP
	  SHLD	1
	  LXI	D,TBUF
	  MVI	C,SETDMA
	  CALL	BDOS		;SET DMA ADDRESS
	  MVI	A,0		;START LOOKING ON 0 DRIVE ("A")
	  STA	TRYDRV		;SET UP TO TRY DRIVE '0' FIRST
;
TRY:	  MOV	C,A		;TRY TO SELECT DRIVE
	  CALL	DSKSEL
	  MOV	A,L
	  ORA	H
	  JZ	DONE		;IF 'HL' IS 0, THEN NO MORE DRIVES
	  LDA	TRYDRV
	  INR	A
	  STA	TRYDRV		;GET READY FOR NEXT DRIVE, TOO
	  STA	FCB		;STORE 1+DRIVE# IN FCB (1=A, 2=B, ETC.)
;
NXTUSR:	  LDA	CTU		;SET USER TO 'CTU' VIA A BDOS CALL
	  MOV	E,A
	  MVI	C,SETUSR
	  CALL	BDOS
;
AVAIL:	  MVI	C,CONSTAT	;CHECK TO SEE IF KEY PRESSED
	  CALL	BDOS
	  ORA	A
	  JZ	NOPRESS		;IF NO KEY PRESSED, THEN CONTINUE
	  MVI	C,CONIN		;IF KEY PRESSED, THEN CHECK FOR ABORT
	  CALL	BDOS
	  CPI	'C'-40H		;IS IT CTL-C?
	  JZ	AVAIL1		;IF NO, THEN CONTINUE
	  CPI	'X'-40H		;IS IT CTL-X?
;
AVAIL1:	  JNZ	NOPRESS		;IF NO, THEN CONTINUE
	  CALL	ILPRT		;IF YES, THEN PRINT ABORT MESSAGE
	  DB	CR,LF,CR,LF,'++ ABORTED ++',0
	  JMP	DONE1
;.....
;
;
NOPRESS:  LXI	D,FCB
	  MVI	C,SRCHFST
	  CALL	BDOS		;CHECK FOR DIRECTORY MATCH WITH 'FCB'
	  CPI	0FFH		;A-REG. HAS 0-3 IF FILE FOUND ELSE 0FFH
	  JZ	NXT		;DO NEXT DRIVE IF NO MORE MATCHES FOUND
	  CALL	SHOFIL		;IF MATCH FOUND, DISPLAY THE FILENAME
;
SNEXT:	  MVI	C,SRCHNXT
	  CALL	BDOS		;CHECK FOR NEXT MATCH WITH FCB
	  CPI	0FFH	
	  JZ	NXT		;NO MORE MATCHES? THEN DO NEXT DRIVE
	  CALL	SHOFIL		;IF MATCH FOUND, DISPLAY THE FILENAME
	  JMP	SNEXT		;CONTINUE UNTIL NO MORE MATCHES FOUND
;
NXT:	  LDA	CTU		;INCREMENT CURRENT TRY USER NUMBER
	  INR	A
	  STA	CTU
	  MOV	B,A
	  LDA	MAXTEMP
	  CMP	B
	  JNC	NXTUSR		;DO NEXT USER NUMBER IF ALL NOT DONE
	  LDA	ORIGCTU		;ELSE RESET USER # AND DO NEXT DRIVE
	  STA	CTU
	  MVI	C,RTNVER
	  CALL	BDOS		;SEE IF CP/M VERSION 1.4 OR 2.X
	  MVI	C,5		;(IF CP/M 1.4, THEN BIOS MUST RETURN AN
	  ORA	A		;ERROR IF BAD DRIVE #, ELSE WON'T WORK)
	  JZ	FOUR		;IF 1.4 THEN FOUR DRIVES MAXIMUM
;
	   IF	DRVTYP
	  MVI	C,16+1		;OTHERWISE 16 DRIVES MAXIMUM UNLESS
	   ENDIF		;NO BIOS TRAP.
;
	   IF	NOT DRVTYP	;IF NO TRAP THEN MAX DRIVES NUMBER IS
	  MVI	C,MAXDRV	;IS SET MANUALLY.
	   ENDIF
;
FOUR:	  LDA	TRYDRV
	  CMP	C
	  JC	TRY		;CONTINUE UNTIL ALL DRIVES CHECKED...
;
;
; ALL DONE NOW, RETURN TO CP/M
;
DONE:	  LDA	MFLAG		;SEE IF ANY FILES FOUND
	  ORA   A
	  JNZ	DONE1		;IF YES, THEN DONE, SO EXIT
	  CALL	ILPRT		;IF NO, THEN SAY NONE FOUND FIRST
	  DB	CR,LF,CR,LF,'++ FILE NOT FOUND ++',0
;
DONE1:	  CALL	ILPRT
	  DB	CR,LF,0		;TURN UP A LINE
	  LHLD	WBOOT		;RESTORE WARM-BOOT JUMP
	  SHLD	1
	  LDA	UDNUM		;RESTORE USER/DRIVE NUMBER
	  STA	4
	  ANI	0FH
	  MOV	C,A		;PUT THE DRIVE INTO 'C'
	  CALL	DSKSEL
;
EXIT:	  JMP	0000H		;THEN RETURN TO CP/M VIA WARM REBOOT
;.....
;
;
NONAME:	  CALL	ILPRT		;ELSE, PRINT HELP MESSAGE AND EXIT
	  DB	CR,LF
	  DB	'     You must specify the file(s) you',CR,LF
	  DB	'     want to find.  Wildcards are ok.',CR,LF,LF
	  DB	'     EXAMPLE:  FILE MODEM7.DOC',CR,LF
	  DB	'               FILE MOD*.*',CR,LF
	  DB	'               FILE *.ASM',CR,LF
	  DB	'               FILE *.*',CR,LF,0
;
EXITSPCL: LHLD	STACK		;GET THE ORIGINAL 'CCP' STACK ADDRESS
	  SPHL			;SET STACK POINTER FROM 'HL' ADDRESS
	  RET			;RETURN TO THE 'CCP' STACK
;.....
;
;
OUTSIDE:  LDA	CUN
	  STA	CTU		;SET CURRENT TRY USER TO CURRENT USER #
	  STA	ORIGCTU		;SET ORIGINAL 'CTU' TO SAME
	  STA	MAXTEMP		;SET MAXIMUM USER NUMBER TO CURRENT
	  JMP	SBOOT		;AND CONTINUE...
;
SHOFIL:	  MOV	L,A		;GET FILENAME TO DISPLAY FROM DIRECTORY
	  MVI	H,0		;WHICH CP/M PUTS AT DMA ADDRESS
	  DAD	H		;("A" REGISTER HAS RELATIVE POSITION OF
	  DAD	H		;NAME  WITHIN DIRECTORY RECORD)
	  DAD	H
	  DAD	H
	  DAD	H		;MULTIPLY 'A' BY 32 TO POINT TO START OF
	  LXI	D,TBUF		;FILENAME
	  DAD	D		;NOW POINT TO FILENAME
	  XCHG			;SAVE FILENAME POINTER IN 'DE'
;
	   IF	NOT SHOWSYS	;THEN IGNORE 'SYS' FILES
	  LXI	H,10
	  DAD	D		;POINT TO 'SYS' FILE ATTRIBUTE
	  MOV	A,M
	  ANI	80H		;CHECK FOR 'SYS' TYPE FILE
	  RNZ			;DON'T DISPLAY IF 'SYS' ATTRIBUTE IS SET
	   ENDIF
;
	  LDAX	D		;GET USER NUMBER
	  INX	D
	  PUSH	PSW		;SAVE THE USER NUMBER
	  CPI	9+1		;IS USER NUMBER = 0 THRU 9?
	  JNC	SHOFIL1		;IF NOT, EXIT
	  MVI	A,' '
	  CALL  AOUT		;PRINT THE EXTRA SPACE
;
SHOFIL1:  LDA	TRYDRV		;GET THE DISK DRIVE
	  ADI	'A'-1		;CONVERT BINARY TO ASCII
	  CALL	AOUT		;DISPLAY DRIVE (A-P)
	  POP	PSW		;SAVE THE USER NUMBER
	  CPI	9+1		;0-9 ?
	  JC	USRL		;IF YES, EXIT
;
	  SUI	10		;USER NUMBER = 10 THRU 15
	  PUSH	PSW		;REMAINDER IS <10
	  MVI	A,'1'
	  CALL	AOUT2		;PRINT A LEADING '1'
	  POP	PSW		;GET THE REMAINDER BACK
;
USRL:	  ADI	'0'		;CONVERT FROM BINARY TO ASCII #
	  CALL	AOUT2		;PRINT DIGIT
;
NOUSR:	  MVI	A,':'		;FENCE CHARACTER
	  CALL	AOUT2		;DISPLAY A ':' TO LOOK NICE
;;;	  MVI	A,' '
;;;	  CALL	AOUT2		;SEPARATE IT FROM THE FILE NAME
	  MVI	B,8		;(8 CHARACTERS OR LESS IN FILENAME)
;
PFN:	  LDAX	D		;NOW PRINT THE FILENAME..
	  INX	D
	  CALL	AOUT2		;..ONE CHARACTER AT A TIME
	  DCR	B
	  JNZ	PFN		;CONTINUE FOR ALL 8 CHARACTERS 
	  MVI	A,'.'
	  CALL	AOUT2		;DISPLAY THE '.' BEFORE THE FILETYPE
	  MVI	B,3		;NOW DO THE SAME FOR THE FILETYPE
;
PXT:	  LDAX	D
	  INX	D
	  CALL	AOUT2
	  DCR	B
	  JNZ	PXT
	  LDA	COLUMN		;PRINT MAXCOL COLUMNS ACROSS THE SCREEN
	  DCR	A
	  JZ	DOCRLF
	  STA	COLUMN
	  CALL	TWOSPC		;PRINT TWO SPACES TO MAKE IT NEAT
	  MVI	A,0FFH		;SHOW THAT A FILE WAS FOUND
	  STA	MFLAG		;SUPPRESSES 'NOT FOUND' MESSAGE
	  RET
;.....
;
;
DOCRLF:	  MVI	A,MAXCOL	;RESET COLUMN NUMBER AFTER LAST COLUMN
	  STA	COLUMN
	  MVI	A,CR
	  CALL	AOUT2
	  MVI	A,LF
	  CALL	AOUT2
	  RET
;.....
;
;
TWOSPC:	  MVI	A,' '
	  CALL	AOUT2
	  MVI	A,' '
	  JMP	AOUT2
;
AOUT:	  MOV	B,A		;SAVE THE CHARACTER FOR NOW
	  LDA	FIRST
	  ORA	A
	  JNZ	AOUT1
	  CALL	ILPRT
	  DB	CR,LF,CR,LF,0
	  MVI	A,1
	  STA	FIRST
;
AOUT1:	  MOV	A,B
;
AOUT2:	  PUSH	B		;SEND A CHARACTER TO THE CONSOLE
	  PUSH	D
	  PUSH	H		;SAVE REGISTERS IN CASE BDOS EATS THEM
	  ANI	7FH		;STRIP PARITY BIT
	  MOV	E,A
	  MVI	C,2
	  CALL	BDOS		;PRINT THE CHAR. IN 'A' ON THE CONSOLE
	  POP	H
	  POP	D
	  POP	B		;RESTORE THE REGISTERS
	  RET
;.....
;
;
; INLINE PRINT ROUTINE
;
ILPRT:	  XTHL			;SET HL TO POINT TO MESSAGE
;
ILPLP:	  MOV	A,M		;GET A CHARACTER FROM MESSAGE
	  CALL	AOUT2		;OUTPUT IT
	  INX	H		;POINT TO NEXT CHARACTER
	  MOV	A,M		;CHECK FOR END OF MESSAGE
	  ORA	A		; (00H MARKS END OF MESSAGE)
	  JNZ	ILPLP
	  XTHL			;GET PROPER RETURN ADDRESS ONTO STACK
	  RET			;THEN RETURN TO PROGRAM
;.....
;
;
COLUMN:	  DB	MAXCOL		;COLUMN COUNTER
CTU:	  DB	0		;CURRENT TRY USER NUMBER
CUN:	  DB	0		;CURRENTLY LOGGED-IN USER NUMBER
FIRST:	  DB	0		;FIRST TIME USE OF 'AOUT' (FOR CR/LF)
MAXTEMP:  DB	0		;MAXIMUM TRY USER NUMBER
MFLAG:	  DB	0		;FLAG SET TO NON-ZERO IF FILE IS FOUND
ORIGCTU:  DB	0		;ORIGINAL CURRENT TRY USER NUMBER
TRYDRV:	  DB	0		;NUMBER OF DRIVE BEING TRIED
UDNUM:	  DB	0		;USER/DRIVE NUMBER IS SAVED HERE
;
DSKSEL:	  DB	0C3H		;'JMP' INSTRUCTION
	  DW	00000H		;(BIOS'S DSKSEL ADDRESS IS STORED HERE)
				;(BYPASSES BDOS TO AVOID "BDOS CALL")
WBOOT:	  DW	0000H		;CP/M WARM-BOOT ADDRESS IS SAVED HERE
;.....
;
;
	  DS	64		;32 LEVEL STACK SHOULD BE ENOUGH ROOM
STACK:	  DS	2
;.....
;
;
	  END
OOT ADDRESS IS SAVED HERE
;.....
;
;
	  DS	64		;32 LEVE