home *** CD-ROM | disk | FTP | other *** search
- {$I cpmswitc.inc}
-
- {--------------------------------------------------------------------------
-
- FINDER.PAS (Demonstration of the unit MTPipe)
-
- This program requires the CPMULTI Multitasking Toolkit and Turbo Pascal
- 5.0 or later.
-
- January 1994
-
- Copyright (C) 1994 (USA) Copyright (C) 1989-1994
- Hypermetrics Christian Philipps Software-Technik
- PO Box 9700 Suite 363 Duesseldorfer Str. 316
- Austin, TX 78758-9700 D-47447 Moers
- Germany
-
- The program Finder searches one or more disks with one or more search
- patterns given as command line parameters. For each pattern a separate
- task is started, so that individual searches run in parallel. There is a
- maximum of 10 search patterns which can be specified on the command line.
-
- Finder waits for a keystroke after each screenful of matches. During this
- time, however, the searches continue in the background so long as the pipe
- buffer is not yet full.
-
- --------------------------------------------------------------------------- }
-
- PROGRAM Finder;
-
- USES DOS, CRT, CPMulti, CPMisc, MTPipe;
-
- TYPE FileType = (Directory, NonDirectory);
- FMaskType = String[12];
- ErrorType = (ErrCreateSem, ErrAssignPipe,
- ErrRemoveSem, ErrCreateTask,
- ErrRewrite, ErrReset);
- ParmType = RECORD
- Ready : Pointer;
- Path : String;
- Mask : FMaskType;
- END;
- ParmPtr = ^ParmType;
-
- CONST FinderStackSize = 8000;
- PipeSize = 10000;
- MaxFinders = 10;
-
- VAR MainPipe : TEXT;
- DispSem : Pointer;
- FindSem : Pointer;
-
- {-----------------------------------------------------------------------------}
-
- PROCEDURE SafeFindFirst(Path:String; Attr:Word; VAR S:SearchRec);
- BEGIN
- SemWait(FindSem);
- FindFirst(Path,Attr,S);
- SemSignal(FindSem);
- END;
-
- {-----------------------------------------------------------------------------}
-
- PROCEDURE SafeFindNext(VAR S:SearchRec);
- BEGIN
- SemWait(FindSem);
- FindNext(S);
- SemSignal(FindSem);
- END;
-
- {-----------------------------------------------------------------------------}
-
- PROCEDURE FinderError(Err:ErrorType);
- BEGIN
- Write(^G'Finder: ');
- CASE Err OF
- ErrCreateSem: Writeln('Error in CreateSem');
- ErrRemoveSem: Writeln('Error in RemoveSem');
- ErrCreateTask: Writeln('Error in CreateTask');
- ErrAssignPipe: Writeln('Error in AssignPipe');
- ErrRewrite: Writeln('Error in Rewrite Pipe');
- ErrReset: Writeln('Error in Reset Pipe');
- ELSE
- Writeln('Unknown error (',Byte(Err),')!');
- END;
- Halt(1);
- END;
-
- {-----------------------------------------------------------------------------}
-
- PROCEDURE Display(FType:FileType; FName:String; VAR Pipe:TEXT);
-
- { Output of status messages over a pipe. The message consists of 3
- interrelated parts which makes the whole output operation atomic.
- Semaphore operation at the beginning and end of the procedure
- ensure that all 3 parts of the message are output together and in
- sequence.
-
- Note: This procedure uses standard PASCAL operations to write into
- the pipe. Things could be done simple by using the direct
- access functions.
- }
-
- BEGIN
- SemWait(DispSem);
- IF FType = Directory
- THEN Write(Pipe,'D ')
- ELSE Write(Pipe,'F ');
- WriteLn(Pipe,GetPID,' ',Fname);
- SemSignal(DispSem);
- END;
-
- {-----------------------------------------------------------------------------}
-
- PROCEDURE ScanFiles(Path:String; FileMask:FMaskType; VAR Pipe:TEXT);
-
- { Scan a directory for matching filenames }
-
- VAR S : SearchRec;
- BEGIN
- SafeFindFirst(Path+FileMask,$27,S);
- WHILE DosError=0 DO
- BEGIN
- Display(NonDirectory,Path+S.Name,Pipe);
- SafeFindNext(S);
- END;
- END;
-
- {-----------------------------------------------------------------------------}
-
- PROCEDURE ScanDirs(Path:String; FileMask:FMaskType; VAR Pipe:TEXT);
-
- { Recursively scan the whole directory tree }
-
- VAR S : SearchRec;
- BEGIN
- SafeFindFirst(Path+'*.*',$10,S);
- WHILE DosError=0 DO
- BEGIN
- IF (S.Name[1] <> '.') AND (S.Attr = $10)
- THEN BEGIN
- Display(Directory,Path+S.Name,Pipe);
- ScanFiles(Path+S.Name+'\',FileMask,Pipe);
- ScanDirs(Path+S.Name+'\',FileMask,Pipe);
- END;
- SafeFindNext(S);
- END;
- END;
-
- {-----------------------------------------------------------------------------}
-
- {$F+}
- PROCEDURE FindTask(P:Pointer);
-
- { This is the task body for the search tasks.
- Each task opens its own communication channel through the pipe "Finder."
- After that it recursively scans the directory tree with the given
- search pattern. Status messages are passed to the output process
- by means of the procedure "Diskplay" in the main program (via pipe).
-
- After successful completion of the work, the task closes its side of the
- pipe and terminates. After all writing tasks, i. e. all search tasks
- have terminated, the main program which is reading the pipe will return
- an error return which signals EOF.
- }
-
- VAR Parms: ParmPtr absolute P;
- Pipe : TEXT;
- Path : String;
- Mask : FMaskType;
-
- BEGIN
- IF Not AssignPipe(Pipe,'Finder',0,0,NoWait)
- THEN FinderError(ErrAssignPipe);
- Rewrite(Pipe);
- IF IoResult <> 0
- THEN FinderError(ErrRewrite);
- Path := Parms^.Path;
- Mask := Parms^.Mask;
- SemSignal(Parms^.Ready);
- ScanFiles(Path,Mask,Pipe);
- ScanDirs(Path,Mask,Pipe);
- Display(Directory,'--- Finished! ---',Pipe);
- Close(Pipe);
- END;
- {$F-}
-
- {-----------------------------------------------------------------------------}
-
- FUNCTION StartFinder:Byte;
-
- { For every command line parameter, a separate process is started.
- The procedure FindTask comprises the task body for ALL of these processes.
- StartFinder also creates a semaphore necessary (to the procedure
- "Display") for access synchronization.
- StartFinder returns as a function value the number of the first task started.
- This value is needed for the calculation of the output positions inside
- "ProcessOutput."
- }
-
- VAR N : Byte;
- P : Byte;
- Parms : ParmType;
- T : TaskNoType;
-
- BEGIN
- IF CreateSem(DispSem) <> Sem_OK
- THEN FinderError(ErrCreateSem);
-
- IF CreateSem(FindSem) <> Sem_OK
- THEN FinderError(ErrCreateSem);
-
- IF CreateSem(Parms.Ready) <> Sem_OK
- THEN FinderError(ErrCreateSem);
- FOR N := 1 TO Min(ParamCount,MaxFinders) DO
- WITH Parms DO
- BEGIN
- Path := ParamStr(n);
- P := Byte(Path[0]);
- WHILE (P > 0) AND (Path[P] <> '\') AND (Path[P] <> ':') DO
- Dec(P);
- IF P = 0
- THEN BEGIN
- Mask := Path;
- Path := '\';
- END
- ELSE BEGIN
- Mask := Copy(Path,P+1,255);
- Delete(Path,P+1,255);
- IF Path[P] = ':'
- THEN Path := Path+'\';
- END;
- SemClear(Ready);
- T := CreateTask(FindTask,@Parms,Pri_User,FinderStackSize);
- IF T < 0
- THEN FinderError(ErrCreateTask);
- IF N = 1 { return ID of first task }
- THEN StartFinder := T;
- SemWait(Ready);
- END;
- IF RemoveSem(Parms.Ready) <> Sem_OK
- THEN FinderError(ErrRemoveSem);
- END;
-
- {-----------------------------------------------------------------------------}
-
- PROCEDURE ProcessOutput(BaseNo:TaskNoType; NoOfTasks:Byte);
-
- { This procedure reads messages from the pipe and displays them on
- the screen.
- Each message consists of three parts:
- 1. A letter giving the type of message: (D)irectory or (F)ile
- 2. The ID of the sender
- 3. A Pathname of a currently searched directory or a matching file
- These message segments are separated by a blank (see also "Display").
-
- The whole content of the pipe is read inside the main loop of this
- procedure. An error return from the read of the first message segment
- indicates that no more writing processes exist.
- }
-
- VAR N : Byte;
- BotL : Byte;
- Typ : Char;
- Task : Byte;
- Path : String;
- Hits : Word;
- Sep : String[80];
- C : Char;
- Ende : Boolean;
-
- BEGIN
- Hits := 0;
- Ende := False;
-
- ClrScr;
- TextColor(0);
- TextBackground(7);
- GotoXY(1,1);
- ClrEol;
- GotoXY(17,1);
- Write('>> Finder V1.0 (c) Christian Philipps, April 1990 <<');
- TextColor(7);
- TextBackground(0);
-
- BotL := 25-NoOfTasks-1;
- FillChar(Sep,sizeof(Sep),'-');
- Sep[0] := #80;
- GotoXY(1,BotL+1);
- Write(Sep);
- Reset(MainPipe);
- IF IoResult <> 0
- THEN FinderError(ErrReset);
- Read(MainPipe,Typ);
- Read(MainPipe,Task);
- ReadLn(MainPipe,Path);
- Ende := IOResult <> 0;
- WHILE NOT Ende DO
- BEGIN
- IF Typ = 'D'
- THEN BEGIN
- GotoXY(1,BotL+2+Task-BaseNo);
- ClrEol;
- END
- ELSE BEGIN
- Inc(Hits);
- IF (Hits MOD BotL) = 0
- THEN BEGIN
- GotoXY(20,BotL+1);
- Write(' Press Return to continue, Escape to exit. ');
- REPEAT
- WHILE NOT Keypressed DO
- Sleep(1);
- C := ReadKey;
- UNTIL C IN [#27,#13];
- IF C = #27
- THEN Halt(1);
- GotoXY(1,BotL+1);
- Write(Sep);
- END;
- GotoXY(1,2);
- DelLine;
- GotoXY(1,BotL);
- InsLine;
- END;
- Write(Task:2,': ',Copy(Path,1,75));
- Read(MainPipe,Typ);
- Ende := IOResult <> 0;
- IF NOT Ende
- THEN BEGIN
- Read(MainPipe,Task);
- ReadLn(MainPipe,Path);
- END;
- END;
- Close(MainPipe);
- GotoXY(20,BotL+1);
- Write(' ',Hits,' Matches! - Press any key to continue. ');
- IF ReadKey = #0 THEN;
- END;
-
- {-----------------------------------------------------------------------------}
-
- BEGIN
- IF ParamCount < 1
- THEN BEGIN
- Writeln('Finder V1.00 / Ch. Philipps');
- Writeln('> Finder pattern [...]');
- Writeln;
- Writeln('Finder recursively scans the directory tree looking for');
- Writeln('filenames matching the pattern. If no path is contained');
- Writeln('in the pattern, the search starts at the root directory!');
- Writeln('At max ',MaxFinders,' pattern may be given on the command line.');
- Writeln;
- Writeln('Example: Finder C:*.sys D:*.sys');
- Writeln(' Scan disks C and D starting at \ for files');
- Writeln(' with the extension .SYS');
- Halt(1);
- END;
-
- SpeedUp(3);
- TimeSlice(1,5);
- SetPri(Pri_User+1);
- IF Not AssignPipe(MainPipe,'Finder',PipeSize,0,NoWait)
- THEN FinderError(ErrAssignPipe);
- ProcessOutput(StartFinder,Min(ParamCount,MaxFinders));
- END.
-