home *** CD-ROM | disk | FTP | other *** search
- {--------------------------------------------------------------}
- { LOCATE }
- { }
- { Disk file tree-search search utility }
- { }
- { by Jeff Duntemann }
- { Turbo Pascal V5.0 }
- { Last update 5/22/88 }
- { }
- { This utility searches a tree of directories (from the root }
- { or from any child directory of the root) for a given file }
- { spec, either unique or ambiguous. It provides a good }
- { example of the use of the DOS 2.X/3.X FIND FIRST/NEXT }
- { function calls. See the main program block for instructions }
- { on its use. }
- { }
- { From: COMPLETE TURBO PASCAL 5.0 by Jeff Duntemann }
- { Scott, Foresman & Co., Inc. 1988 ISBN 0-673-38355-5 }
- {--------------------------------------------------------------}
-
- PROGRAM Locate;
-
- USES DOS;
-
- TYPE
- String80 = String[80];
- String15 = String[15];
-
- {$I TIMEREC.DEF} { Described in Section 20.6 }
- {$I DATEREC.DEF} { Described in Section 20.6 }
- {$I DIRREC.DEF} { Described in Section 20.7 }
-
- DTAPtr = ^SearchRec;
-
-
- VAR
- I,J : Integer;
- SearchSpec : String80;
- InitialDirectory : String80;
- Searchbuffer : SearchRec;
-
-
- {$I DAYOWEEK.SRC} { Described in Section 20.6 }
- {$I CALCDATE.SRC} { Described in Section 20.6 }
- {$I CALCTIME.SRC} { Described in Section 20.6 }
- {$I DIRSTRIN.SRC} { Described in Section 20.7 }
- {$I DTATODIR.SRC} { Described in Section 20.7 }
-
-
- {->>>>SearchDirectory<<<<--------------------------------------}
- { }
- { This is the real meat of program LOCATE. The machinery }
- { for using FIND FIRST and FIND NEXT are placed in a procedure }
- { so that it may be recursively called. Recursion is used }
- { because it is the most elegant way to search a tree, which }
- { is really all we're doing here. All the messiness (and it }
- { IS messy!) exists to cater to DOS's peculiarities. }
- { }
- { For example, note that each recursive instantiation of }
- { SearchDirectory needs its own DTA. No problem--one is }
- { created on the stack each time SearchDirectory is called. }
- { BUT--DOS is not a party to the recursion, so the DTA address }
- { must be set both before AND after the recursive call, so }
- { that once control comes BACK to an instance of }
- { SearchDirectory that has been left via recursion, DOS can }
- { "come back" to the temporarily dormant DTA, which may still }
- { contain information necessary to execute a FIND NEXT call. }
- { }
- { Much of the rest of the fooling around involves formatting }
- { the search strings correctly for passing to the next }
- { instantiation of SearchDirectory. }
- { }
- { It's not documented, but I have found that DOS returns error }
- { code 3 (Bad Path) on a file FIND when the path includes a }
- { nonexistant directory name. Error code 2, on the other }
- { hand, while documented, never seems to come up at all. }
- {--------------------------------------------------------------}
-
-
- PROCEDURE SearchDirectory(Directory,SearchSpec : String);
-
- VAR
- NextDirectory : String;
- TempDirectory : String;
- CurrentDTA : SearchRec;
- CurrentDIR : DIRRec;
- Regs : Registers;
-
-
- {>>>>DisplayData<<<<}
- { Displays file data and full path for the passed file }
-
- PROCEDURE DisplayData(Directory : String; CurrentDIR : DIRRec);
-
- VAR
- Temp : String;
-
- BEGIN
- Temp := DIRToString(CurrentDIR);
- Delete(Temp,1,13);
- Write(Temp,Directory);
- IF Directory <> '\' THEN Write('\');
- Writeln(CurrentDIR.FileName);
- END;
-
-
-
- BEGIN
- { First we look for any subdirectories. If any are found, }
- { we make a recursive call and search 'em too: }
-
- { Suppress unnecessary backslashes if we're searching the root: }
- IF Directory = '\' THEN
- TempDirectory := Directory + '*.*'
- ELSE
- TempDirectory := Directory + '\*.*';
-
- { Now make the FIND FIRST call for directories: }
-
- FindFirst(TempDirectory,$10,CurrentDTA);
-
-
- { Here's the tricky stuff. If we get an indication that there is }
- { at least one more subdirectory within the current directory, }
- { (indicated by lack of error codes 2 or 18) we must search it }
- { by making a recursive call to SearchDirectory. We continue }
- { recursing and returning from the searched subdirectories until }
- { we get a code indicating none are left. }
- WHILE (DOSError <> 2) AND (DOSError <> 18) DO
- BEGIN
- IF ((CurrentDTA.Attr AND $10) = $10) { If it's a directory }
- AND (CurrentDTA.Name[1] <> '.') THEN { and not '.' or '..' }
- BEGIN
- { Add a slash separating sections of the path if we're not }
- { currently searching the root: }
- IF Directory <> '\' THEN NextDirectory := Directory + '\'
- ELSE NextDirectory := Directory;
-
- { This begins with the current directory name, and copies }
- { the name of the found directory from the current DTA to }
- { the end of the current directory string. Then the new }
- { path is passed to the next recursive instantiation of }
- { SearchDirectory. }
- NextDirectory := NextDirectory + CurrentDTA.Name;
-
- { Here's where we call "ourselves." }
- SearchDirectory(NextDirectory,SearchSpec);
-
- END;
- FindNext(CurrentDTA); { Now we look for more... }
- END;
-
- { Now we can search for files, once we've run out of directories. }
- { This is conceptually simpler, as recursion is not involved. }
- { We combine the path and the file spec into one string, and make }
- { the FIND FIRST call: }
-
- { Suppress unnecessary slashes for root search: }
- IF Directory <> '\' THEN
- TempDirectory := Directory + '\' + SearchSpec
- ELSE TempDirectory := Directory + SearchSpec;
-
- { Now, make the FIND FIRST call: }
- FindFirst(TempDirectory,$07,CurrentDTA);
-
- IF DOSError = 3 THEN { Bad path error }
- Writeln('Path not found; check spelling.')
-
- { If we found something in the current directory matching the filespec, }
- { format it nicely into a single string and display it: }
- ELSE IF (DOSError = 2) OR (DOSError = 18) THEN
- { Null; Directory is empty }
- ELSE
- BEGIN
- DTAtoDIR(CurrentDIR); { Convert first find to DIR format.. }
- DisplayData(Directory,CurrentDIR); { Show it pretty-like }
-
- IF DOSError <> 18 THEN { More files are out there... }
- REPEAT
- FindNext(CurrentDTA);
- IF DOSError <> 18 THEN { More entries exist }
- BEGIN
- DTAtoDIR(CurrentDIR); { Convert further finds to DIR format }
- DisplayData(Directory,CurrentDIR) { and display 'em }
- END
- UNTIL (DOSError = 18) OR (DOSError = 2) { Ain't no more! }
- END
- END;
-
-
- BEGIN
- IF ParamCount = 0 THEN
- BEGIN
- Writeln('>>LOCATE<< V2.00 By Jeff Duntemann');
- Writeln(' From the book, COMPLETE TURBO PASCAL 5.0');
- Writeln(' Scott, Foresman & Co. 1988');
- Writeln(' ISBN 0-673-38355-5');
- Writeln;
- Writeln('This program searches for all files matching a given ');
- Writeln('filespec on the current disk device, in any subdirectory.');
- Writeln('Now that 32MB disks are getting cheap, we can pile up');
- Writeln('great heaps of files and easily forget where we put things.');
- Writeln('Given only the filespec, LOCATE prints out the FULL PATH');
- Writeln('of any file matching that filespec.');
- Writeln;
- Writeln('CALLING SYNTAX:');
- Writeln;
- Writeln('LOCATE <filespec>');
- Writeln;
- Writeln('For example, to find out where your screen capture files');
- Writeln('(ending in .CAP) are, you would enter:');
- Writeln;
- Writeln('LOCATE *.CAP');
- Writeln;
- Writeln('and LOCATE will show the pathname of any file ending in .CAP.');
- END
- ELSE
- BEGIN
- Writeln;
- SearchSpec := ParamStr(1);
- { A "naked" filespec searches the entire volume: }
- IF Pos('\',SearchSpec) = 0 THEN
- SearchDirectory('\',SearchSpec)
- ELSE
- BEGIN
- { This rigamarole separates the filespec from the path: }
- I := Length(SearchSpec);
- WHILE SearchSpec[I] <> '\' DO I := Pred(I);
- InitialDirectory := Copy(SearchSpec,1,I-1);
- Delete(SearchSpec,1,I);
- SearchDirectory(InitialDirectory,SearchSpec);
- END;
- END
- END.