home *** CD-ROM | disk | FTP | other *** search
- ; Search.asm
- ; FORMAT: SEARCH [d:][path][filename] [string][/P][/C][/B]
- ; At least one parameter must be entered.
- ; /P=printer /C=case sensitive /B=include executable files
- ; in string searches. Default is diskwide search. Limit search
- ; by adding parameters. String must be enclosed in quotes.
-
- CODE SEGMENT ;*************************
- ASSUME CS:CODE,DS:CODE ;* *
- ORG 100H ;* REMEMBER TO EXE2BIN *
- ;* *
- START: JMP BEGINNING ;*************************
-
- ; DATA AREA
- ; ---------
- COPYRIGHT DB 'Copyright 1986 Ziff Davis Publishing Co.',1AH
- PROGRAMMER DB 'Michael J. Mefford'
- SEARCH_SPEC DW OFFSET GLOBAL
- GLOBAL DB '*.*',0
- ROOT DB '\',0
- PARENT DB '..',0
- CURRENT_DISK DB ?
- PATH_END DW ?
- PARA_START DW ?
- GOOD_PARA DB 0
- STRING_START DW ?
- STRING_CT DW 0
- LINE_NUM DW 1
-
- STRING_FLAG DB 0
- PATH_FLAG DB 0
- PRINT_FLAG DB 0
- CASE_FLAG DB 0
- BINARY_FLAG DB 0
- EOF_FLAG DB 0
- MATCH_FLAG DB 0
- DISPLAY_FLAG DB 0
-
- EXE DB 'EXE'
- COM DB 'COM'
- BAD_PARA DB 'Invalid parameters',7,'$'
- SEARCH DB 13,10,'Searching for ',0
- DIRECTORY DB 13,10,13,10,'Directory ',0
- LINE DB 9,'Line number ',0
- SPACING DB 13,10,32,32,0
-
- DIR_ATTRIBUTE EQU 10H
- ALL_FILES EQU 6H
- QUOTES EQU 22H
-
- ;--------------------------------------------------------------;
- ; The first task is to initialize 100 bytes at the end of code ;
- ; to one. This will be used to track the directory level. ;
- ; The current drive and directory and drive will be saved. ;
- ; Then the command line at 80H in the PSP will be parsed. ;
- ;--------------------------------------------------------------;
-
- BEGINNING: CLD ;All string instructions will be
- MOV AL,1 ; done in a forward direction.
- MOV CX,100 ;Initialize directory subscripts
- MOV DI,OFFSET SUBSCRIPTS ;to one.
- REP STOSB
-
- MOV AH,19H ;Retrieve and save the current
- INT 21H ; drive.
- MOV CURRENT_DISK,AL
-
- MOV SI,OFFSET CURRENT_DIR+1 ;Leave room for "\".
- MOV DL,0
- MOV AH,47H ;Retrieve and save the
- INT 21H ; the current directory.
- MOV DX,OFFSET DTA ;Point the disk transfer address
- CALL CHANGE_DTA ; to the end of code.
-
- CMP BYTE PTR DS:[80H],0 ;If no parameters, exit with error.
- JA FIRST_PARA
- JMP EXIT
- FIRST_PARA: MOV SI,82H ;Point to the first byte of the
- NEXT_PARA: LODSB ; command line.
- CMP AL,32 ;Scan off leading spaces.
- JZ NEXT_PARA
- CMP AL,QUOTES ;If no filespec, parse string.
- JNZ CK_CR
- JMP STRING
- CK_CR: CMP AL,13 ;If no parameters, exit with error.
- JNZ CK_DRIVE
- JMP EXIT
-
- CK_DRIVE: CMP BYTE PTR [SI],':'
- JNZ NO_DRIVE ;If drive spec exists,
- AND AL,5FH ; convert drive to DOS format by
- SUB AL,'A' ; capitalizing and changing to
- MOV DL,AL ; hex number.
- MOV AH,0EH ;Change drive.
- INT 21H
- INC SI
- CALL PARA_END ;If end of filespec, done parsing
- JC DRIVE_ONLY ; here
- LODSB ; otherwise get next parameter.
- CMP AL,QUOTES ;If it's quotes exit with error.
- JNZ NO_DRIVE ; (need a space delimiter
- JMP EXIT ; before string.)
-
- NO_DRIVE: MOV PARA_START,SI ;We now are pointing to the start
- DEC PARA_START ; of the filespec parameter.
- MOV PATH_END,SI ;Will assume the end of path to
- DEC PATH_END ; be parameter start-1.
- DEC PATH_END
- CMP AL,'\' ;If search is to start at root,
- JNZ CK_GLOBAL ; change the directory to the root
- MOV DX,OFFSET ROOT ; and adjust the start pointer.
- CALL CHANGE_DIR
- MOV PATH_FLAG,1 ;Flag that a path exists.
- INC PARA_START
- CALL PARA_END
- DRIVE_ONLY: JC NEXT_DELIMIT ;If no other filespec, done here.
- CK_GLOBAL: CMP AL,'*' ;If *.*, search the entire disk.
- JNZ CK_SWITCH
- LODSB
- CMP AL,'.'
- JZ GOT_DOT
- JMP EXIT
- GOT_DOT: LODSB
- CMP AL,'*'
- JZ NEXT_DELIMIT
- CK_SWITCH: CMP AL,'/' ; We will loop from here to >----+
- JNZ NEXT_FILESPEC ; |
- CALL SWITCH ; |
- CMP AL,QUOTES ;If quotes without space, |
- JNZ NEXT_FILESPEC ; |
- JMP EXIT ; exit with error. |
- NEXT_FILESPEC: LODSB ; |
- CMP AL,32 ;If space character or below, |
- JBE FILESPEC ; we have the filespec. |
- CMP AL,'\' ;Check for path. |
- JNZ CK_SWITCH ; |
- MOV PATH_FLAG,1 ; |
- MOV PATH_END,SI ;If path found, update variables. |
- DEC PATH_END ; |
- JMP SHORT CK_SWITCH ; here to find the filespec. <----+
-
- ;------------------------------------------------------------;
- ; Now that we have the filespec, will check if it is a path. ;
- ;------------------------------------------------------------;
-
- FILESPEC: MOV BL,AL ;Save current delimiter.
- MOV BYTE PTR [SI-1],0 ;Format the end for DOS with a 0.
- MOV BYTE PTR DTA+21,0 ;Initiate file attribute to 0.
- MOV DX,PARA_START
- MOV CX,10H
- CALL FIND_FIRST ;Get file's attribute via DOS.
- FOUND_FILE: CMP BYTE PTR DTA+21,10H
- JNZ NO_PATH ;If it is a path, update variables
- MOV PATH_FLAG,1
- MOV PATH_END,SI
- DEC PATH_END
- JMP SHORT CK_DELIMITER
- NO_PATH: MOV DX,PATH_END ; otherwise, it is a filename;
- INC DX ; update path end; change search
- MOV SEARCH_SPEC,DX ; spec from global to filename.
- CK_DELIMITER: CMP BL,13 ;Check if delimiter is carriage
- JZ NO_STRING ; return. If yes, no string.
-
- ;------------------------------------------------------------------;
- ; Done with filespec. Now continuing by parsing string parameter. ;
- ;------------------------------------------------------------------;
-
- NEXT_DELIMIT: LODSB
- CMP AL,32 ;Scan off delimiting spaces.
- JZ NEXT_DELIMIT
- CMP AL,'/' ;Check if switch.
- JNZ NO_SWITCH
- CALL SWITCH
- JMP SHORT NEXT_DELIMIT
- NO_SWITCH: CMP AL,13 ;If carriage return, no string.
- JZ NO_STRING
- CMP AL,QUOTES ;If quotes, start of string.
- JNZ NEXT_DELIMIT
-
- STRING: MOV STRING_FLAG,1 ;Flag that string exists.
- MOV STRING_START,SI ;Point to start of string.
- XOR BH,BH
- MOV BL,BYTE PTR DS:[80H]
- ADD BX,81H ;Point to end of parameters and
- NEXT_QUOTE: DEC BX ;work backwards until find
- CMP BYTE PTR DS:[BX],QUOTES ;first quotes.
- JZ END_STRING
- CMP BX,SI ;If only one quote,
- JZ EXIT ; exit with error.
- JMP SHORT NEXT_QUOTE
-
- END_STRING: MOV BYTE PTR DS:[BX],0 ;Got end of string; mark with 0.
- PUSH BX ;Save position.
- SUB BX,SI ;Subtract to get string length.
- MOV STRING_CT,BX
- POP SI ;Restore position.
- LAST_PARA: LODSB ;We have the string. Now all
- CMP AL,'/' ; have left to do is check for
- JNZ LAST_SWITCH ; switches.
- CALL SWITCH
- LAST_SWITCH: CMP AL,13
- JNZ LAST_PARA
-
- ;-----------------------------------------------------;
- ; If no case sensitive switch, capitalize the string. ;
- ;-----------------------------------------------------;
-
- CMP CASE_FLAG,1
- JZ NO_STRING
- MOV CX,STRING_CT
- MOV BX,STRING_START
- CALL CAPITALIZE
-
- ;----------------------------------------------------------;
- ; If we got this far, the parameters were found valid. ;
- ; If a string was found, display it. If path was found, ;
- ; change directory and search, otherwise do global search. ;
- ;----------------------------------------------------------;
-
- NO_STRING: MOV GOOD_PARA,1 ;Flag as good parameters.
- CMP STRING_FLAG,1 ;If string exists, display it.
- JNZ STRINGLESS
- MOV SI,OFFSET SEARCH
- CALL WRITE_STRING
- MOV SI,STRING_START
- CALL WRITE_STRING
- STRINGLESS: CMP PATH_FLAG,1
- JNZ GLOBAL_SEARCH ;If path does not exist, do global
- MOV BX,PATH_END ; search, otherwise, change
- MOV BYTE PTR [BX],0 ; directory and display it.
- MOV DX,PARA_START
- CALL CHANGE_DIR
- CALL PRINT_DIR
- MOV DX,SEARCH_SPEC ;Find first matching filename.
- MOV CX,ALL_FILES
- CALL FIND_FIRST
- JC EXIT ;If no match, exit.
- CALL READ_FILE ;If string, read the file.
- NEXT_PATH: CALL FIND_NEXT ;Loop here finding subsequent
- JC EXIT ; matching files until no more.
- CALL READ_FILE
- JMP SHORT NEXT_PATH
-
- ;-------------------------------------------------------;
- ; This is the exit. The drive and directory is restored ;
- ; to how it was found. If parameters are invalid, error ;
- ; message is displayed, otherwise, just return to DOS. ;
- ;-------------------------------------------------------;
-
- EXIT: MOV DL,CURRENT_DISK ;Change drive.
- MOV AH,0EH
- INT 21H
-
- MOV DX,OFFSET ROOT ;Assume we came from root.
- CMP BYTE PTR CURRENT_DIR,0 ;If root, it will be a zero.
- JZ CHANGE_IT
- MOV BYTE PTR CURRENT_DIR,'\' ;Else, format with "\"
- MOV DX,OFFSET CURRENT_DIR
- CHANGE_IT: CALL CHANGE_DIR ;Change directory.
- MOV DL,13 ;Clear printer buffer
- CALL DISPLAY ; carriage return and linefeed.
- MOV DL,10
- CALL DISPLAY
- CMP GOOD_PARA,1
- JZ DONE
- MOV DX,OFFSET BAD_PARA
- MOV AH,9H
- INT 21H ;Display error message if invalid.
- DONE: INT 20H ;Terminate.
-
- ;---------------------------------------------------------------;
- ; This routine will systematically change directories up and ;
- ; down the directory tree, searching for the matching filename. ;
- ;---------------------------------------------------------------;
-
- GLOBAL_SEARCH: MOV DX,OFFSET ROOT ;Start the search from root.
- CALL CHANGE_DIR
- MOV BP,OFFSET SUBSCRIPTS ;Point to first level directory.
- FIRST_FILE: CALL PRINT_DIR ;Print the directory.
- MOV DX,SEARCH_SPEC
- MOV CX,ALL_FILES ;Find first matching filename
- CALL FIND_FIRST ; in this directory.
- JC FIRST_DIR
- CALL READ_FILE
-
- NEXT_FILE: CALL FIND_NEXT ;Find next matching filename.
- JC FIRST_DIR
- CALL READ_FILE ;If string, read the file.
- JMP SHORT NEXT_FILE ;Loop here until no more matches.
-
- PARENT_DIR: CMP BP,OFFSET SUBSCRIPTS ;When we try to return to parent
- JZ EXIT ; directory and are in root, we
- MOV DX,OFFSET PARENT ; are done. Otherwise, change
- CALL CHANGE_DIR ; to parent directory.
- MOV BYTE PTR DS:[BP],1 ;Put one back in previous level
- DEC BP ; and point to parent level.
-
-
- FIRST_DIR: XOR BL,BL ;Use BL as pointer to directory no.
- MOV DX,OFFSET GLOBAL
- MOV CX,DIR_ATTRIBUTE ;Ask for global match.
- CALL FIND_FIRST ;Find first matching.
- JC PARENT_DIR
- CK_DIR: CMP BYTE PTR DTA+21,10H ;If not a directory get next.
- JNZ NEXT_DIR
- CMP BYTE PTR DTA+30,'.' ;If it is a dot directory get next.
- JZ NEXT_DIR
- INC BL ;Increment position in directory.
- CMP BL,DS:[BP] ;Continue until new directory.
- JNZ NEXT_DIR
- INC BYTE PTR DS:[BP] ;Update variables.
- MOV DX,OFFSET DTA+30
- CALL CHANGE_DIR ;Change the directory.
- INC BP
- JMP SHORT FIRST_FILE ;Get all files in new directory.
-
- NEXT_DIR: CALL FIND_NEXT ;Get all subdirectories in current
- JC PARENT_DIR ; directory then go to parent.
- JMP SHORT CK_DIR
-
- ;*************;
- ; SUBROUTINES ;
- ;*************;
-
- CHANGE_DIR: MOV AH,3BH
- INT 21H
- RET
-
- CHANGE_DTA: MOV AH,1AH
- INT 21H
- RET
-
- FIND_FIRST: MOV AH,4EH
- INT 21H
- RET
-
- FIND_NEXT: MOV AH,4FH
- INT 21H
- RET
-
- ;---------------------------------------------------;
- ; This subroutine checks for delimiting characters. ;
- ;---------------------------------------------------;
-
- PARA_END: CMP BYTE PTR [SI],32
- JBE SET_CARRY
- CMP BYTE PTR [SI],'/'
- JZ SET_CARRY
- CLC
- RET
- SET_CARRY: STC
- RET
-
- ;---------------------------------------------------;
- ; This subroutine checks for the switch characters. ;
- ;---------------------------------------------------;
-
- SWITCH: MOV BYTE PTR [SI-1],0 ;Zero in place of /.
- MOV BL,DS:[SI] ;Retrieve the character.
- AND BL,5FH ;Capitalize.
- CMP BL,'P'
- JNZ CK_CASE
- MOV PRINT_FLAG,1
- CK_CASE: CMP BL,'C'
- JNZ CK_BINARY
- MOV CASE_FLAG,1
- CK_BINARY: CMP BL,'B'
- JNZ END_SWITCH
- MOV BINARY_FLAG,1
- END_SWITCH: RET
-
- ;---------------------------------------------------------;
- ; This subroutine prints the current drive and directory. ;
- ;---------------------------------------------------------;
-
- PRINT_DIR: MOV SI,OFFSET DIRECTORY ;Print "Directory "
- CALL WRITE_STRING
- MOV AH,19H ;Get current drive and display.
- INT 21H
- ADD AL,'A'
- MOV DL,AL
- CALL DISPLAY
- MOV DL,':' ;Add the colon.
- CALL DISPLAY
- MOV DL,'\' ;And root.
- CALL DISPLAY
- MOV SI,OFFSET WORKING_DIR
- MOV DL,0
- MOV AH,47H ;Get the current directory
- INT 21H ; and display.
- CMP BYTE PTR WORKING_DIR,0
- JZ END_DIR
- CALL WRITE_STRING
- END_DIR: RET
-
- ;-----------------------------------------------------------;
- ; This is the major subroutine. If a string is to be found, ;
- ; the file is opened, read and compared with the string. ;
- ;-----------------------------------------------------------;
-
- READ_FILE: PUSH BP ;Save the BP; caller is using it.
- CMP STRING_FLAG,1 ;If no string, simply display file.
- JZ BINARY_READ
- JMP PRINT_FILE
- BINARY_READ: CMP BINARY_FLAG,1 ;If /B was found open the file
- JZ OPEN_FILE ; otherwise, skip EXE and COM files
- CALL EXE_COM
- JNC OPEN_FILE
- JMP RETURN
-
- OPEN_FILE: MOV EOF_FLAG,0 ;Reset EOF and MATCH flags.
- MOV MATCH_FLAG,0
- MOV DX,OFFSET DTA+30
- MOV AX,3D00H ;Open the file for reading.
- INT 21H
- MOV BX,AX
- GET_FILE: PUSH BX ;Save the file handle for closing.
- MOV DX,OFFSET FILE
- MOV CX,63488 ;Attempt to read 63488 bytes.
- MOV AH,3FH
- INT 21H
- CMP AX,63488 ;If less than 63488, we got
- JZ FILE_END ; all of the file; flag so.
- MOV EOF_FLAG,1
- FILE_END: CMP AX,0 ;If no bytes to read, close file.
- JZ CLOSE_FILE
-
- WORDSTAR: MOV CX,AX
- MOV BX,OFFSET FILE
- STRIP: AND BYTE PTR DS:[BX],7FH ;Strip the high bit for WORDSTAR.
- INC BX
- LOOP STRIP
-
- CMP CASE_FLAG,1 ;If not case sensitive, capitalize.
- JZ SENSITIVE
- MOV CX,AX
- MOV BX,OFFSET FILE
- CALL CAPITALIZE
-
- SENSITIVE: CMP AX,STRING_CT ;If string count is larger than
- JB CLOSE_FILE ; file, we are done here.
- MOV BP,AX ;BP will count bytes of file.
- MOV BX,OFFSET FILE ;BX will track position in file.
- MOV DX,STRING_START ;Store string start in DX
- SUB BP,STRING_CT
- INC BP
- NEXT_BYTE: MOV SI,BX ;Recover file position.
- MOV DI,DX ;Recover string start.
- MOV CX,STRING_CT ;Get string length.
- MOV AH,CL ;Track delimiters.
- LOAD_BYTE: LODSB ;Get a byte.
- CMP AL,32 ;If it is below space, skip.
- JAE COMPARE
- DEC AH ;Track skips so not endless loop.
- JNZ LOAD_BYTE
- JMP SHORT NEXT_LOAD
- COMPARE: DEC AH ;Compare with string.
- SCASB
- JNZ NEXT_LOAD ;If no match, move up in file.
- NEXT_COMPARE: LOOP LOAD_BYTE
- MOV MATCH_FLAG,1 ;If all bytes match, flag.
- MOV LINE_NUM,SI ;Save position in file.
- JMP SHORT CLOSE_FILE ;And close file.
- NEXT_LOAD: INC BX ;Otherwise, point to next byte
- DEC BP ;in file and decrement byte counter
- JNZ NEXT_BYTE ;and get next byte.
-
- EOF: CMP EOF_FLAG,1 ;If we did not get all the file,
- JZ CLOSE_FILE ;return for more, otherwise close.
- MOV CX,0FFFFH ;Bump the file pointer back the
- MOV DX,STRING_CT ;length of the file so we will
- NEG DX ;not miss match at the break.
- POP BX
- MOV AX,4201H ;Move pointer via DOS.
- INT 21H
- JMP GET_FILE ;And get more bytes.
-
- CLOSE_FILE: POP BX ;Recover file handle.
- MOV AH,3EH ;And close.
- INT 21H
- CMP MATCH_FLAG,1 ;if no match, return.
- JNZ RETURN
-
- PRINT_FILE: MOV SI,OFFSET SPACING ;Indent then display the file.
- CALL WRITE_STRING
- MOV SI,OFFSET DTA+30
- CALL WRITE_STRING
- CMP STRING_FLAG,1
- JNZ RETURN
- CALL PRINT_LINE ;Print line number match was found.
- RETURN: POP BP ;Restore BP
- RET ;And return.
-
- ;------------------------------------------;
- ; These two subroutines do the displaying. ;
- ;------------------------------------------;
-
- DISPLAY: CMP PRINT_FLAG,1 ;If /P, echo to the printer.
- JNZ NOT_PRINTER
- MOV AH,5
- INT 21H
- NOT_PRINTER: MOV AH,2
- INT 21H
- RET
-
- WRITE_IT: MOV DL,AL
- CALL DISPLAY
- WRITE_STRING: LODSB
- CMP AL,0 ;Zero marks end of string.
- JNZ WRITE_IT
- RET
-
- ;-------------------------------------------;
- ; This subroutine will capitalize the file. ;
- ;-------------------------------------------;
-
- CAPITALIZE: CMP BYTE PTR DS:[BX],'a'
- JB NEXT_CAP
- AND BYTE PTR DS:[BX],5FH
- NEXT_CAP: INC BX
- LOOP CAPITALIZE
- RET
-
- ;------------------------------------------------------------;
- ; This subroutine will check to see it file is .EXE or .COM. ;
- ;------------------------------------------------------------;
-
- EXE_COM: MOV SI,OFFSET DTA+30 ;Point to filename.
- EXTENSION: LODSB ; and search for dot.
- CMP AL,0 ;If zero, end of filename.
- JZ NOT_BINARY
- CMP AL,'.'
- JNZ EXTENSION
- MOV AX,SI ;Save extension pointer.
- MOV DI,OFFSET EXE ;Compare first with EXE
- MOV CX,3
- REP CMPSB
- JZ BINARY
- MOV SI,AX
- MOV DI,OFFSET COM ;Then compare with COM
- MOV CX,3
- REP CMPSB
- JZ BINARY
- NOT_BINARY: CLC ;Return with no carry is no match.
- RET
- BINARY: STC ;Return with carry is match.
- RET
-
- ;----------------------------------------------------------------------------;
- ; This subroutine will calculate and display the line number for each match. ;
- ;----------------------------------------------------------------------------;
-
- PRINT_LINE: XOR BH,BH ;Get the cursor position to see
- MOV AH,3 ; if need to add a tab character
- INT 10H ; to format the display.
- CMP DL,7 ;If column 8 or less, add tab.
- JA NO_TAB
- MOV DL,9
- CALL DISPLAY
- NO_TAB: MOV SI,OFFSET LINE ;Display "Line number "
- CALL WRITE_STRING
- MOV CX,LINE_NUM ;Retrieve offset into file to
- SUB CX,OFFSET FILE ; calculate the number of bytes
- MOV SI,OFFSET FILE ; to look for carriage returns.
- MOV BX,1 ;Start at line one.
- CK_LINE: LODSB
- CMP AL,13 ;Count the carriage returns.
- JNZ NEXT_LINE
- INC BX
- NEXT_LINE: LOOP CK_LINE
-
- MOV DISPLAY_FLAG,0 ;Reset the display flag.
- TENTHS: MOV CX,10000 ;Get ten thousands by dividing.
- CALL DIVIDE
- MOV CX,1000 ;Get thousands by dividing.
- CALL DIVIDE
- MOV CX,100 ;Get hundreds by dividing.
- CALL DIVIDE
- MOV CX,10 ;Get tens by dividing.
- CALL DIVIDE
- MOV CX,1 ;Get ones by dividing.
- CALL DIVIDE
- RET
-
- DIVIDE: MOV AX,BX ;Number in AX
- XOR DX,DX ; and zero in DX
- DIV CX ; divide by CX
- MOV BX,DX ; remainder into BX
- MOV DL,AL ; and quotient into DL.
- CMP AL,0 ;Is it zero?
- JZ FLAG ;If yes, is a non zero displayed?
- OR DISPLAY_FLAG,AL ;If non zero indicate by flag.
- FLAG: CMP DISPLAY_FLAG,0 ;Has there been a display?
- JZ END_LINE ;If no, return.
-
- DISP_NUMBER: ADD DL,30H ;Convert hexadecimal to decimal
- CALL DISPLAY ;And display.
- END_LINE: RET
-
-
- SUBSCRIPTS:
- CURRENT_DIR EQU SUBSCRIPTS+100
- WORKING_DIR EQU CURRENT_DIR+64
- DTA EQU WORKING_DIR+64
- FILE EQU DTA+65
- CODE ENDS
- END START
-