CODE_SEG SEGMENT ASSUME CS:CODE_SEG,DS:CODE_SEG,ES:CODE_SEG ORG 100H ;Start off right for a .COM file ENTRY: JMP LOCATE ;Skip over Data area COPY_RIGHT DB '(C)1985 S.Holzner' ;Author's Mark FOUND_MSG DB 13,10,13,10,'FOUND IN $' ;Like it says LEN DW 1 ;The file length (low word) PATH_LEN DW 0 ;Length of Path.Dat NUMBER DW 0 ;Number of bytes read from file EXTRA_PATHS DB 0 ;=1 if we open & use Path.Dat OLD_BX DW 0 ;Save pointer to path at CS:DBH OLD_SI DW 0 ;Save SI as pointer also START_FLAG DB 0 ;For searches in Path.Dat PATH_DAT DB "\PATH.DAT",0 ;ASCIIZ string of Path.Dat LOCATE PROC NEAR ;Here we go MOV DX,0B0H ;Move Disk Transfer Area to CS:0B0H MOV AH,1AH ;Matched file information goes there INT 21H MOV DI,5CH ;Use CS:5CH to put '*.*'0 at for search CALL PUT ; in current directory MOV DX,5CH ;Point to '*.*'0 for search MOV AH,4EH ; and find first matching file INT 21H ;Match now at DTA, 0B0H LOOP: ;Loop over matches now MOV BX,0CAH ;Get file length, came from match MOV DX,[BX] MOV LEN,DX ;Store in Len CMP DX,60*1024 ;Don't write over stack, allow < 64K files JB NOT_BIG ;Range extender (Find > 127 bytes ahead) JMP FIND NOT_BIG:CMP DX,0 ;Was this a 0 length file (disk dir or label)? JA FILE_OK ;No, go on and read it JMP FIND ;Yes, find next file and skip this one FILE_OK:CALL READ_FILE ;Get the file into memory MOV CX,NUMBER ;Prepare to loop over all read bytes MOV DI,OFFSET PATHS+300 ;File starts at Offset Paths+300 SEARCH: ;Use Repne Scasb & DI to search for the MOV BX,82H ;first letter of the string, which is at CS:82H MOV AL,BYTE PTR [BX] ;Load into AL for Repne Scasb REPNE SCASB ;Find first letter JCXZ FIND ;If out of file to search, find next file MOV BX,80H ;How many chars in string? Get from CS:80H XOR DX,DX ;Set DX to zero MOV DL,[BX] ;Get # of chars in string DEC DX ;Get rid of space typed after 'Locate' MOV SI,83H ;Search from second typed letter (1st matched) CPLOOP: DEC DX ;Loop counter CMPSB ;See how far we get until no match JZ CPLOOP DEC DI ;At end, reset DI (Scasb increments 1 too much) CMP DX,0 ;If DX is not zero, all letters did not match JA SEARCH ;If not a match, go back and get next one LEA DX,FOUND_MSG ;FILE HAS BEEN FOUND, so say so. MOV AH,9 ;Request string search INT 21H MOV AH,2 ;Now to print filename. Without Path.Dat, at MOV BX,0DBH ; CS:CEH, with Path.Dat at CS:DBH CMP EXTRA_PATHS,1 ; Using Path.Dat yet? JE PRINT ;Yes, print MOV BX,0CEH ;No, reset BX to point to CS:CEH PRINT: MOV DL,[BX] ;Print out the filename until 0 found CMP DL,0 ;Is it 0? JE MORE ;If yes,print out sample at More: INT 21H ;Print filename character INC BX ;Point to next character JMP PRINT ;Go back relentlessly until done MORE: PUSH DI ;Save DI,BX,CX PUSH BX PUSH CX MOV CX,40 ;Prepare to type out total of 40 characters MOV AH,2 ;With Int 21H service 2 MOV DL,':' ;But first, add ':' to filename INT 21H ;And a carriage return linefeed MOV DL,13 INT 21H MOV DL,10 INT 21H SUB DI,20 ;DI points to end of found string, move back MOV BX,OFFSET PATHS+300 ;Beginning of file CMP DI,BX ;If before beginning, start at beginning JA GO MOV DI,BX GO: ADD BX,LEN ;Now BX=end of file (to check if we're past it) SHOW: MOV DL,[DI] ;Get character from file INC DI ;And point to next one CMP DI,BX ;Past end? JA SHOWS_OVER ;Yes, jump out, look for next match CMP DL,30 ;Unprintable character? JA POK ;No, OK MOV DL,' ' ;Yes, make it a space POK: INT 21H ;Print Character LOOP SHOW ;And return for the next one SHOWS_OVER: ;End of printout POP CX ;Restore the registers used above POP BX POP DI JMP SEARCH ;Return to search more of the file FIND: CALL FIND_FILE ;This file done, find next match CMP AL,18 ;AL=18 --> no match JE OUT ;And so we leave JMP LOOP ;If match found, go back once again OUT: INT 20H ;End of Main Program LOCATE ENDP PUT PROC NEAR ;This little gem puts a '*.*'0 MOV BYTE PTR [DI],'*' ;Wherever you want it--just send MOV BYTE PTR [DI+1],'.' ; it a value in DI. '*.*'0 is used as MOV BYTE PTR [DI+2],'*' ; a universal wilcard in searches MOV BYTE PTR [DI+3],0 RET PUT ENDP WS PROC NEAR ;Strip the bits for WordStar CMP CX,0 ;If there is a length of 0, e.g. JE FIN ;Directory entries, etc. do nothing. WSLOOP: AND BYTE PTR [BX],127 ;Set top bit to zero INC BX ;Point to next unsuspecting byte LOOP WSLOOP ;And get it too. FIN: RET ;To use, send this program BX and CX WS ENDP FIND_FILE PROC NEAR ;The file finder MOV AH,4FH ;Try service 4FH, find next match, first INT 21H CMP AL,18 ;AL = 18 --> no match JE CHECK ;Range extender. JMP NEW CHECK: CMP EXTRA_PATHS,1 ;Have we used path.Dat? JE NEXT_PATH ;Yes, get next path, this one's used up INC EXTRA_PATHS ;No, set it to 1 MOV AX,3D00H ;Request file opening for Path.Dat LEA DX,PATH_DAT ;Point to '\PATH.DAT'0 INT 21H JNC READ ;If there was a carry, Path.Dat not found DONE: MOV AL,18 ;And so we exit with AL=18 JMP END READ: MOV CX,300 ;Assume the max length for Path.Dat, 300. MOV BX,AX ;Move found file handle into BX for read MOV AH,3FH ;Set up for file read LEA DX,PATHS ;Put the file at location Paths (at end) INT 21H ;Read in the file ADD AX,OFFSET PATHS ;Full offset of end of Path.Dat MOV PATH_LEN,AX ;Get Path.Dat end point for loop MOV AH,3EH ;Now close the file INT 21H ;Close file MOV OLD_SI,OFFSET PATHS ;Save for future path-readings MOV CX,300 ;Get ready to Un-WordStar MOV BX,OFFSET PATHS ;300 bytes at location Paths CALL WS ;Strip high bit for WS NEXT_PATH: ;Come here to find next path to search for files MOV SI,OLD_SI ;Point to start of next path MOV DI,5CH ;Move will be to CS:5CH for '\path\*.*0' file find MOV BX,0DBH ;Also to CS:DBH; will assemble full path & filename MOV START_FLAG,0 ;Start the path search CHAR: CMP SI,PATH_LEN ;Past end of possible path names? JGE DONE ;Yes, we're done. Leave with AL=18 CMP BYTE PTR [SI],30 ;Carriage return or linefeed? JB NEXT ;Yes, get next char MOV START_FLAG,1 ;First char, stop skipping chars MOV AL,[SI] ;Get char from Path.Dat MOV [BX],AL ;Move char to DBH INC BX ;And increment to next location there MOVSB ;Also move to 5CH area JMP CHAR ;And go back for more NEXT: CMP START_FLAG,1 ;Bad char, have we been reading a real pathname? JE PDONE ;Yes, we've reached the end of it. INC SI ;No, keep skipping chars to find pathname JMP CHAR PDONE: MOV OLD_SI,SI ;Save SI for the next path. MOV BYTE PTR [DI],'\' ;Add '\' to both paths MOV BYTE PTR [BX],'\' INC BX ;Move BX on for next time MOV OLD_BX,BX ;And save it. INC DI ;Move to next location at 5CH and CALL PUT ;Put '*.*'0 there to find all files. MOV DX,5CH ;Start the search for all files in MOV AH,4EH ; the new path. MOV CX,0 ;Set the file attribute to 0 INT 21H CMP AL,18 ;Did we find any new files in new path? JE NEXT_PATH ;No, get the next path. NEW: CMP EXTRA_PATHS,1 ;Yes,Move found filename to DBH area to JNE END ; read it in-only if DBH area is active MOV BX,OLD_BX ; (i.e. Extra_Paths=1). Restore BX MOV SI,0CDH ;And point to found filename in DTA CLOOP: INC SI ;Next letter from found filename MOV AH,[SI] ;Move it to the DBH area so we can read MOV [BX],AH ; in the file (needs pathname\filename) INC BX ;Next character in 5CH area. CMP BYTE PTR [SI],0 ;Is this the last character? JNE CLOOP ;Nope, get next one END: RET ;After path & filename assembled, return FIND_FILE ENDP READ_FILE PROC NEAR ;Looks for filename at CEH or DBH & reads it PUSH AX ;Push everything to save it. PUSH BX PUSH CX PUSH DX MOV DX,0DBH ;Try the DBH area CMP EXTRA_PATHS,1 ;Has it been used? JE OK ;Yes MOV DX,0CEH ;No, not using paths yet, use filename only, at CEH OK: MOV AX,3D00H ;Prepare for file reading INT 21H ;And do so. MOV BX,AX ;Move file handle into BX to read MOV DX,OFFSET PATHS+300 ;Read into data area at Paths+300 bytes MOV CX,LEN ;Read the full file's length in bytes MOV AH,3FH ;Read it in at last INT 21H MOV NUMBER,AX ;Number of bytes actually read. MOV AH,3EH ;Close file INT 21H MOV BX,OFFSET PATHS+300 ;Clean up the Word Star high bit. MOV CX,LEN ;For the full file CALL WS ;Strip high bit for ws POP DX ;Pop evrything and return POP CX POP BX POP AX RET ;Fin of Read_File READ_FILE ENDP PATHS: ;Here's the end of program marker CODE_SEG ENDS END ENTRY ;End 'Entry' so DOS starts at 'Entry'