home *** CD-ROM | disk | FTP | other *** search
- ; FILENAME: IWHEREIS.ASM
- ;
- ; Copyright (c) 1988, 1992 by Borland International, Inc.
- ;
- ; DESCRIPTION: This program does a search for the file(s) specified on the
- ; command line. It can also perform a DOS command on each file that is
- ; found.
- ;
- ; Syntax: WHEREIS [d:][path]filename filename filename... [dos_command]
- ; dos_command is a command surrounded by "",'', or []. It will be called
- ; for each file that is found. It should include at least one of these:
- ; %1 - Insert full path, filename and extension
- ; %2 - Filename and extension (no path)
- ; %3 - Only the path.
- ; %4 - Only the filename before the extension followed by a .
- ; %5 - Only the extension, preceeded by a .
- ; For example to delete all .BAK files on a drive:
- ; WHEREIS *.BAK [DEL %2]",13,10>
- ;
- ; Note that dos_command may be any valid DOS command, including invoking
- ; batch files or built-in DOS commands. Note that the RMDIR, (also RD),
- ; command should not be used on the directory that WHEREIS is currently
- ; executing in.
- ;
- ;
- ; ASSEMBLY INSTRUCTIONS: To assemble this module use the following
- ; TASM command line.
- ;
- ; TASM /m /dMDL=memorymodel iwhereis
- ;
- ; /m in the above command line allows TASM to use extra passes to resolve
- ; jumps and other operations to their shortest form and get rid of extra NOPs.
- ; 'memorymodel' in the above command line may be replaced by TINY, SMALL,
- ; MEDIUM, COMPACT, LARGE or HUGE. If assembling this module to run on
- ; a 286/386 machine, turn on the P286 directive in order to take advantage of
- ; 286/386 specific instructions. For example:
- ;
- ; TASM /m /dMDL=memorymodel /jP286 iwhereis
- ;
- ; SYSTEM REQUIREMENTS:
- ; TASM 2.0
- ; 256K
- ; DOS 2.0 or later
-
- ; TURBO ASSEMBLER NEW FEATURES:
- ; TASM 2.0 has many new features. The following is a list of a few of
- ; them that have been used to make this program easier and more readable.
- ; To find the examples in the code, just seach for "**n", where n is a
- ; number from the following table.
-
- ; Special TASM 2.0 features:
- ; **1 - TASM automatically pushes the immediate value in a way that
- ; preserves all registers if the processor mode is 8086. If
- ; 186 or above, then TASM pushes the value directly.
- ; **2 - Many lines of assembler are replaced by the use of the
- ; extended call syntax.
- ; **3 - Conditional jumps that go out of range are automatically
- ; adjusted to a different code sequence that allows the
- ; further jump. Other jumps, even if forward referenced, are
- ; automatically changed to the shortest possible code sequence
- ; without extra NOPs, because of multipass capability.
- ; **4 - TASM handles forward referenced variables that occur
- ; in a segment other than DS: by automatically inserting
- ; the proper segment override, and without causing phase errors.
- ; **5 - TASM's ability to handle multiple objects on a single
- ; PUSH or POP command makes coding shorter.
- ; **6 - TASM's new line continuation feature while in IDEAL mode
- ; makes long argument lists very easy.
-
-
- jumps ; Have TASM automatically resolve out of range jumps
-
- %tabsize 4
-
- ifndef MDL
- display "Error: This module requires that you provide a memory model"
- display " definition on the command line. I.E. /dMDL=SMALL."
- err ; Force a fatal error
- else
-
- ideal ; Use TASM's Ideal mode
- % model MDL,pascal ; Define the memory model
- ; Set language to PASCAL so we can rely on TASM's
- ; new extended call features.
-
- ProgramVersion EQU "2.01"
-
- include "iwhglobl.inc" ; Public symbol declarations
- include "imacros.mac" ; Various macros
- include "bios.inc"
- include "ibios.mac"
- include "kbd.inc" ; Keyboard scan codes
- include "dos.inc" ; Equates representing DOS functions/services
- include "idos.mac"
-
- stack 7FFFh ; Allocate 32K stack
-
-
-
-
- codeseg
- SavedDS dw ? ; For the control-break handler to find the path
- ; variables for restoring the original path and
- ; drive.
-
- BreakPressed db 0 ; Set by Int1B handler to one if
- ; CTRL-BREAK pressed. Allows us to break even
- ; if DOS BREAK is set to off.
- global BreakPressed:byte ; So other modules can check it!
-
-
- dataseg
-
- PspAddress dw ? ; Segment address of Program Segment Prefix(PSP)
- DisplayPage db 0 ; Current display page
-
- Old1BHandlerSeg dw ?
- Old1BHandlerOfs dw ?
-
-
- include "WHUSAGE.INC" ; Usage screen declaration
-
- ; Pascal style strings to store the parsed file specification.
-
- Drive db 0," : "
- Path db MAX_PATH_LENGTH dup (0)
-
- ; Following is used as a scratchpad when parsing additional filespecs
- ; from the command line.
- tempDrive db 0," : "
- tempPath db MAX_PATH_LENGTH dup (0)
-
-
- FileSpecCounter db 0 ; Count how many filespecs we parsed
- NextFileSpec dw 0 ; Location of where to put next filespec
-
- DrivePtr dw ? ; Points to where the file parse routine should
- PathPtr dw ? ; place its results.
-
-
- FileSpec db MAX_FILE_SPECS dup (FILE_SPEC_SIZE dup (0))
- ; Make room for the filenames, each with a
- ; preceeding length byte and terminating 0
-
- db '\'
- HomeDirectory db MAX_PATH_LENGTH dup (0)
- OldDrive db ?
-
- ; When working through the arguments on the command line to setup
- ; filespecs,
- CurrentArgument db MAX_PATH_LENGTH+FILE_SPEC_SIZE dup (0)
-
- codeseg
-
- proc GetArgument
- ; This procedure gets an argument transfered into a temporary
- ; buffer where all leading spaces are removed from the string.
- ;
- ; Input
- ; AL contains number of argument to get.
- ; Output
- ; If argument exists:
- ; AL number of argument
- ; ES:DI points to temporary argument buffer
- ; If argument does not exist:
- ; AL contains 0
- ; Calling conventions
- ; NA
- ; Registers modified
- ; all
-
- call ParamString
- or al,al
- jz @@Finished ; A zero return means no more arguments.
-
-
-
- push ax ; Save it to restore return value from ParamString
-
- ; **2
- ; The following lines are neatly replaced by a single line CALL with
- ; extended syntax. All the variables are automatically pushed on the
- ; stack in the proper order, automatically.
- ;
- ; push es
- ; push di
- ;
- ; if (@Cpu and 100b) eq 100b
- ; push seg CurrentArgument
- ; else
- ; mov ax, seg CurrentArgument
- ; push ax
- ; endif
- ; if (@Cpu and 100b) eq 100b
- ; push offset CurrentArgument
- ; else
- ; mov ax, offset CurrentArgument
- ; push ax
- ; endif
-
- xor ah,ah
- mov al,[byte es:di]
- inc ax
-
- call ByteCopy,es,di,seg CurrentArgument,Offset CurrentArgument
-
- @@DeleteSpaces:
- cmp [CurrentArgument+1], SPACE
- jne @@NoMoreSpaces
-
- ; **2
- ; if (@Cpu and 100b) eq 100b
- ; push seg CurrentArgument
- ; else
- ; mov ax, seg CurrentArgument
- ; push ax
- ; endif
- ; if (@Cpu and 100b) eq 100b
- ; push offset CurrentArgument
- ; else
- ; mov ax, offset CurrentArgument
- ; push ax
- ; endif
-
- mov cx, 1 ; Remove the first character
- mov ax, 1 ; from the string
- call DeleteChar,seg CurrentArgument,offset CurrentArgument
-
- jmp @@DeleteSpaces
- @@NoMoreSpaces:
- mov ax,seg CurrentArgument
- mov es,ax
- mov di,offset CurrentArgument
-
- pop ax
-
-
-
- @@Finished:
- ret
- endp GetArgument
-
-
-
- dataseg
-
- MakePascalString SearchMssg,<"WHEREIS parameters:",13,10>
-
- codeseg
- proc Show_Args
- ; This procedure displays all the command line parameters sent
- ; to the program.
- ;
- ; Input
- ; none
- ; Output
- ; none
- ; Calling conventions
- ; NA
- ; Registers modified
- ; all
-
- push es di ax ;**5
- call WritePascalString,ds,offset SearchMssg
- mov [argcount],1 ;**4
-
- @@Show_loop:
- mov al,[argcount]
- call GetArgument
- or al,al ; Check for zero return. Means no more arguments.
- jz @@Show_Exit
-
- call WritePascalString,es,di ; Show the current argument
-
- push seg BlankLine ;**1
- push offset BlankLine
- call WritePascalString
-
- inc [argcount] ;**4
- jmp @@Show_loop
-
- @@Show_Exit:
- pop ax di es ;**5
- ret
-
- argcount db 1 ;**4
- endp Show_Args
-
-
-
- proc Main
-
- ;************************* Program Entry Point ***************************
- ; Execution of the program begins here.
-
- EntryPoint:
- mov ax, @data ; Initialize ds by moving segment address
- mov ds, ax ; of data segment into ds register
- push bp ; Setup a starting stack frame.
- mov bp, sp
-
- call Initialize ; Initialize data structures, etc.
-
- call Show_Args
-
-
- mov [FileSpecCounter],0 ; FileSpecCounter has # files found so far
- mov [NextFileSpec],offset FileSpec
- mov [PathPtr],offset Path
- mov [DrivePtr],offset Drive
-
-
- mov al,[FileSpecCounter]
- ProcessFileSpec: ; Jump to here if AL already loaded
- cmp al,MAX_FILE_SPECS
- je @@StartFileSearch ;**3
-
- inc al
- call GetArgument
- or al,al
- jz @@StartFileSearch ; If al=0, we are at the end of arguments.
-
- mov al,[byte es:di+1]
- call IsDelimiter
- jc HandleDosCommand
-
- ; **2
- ; push es ; Store the location of the unparsed file spec.
- ; push di
- ;
- ; ; Pull apart the drive, path and filename so we can store the
- ; ; filename specification.
- ;
- ; push ds ; Push the address to store the drive spec. in
- ; if (@Cpu and 100b) eq 100b
- ; push offset Drive
- ; else
- ; mov ax, offset Drive
- ; push ax
- ; endif
- ; push ds ; Push the address to store the path spec. in
- ; if (@Cpu and 100b) eq 100b
- ; push offset Path
- ; else
- ; mov ax, offset Path
- ; push ax
- ; endif
- ; push ds ; Push address to store filename spec. in
- ; if (@Cpu and 100b) eq 100b
- ; push offset FileSpec
- ; else
- ; mov ax, offset FileSpec
- ; push ax
- ; endif
-
- ; Parse the filename into it's components
- call ParseFilename,es,di, \ ;Filespec to be parsed
- ds,[DrivePtr], \ ;**6
- ds,[PathPtr], \
- ds,[NextFileSpec]
-
- mov al,[FileSpecCounter]
- or al,al
- jz CheckFirstArg ; If al is zero, we are checking first
- ; argument, so we can allow drive and
- ; path specification.
-
- mov bx,[PathPtr]
- cmp [byte bx], 0 ; Check if the parsed path is empty
- jne @@IllegalPath
- mov bx,[DrivePtr] ; Check if the parsed drive is empty
- cmp [byte bx],0
- jne @@IllegalPath
-
- jmp @@GetAnotherFileSpec
-
- @@IllegalPath: ; Give an error for path on parameter other
- ; than the first.
- call PathAfterFirst
-
-
- CheckFirstArg:
- ; For the next arguments, set the pointers to dummy areas
- ; since we don't pay attention to the path and drive for
- ; arguments other than the first.
- mov [PathPtr],offset tempPath
- mov [DrivePtr],offset tempDrive
-
- cmp [byte Path], 0 ; Check if the path is empty
- jne HaveAPath
- mov [byte Path], 1
- mov [byte Path+1], '\'
- HaveAPath:
- cmp [byte Drive], 0 ; Check if a drive definition exists
- je DontChangeDrives
- cmp [byte Drive+1], 61h ; Check if the drive letter is lower
- jng IsCapitalized ; case
- sub [byte Drive+1], 20h ; Capitalize the drive letter
- IsCapitalized:
- mov al, [byte Drive+1]
- sub al, 'A'
- ChangeDrive <al> ; Change to the appropriate drive
- jmp DoneWithFirstArg
- DontChangeDrives:
- mov [byte Drive], 2 ; Initialize the drive
- mov al, [byte OldDrive]
- mov [byte Drive+1], al ; string with the
- add [byte Drive+1], 'A' ; current drive.
- DoneWithFirstArg:
- jmp @@GetAnotherFileSpec
-
-
- HandleDosCommand:
- ; If a DOS command is given, it is surrounded by quotes.
- ; We need to strip the quotes, and store it in the module that
- ; handles executing DOS commands.
- call ParseDosCommand
- jnc @@DoneWithArg ; If no errors, we are done with this arg
- call OnlyOneDosCommand
-
- @@GetAnotherFileSpec:
- add [NextFileSpec],FILE_SPEC_SIZE
-
- ; Increment the FileSpecCounter
- mov al,[FileSpecCounter]
- inc al
- mov [FileSpecCounter],al ; FileSpecCounter has # files found so far
- @@DoneWithArg:
- jmp ProcessFileSpec
-
- @@StartFileSearch:
- ; We are now done analyzing the command line parameters.
- ; Copy the start path onto the stack
-
- sub sp, MAX_PATH_LENGTH ; Make room on the stack
- mov si, sp
-
- xor ah, ah
- mov al, [byte Path] ; Get the path length
- inc al ; We want to copy the length byte also
- inc al ; And the null terminator
- call ByteCopy,ds,offset Path,ss,si ; Copy the path onto the stack
-
-
- call FindFiles ; Do the search for the file(s)
- call Terminate ; End the program
- ;*************************************************************************
- endp main
-
-
- proc Terminate
-
- ; This procedure handles exiting from WHEREIS and restoring the
- ; original directory and drive.
-
- mov ax, [SavedDS]
- mov ds,ax
- mov al, [byte OldDrive] ; Get the original disk drive
- ChangeDrive <al> ; Restore the original disk drive
- ChangeDirectory <seg HomeDirectory>, <((offset HomeDirectory) - 1)>
-
- mov es,[Old1BHandlerSeg]
- mov bx,[Old1BHandlerOfs]
- SetVector 1Bh, es, bx
-
- mov ah, DOS_TERMINATE_EXE
- int DOS_FUNCTION
- endp Terminate
-
-
- proc Int1B far
-
- ; This procedure handles intercepting CTRL-BREAK so that the
- ; main directory searching loop can break out.
-
- mov [BreakPressed],1 ; Set break flag
- iret
-
- endp Int1B
-
-
-
- proc Initialize
-
- ; This procedure initializes all global variables and data structures
- ; used by the program.
- ;
- ; Input
- ; none
- ; Output
- ; none
- ; Calling conventions
- ; NA
- ; Registers modified
- ; ax, flags
-
- ; Store the PSP address by storing es in the variable PspAddress.
- ; Note that we do it this way instead of using DOS function 62h because
- ; the function is only available on DOS 3.0 or later.
-
- mov [PspAddress], es
-
- push ds
- GetCurrentDir <0>, <seg HomeDirectory>, <offset HomeDirectory>
- pop ds
- GetDrive ; Get the current disk drive
- mov [byte OldDrive], al ; Save it
-
-
- ; Install a control break handler.
- push ds
- mov ax,ds ; Save DS for future reference by break handler!
- mov [SavedDS],ax
- SetVector 23h,<seg Terminate>,<offset Terminate>
- ; mov ah,25h ; Int 25 = Set interrupt
- ; mov al,23h
- ; mov dx,seg Terminate
- ; mov ds,dx
- ; mov dx,offset Terminate
- ; int 21h
-
- ; Also, so the main loop for going thru directories can respond
- ; in a timely fashion to ctrl-break being pressed, install a
- ; handler for vector 1Bh.
-
- GetVector 1Bh
-
- pop ds
- mov [Old1BHandlerSeg],es
- mov [Old1BHandlerOfs],bx
- push ds
-
- SetVector 1Bh, <seg Int1B>, <offset Int1B>
-
- pop ds
-
-
- ; Verify that the user provided command line parameters.
-
- call ParamCount
- or al, al ; Were any parameters passed by user?
- jnz @@Exit
- call UsageScreen ; If no, display usage screen
-
- @@Exit:
-
- ret
- endp Initialize
-
-
- proc UsageScreen
-
- ; This routine displays a 'usage' screen that describes the syntax for
- ; using WHEREIS. It then terminates the program.
- ;
- ; Input
- ; ds - Points to data segment where usage screen text is located
- ; Output
- ; none
- ; Calling conventions
- ; NA
- ; Registers modified
- ; ax, cx, dx
-
- call WriteAsciizString,ds,offset Syntax
- call Terminate ; Terminate program
- endp UsageScreen
-
-
- proc PathAfterFirst
-
- ; This routine displays a 'usage' screen that tells the user that
- ; drive and path info may only be given on the first argument.
- ; It then terminates the program.
- ;
- ; Input
- ; ds - Points to data segment where usage screen text is located
- ; Output
- ; none
- ; Calling conventions
- ; NA
- ; Registers modified
- ; ax, cx, dx
-
- call WritePascalString,ds,offset OnlyFirst ;**2
- call Terminate ; Terminate program
- endp
-
-
- proc OnlyOneDosCommand
-
- ; This routine displays a 'usage' screen that tells the user that
- ; drive and path info may only be given on the first argument.
- ; It then terminates the program.
- ;
- ; Input
- ; ds - Points to data segment where usage screen text is located
- ; Output
- ; none
- ; Calling conventions
- ; NA
- ; Registers modified
- ; ax, cx, dx
-
- call WritePascalString,ds,offset OnlyOneCommand
- call Terminate ; Terminate program
- endp OnlyOneDosCommand
-
-
- endif ; ifndef MDL
-
- end EntryPoint
-