home *** CD-ROM | disk | FTP | other *** search
/ Turbo Toolbox / Turbo_Toolbox.iso / 1989 / 11 / praxis / search.pas < prev   
Encoding:
Pascal/Delphi Source File  |  1989-02-21  |  12.2 KB  |  399 lines

  1. (* ------------------------------------------------------ *)
  2. (*                    SEARCH.PAS                          *)
  3. (* Dateisuche nach Suffix, Attributen, Größe, Datum, Zeit *)
  4. (*     (c) 1989   TOOLBOX  &  Karsten Gieselmann          *)
  5. (* ------------------------------------------------------ *)
  6. {$R-,S-,I-,V-,B-,N-}    (* größtmögliche Geschwindigkeit! *)
  7. {$M 16384, 0, 0}
  8.  
  9. PROGRAM Search;
  10.  
  11. USES
  12.   Dos;                                 (* benötigte Units *)
  13.  
  14. VAR
  15.   Dir,                    (* Name des Startverzeichnisses *)
  16.   FileMask         : STRING;   (* zu suchende Dateigruppe *)
  17.   AttrMask         : WORD;             (* Attributvorgabe *)
  18.   EntriesFound,          (* Anzahl der gefundenen Dateien *)
  19.   MinSize,MaxSize,                 (* Dateigrößen-Bereich *)
  20.   MinTime,MaxTime  : LONGINT;      (* Datum-/Zeit-Bereich *)
  21.   FullDisplay      : BOOLEAN;
  22.                      (* Anzeige: nur Dateiname oder mehr? *)
  23.  
  24. (*  gibt einen Dateieintrag auf die Standardausgabe aus   *)
  25.  
  26. PROCEDURE DisplayEntry(Path : STRING; Entry : SearchRec);
  27. VAR
  28.   DT : DateTime;
  29.   k  : BYTE;
  30.  
  31.   FUNCTION Str(Value : LONGINT; Len : BYTE;
  32.                FillZeroes : Boolean) : STRING;
  33.     (* verwandelt eine Zahl in eine Zeichenkette und füllt
  34.        die restlichen Positionen mit Leerzeichen bzw. mit
  35.        Nullen (FillZeroes=TRUE) aus. *)
  36.   VAR
  37.     V : STRING;
  38.     k : BYTE;
  39.   BEGIN
  40.     System.Str(Value:Len, V);
  41.     If FillZeroes THEN
  42.       FOR k:=1 TO Len DO
  43.         IF V[k]=' ' THEN V[k] := '0';
  44.     Str := V;
  45.   END;
  46.  
  47. BEGIN
  48.   Inc(EntriesFound);
  49.   WITH Entry DO
  50.     IF FullDisplay THEN BEGIN
  51.       k := 1;
  52.       WHILE (k <= Length(Name)) AND
  53.             (Name[k] <> '.') DO BEGIN
  54.         Write(Name[k]);
  55.         Inc(k);
  56.       END;
  57.       IF Name[k] = '.' THEN
  58.         Write('':10-k, Copy(Name, k+1, 3),
  59.               '':k+3-Length(Name))
  60.       ELSE
  61.         Write('':13-k);
  62.       UnPackTime(Time, DT); Dec(DT.Year, 1900);
  63.       WITH DT DO
  64.         WriteLn(Size:9, '':2,
  65.                 Str(Day,  2, FALSE), '.',
  66.                 Str(Month,2,  TRUE), '.',
  67.                 Str(Year, 2,  TRUE), '  ',
  68.                 Str(Hour, 2, FALSE), ':',
  69.                 Str(Min,  2,  TRUE))
  70.     END ELSE
  71.       WriteLn(Path, Name);
  72.   END;
  73.  
  74.  
  75. (* Absuchen von "Path" und aller zugehörigen
  76.                                       Unterverzeichnisse  *)
  77. PROCEDURE ScanDir(Path : STRING);
  78. VAR
  79.   Entry : SearchRec;
  80. BEGIN
  81.   WITH Entry DO BEGIN
  82.     FindFirst(Path+FileMask, $27 OR AttrMask, Entry);
  83.     WHILE DosError = 0 DO BEGIN
  84.       IF Attr AND AttrMask = AttrMask THEN
  85.         IF (MinSize <= Size) AND (Size <= MaxSize) THEN
  86.           IF (MinTime <= Time) AND (Time <= MaxTime) THEN
  87.             IF (Name[1] <> '.') THEN
  88.               DisplayEntry(Path, Entry);
  89.       FindNext(Entry);
  90.     END;
  91.     FindFirst(Path+'*.*', Directory, Entry);
  92.     WHILE DosError = 0 DO BEGIN
  93.       IF Attr AND Directory = Directory THEN
  94.         IF (Name[1] <> '.') THEN
  95.                                (* '.' und '..' ignorieren *)
  96.           ScanDir(Path+Name+'\');
  97.                               (* Bearbeitung der Einträge *)
  98.       FindNext(Entry);
  99.     END;
  100.   END;
  101. END;
  102.  
  103. (* ----- Auslesen und Auswerten der Kommandozeile ------- *)
  104.  
  105. PROCEDURE ParseArguments;
  106.  
  107. CONST
  108.   AttrError     = 'Unbekanntes Attribut in Parameterliste';
  109.   SizeError     = 'Ungültige Dateigrößenangabe';
  110.   DateTimeError = 'Ungültige Datum-Zeit-Angabe';
  111.   PeriodError   = 'Ungültige Zeitspannen-Angabe';
  112.  
  113. VAR
  114.   s,ErrorMessage,
  115.   Lower,Upper    : STRING;
  116.   Params         : ^STRING;
  117.   k              : BYTE;
  118.  
  119.   PROCEDURE ErrorHalt;
  120.     (* Ausgabe einer Fehlermeldung und Programmabbruch *)
  121.   BEGIN
  122.     WriteLn(ErrorMessage); Halt;
  123.   END;
  124.  
  125.   FUNCTION Stripped(S : STRING) : STRING;
  126.     (* entfernt führende und folgende Leerzeichen *)
  127.   VAR
  128.     a,b : BYTE;
  129.   BEGIN
  130.     a := 1;  b := Length(S);
  131.     WHILE (a <= b) AND (S[a] = ' ') DO Inc(a);
  132.     WHILE (b >= 1) AND (S[b] = ' ') DO Dec(b);
  133.     Stripped := Copy(S, a, b-a+1);
  134.   END;
  135.  
  136.   FUNCTION Argument(Switch : CHAR) : STRING;
  137.     (* liefert den Argumentstring zu "Switch" *)
  138.   VAR
  139.     a,b : BYTE;
  140.   BEGIN
  141.     a := Pos('/'+Switch, Params^);
  142.     IF a > 0 THEN BEGIN
  143.       b := a + 2;
  144.       WHILE (b <= Length(Params^)) AND
  145.             (Params^[b] <> '/') DO Inc(b);
  146.       Argument := Stripped(Copy(Params^, a+2, b-(a+2)));
  147.     END ELSE
  148.       Argument := '';
  149.   END;
  150.  
  151.   FUNCTION ParseAttributes : WORD;
  152.     (* Besetzung der Attributmaske gemäß
  153.                                   Kommandozeilenparameter *)
  154.   CONST
  155.     Attributes : ARRAY[1..6] OF CHAR = 'RHSVDA';
  156.   VAR
  157.     k,m,p : BYTE;
  158.     a     : STRING;
  159.   BEGIN
  160.     m := $00;
  161.     a := Argument('A');
  162.     IF a <> '' THEN
  163.       FOR k := 1 TO Length(a) DO BEGIN
  164.         p := Pos(a[k], Attributes);
  165.         IF p > 0 THEN
  166.           m := m OR (1 SHL (p-1))
  167.         ELSE
  168.           ErrorHalt;
  169.       END;
  170.     ParseAttributes := m;
  171.   END;
  172.  
  173.   PROCEDURE ParseRange(Range : STRING;
  174.                        VAR Left, Right : STRING);
  175.     (* zerlegt eine Bereichsangabe "aa,bb" in oberen
  176.                                          und unteren Teil *)
  177.   VAR
  178.     p : BYTE;
  179.   BEGIN
  180.     p := Pos(',', Range);
  181.     IF p > 0 THEN BEGIN           (* echte Bereichsangabe *)
  182.       Left := Stripped(Copy(Range, 1, p-1));
  183.       Right := Stripped(Copy(Range, p+1, 255));
  184.     END ELSE BEGIN       (* nur ein Wert, Left=Right=Wert *)
  185.       Left := Range;
  186.       Right := Left;
  187.     END;
  188.   END;
  189.  
  190.   FUNCTION ParseSize(Size : STRING;
  191.                      DefSize : LONGINT) : LONGINT;
  192.     (* liefert LONGINT-Zahl;
  193.               wenn Size leer ist, wird DefSize angenommen *)
  194.   VAR
  195.     Value  : LONGINT;
  196.     Result : INTEGER;
  197.   BEGIN
  198.     IF Size <> '' THEN BEGIN
  199.       Val(Size, Value, Result);
  200.       IF Result <> 0 THEN
  201.         ErrorHalt;
  202.       ParseSize := Value;
  203.     END ELSE
  204.       ParseSize := DefSize;
  205.   END;
  206.  
  207.   PROCEDURE ParseNumber(VAR s : STRING; Seperator : CHAR;
  208.                                         VAR Number : WORD);
  209.    (* wandelt den Teilstring von s bis zum ersten Auftreten
  210.       von Seperator in eine ganze Zahl um; bei Mißerfolg
  211.       erfolgt Fehlermeldung/Abbruch. *)
  212.   VAR
  213.     p      : BYTE;
  214.     Result : INTEGER;
  215.     SubStr : STRING;
  216.   BEGIN
  217.     IF Seperator = ' ' THEN
  218.       SubStr := s
  219.     ELSE BEGIN
  220.       p := Pos(Seperator, s);
  221.       IF p = 0 THEN
  222.         Exit;
  223.       SubStr := Copy(s, 1, p-1);
  224.       Delete(s, 1, p);
  225.     END;
  226.     IF SubStr <> '' THEN BEGIN
  227.       Val(SubStr, Number, Result);
  228.       IF Result <> 0 THEN
  229.         ErrorHalt;
  230.     END;
  231.   END;
  232.  
  233.   FUNCTION ParseDateTime(DateTimeStr : STRING;
  234.                           UpperBound : BOOLEAN) : LONGINT;
  235.    (* konvertiert eine als Zeichenkette vorliegenden
  236.       Datum-/Zeitangabe "DD.MM.YY HH:MM" in das von DOS
  237.       benutzte gepackte Format (LONGINT); je nachdem, ob es
  238.       sich bei der Zeitangabe um die obere oder untere
  239.       Begrenzung eines Abschnitts handelt, werden anstelle
  240.       fehlender Angaben gewisse Standardeinstellungen
  241.       angenommen.                    *)
  242.   VAR
  243.     DT        : DateTime;
  244.     b,d,t     : BYTE;
  245.     Dummy     : WORD;
  246.     p         : LONGINT;
  247.     Date,Time : STRING;
  248.   BEGIN
  249.     d := Pos('.', DateTimeStr);
  250.     t := Pos(':', DateTimeStr);
  251.     WITH DT DO BEGIN                  (* Voreinstellungen *)
  252.       IF UpperBound THEN BEGIN
  253.         Sec := 59;
  254.         GetDate(Year, Month, Day, Dummy);
  255.         IF d > 0 THEN BEGIN
  256.           Hour := 23; Min := 59;
  257.         END ELSE
  258.           GetTime(Hour, Min, Dummy, Dummy);
  259.       END ELSE BEGIN
  260.         IF t > 0 THEN
  261.           GetDate(Year, Month, Day, Dummy)
  262.         ELSE BEGIN
  263.           Year := 1980; Month := 1; Day := 1;
  264.         END;
  265.         Hour := 0; Min := 0; Sec := 0;
  266.       END;
  267.       IF d > 0 THEN
  268.         GetDate(Year, Dummy, Dummy, Dummy);
  269.       b := Pos(' ', DateTimeStr);
  270.       IF b > 0 THEN BEGIN
  271.         Date := Stripped(Copy(DateTimeStr, 1, b-1));
  272.         Time := Stripped(Copy(DateTimeStr, b+1, 255));
  273.       END ELSE
  274.         IF d > 0 THEN BEGIN
  275.           Date := DateTimeStr;
  276.           Time := '';
  277.         END ELSE BEGIN
  278.           Date := '';
  279.           Time := DateTimeStr;
  280.         END;
  281.       ParseNumber(Date, '.', Day);
  282.       ParseNumber(Date, '.', Month);
  283.       ParseNumber(Date, ' ', Year);
  284.       IF (80 <= Year) AND (Year <= 99) THEN Inc(Year, 1900);
  285.       ParseNumber(Time, ':', Hour);
  286.       ParseNumber(Time, ' ', Min);
  287.       IF (Min > 60) OR (Hour > 24) OR (Day > 31)
  288.                                    OR (Month > 12) THEN
  289.         ErrorHalt;
  290.     END;
  291.     PackTime(DT, p);
  292.     ParseDateTime := p;
  293.   END;
  294.  
  295.   FUNCTION SubtractPeriod(Period : STRING) : LONGINT;
  296.    (* subtrahiert die durch "Period" gegebene Zeitspanne
  297.       HH:MM von der aktuellen Uhrzeit und liefert den
  298.       entsprechenden gepackten Wert. Um das Problem der
  299.       Zeitrückrechnung (extremes Beispiel: 01.01.89,
  300.       00:05 minus 10 Minuten) nicht zu sehr in den
  301.       Vordergrund treten zu lassen, werden nur Tageswechsel
  302.       berücksichtigt.                      *)
  303.   VAR
  304.     DT               : DateTime;
  305.     Hour,Min,Dummy   : WORD;
  306.     cYear,cMonth,
  307.     cDay, cHour,cMin : INTEGER;
  308.     p                : LONGINT;
  309.   BEGIN
  310.     ParseNumber(Period, ':', Hour);
  311.     ParseNumber(Period, ' ', Min);
  312.     IF Hour*60+Min > 1440 THEN ErrorHalt;
  313.     GetDate(WORD(cYear), WORD(cMonth), WORD(cDay), Dummy);
  314.     GetTime(WORD(cHour), WORD(cMin), Dummy, Dummy);
  315.     Dec(cMin, Min);
  316.     IF cMin < 0 THEN BEGIN
  317.       Inc(cMin, 60); Dec(cHour);
  318.     END;
  319.     Dec(cHour, Hour);
  320.     IF cHour < 0 THEN BEGIN
  321.       Inc(cHour, 24); Dec(cDay);
  322.     END;
  323.     WITH DT DO BEGIN
  324.       Year := cYear; Month := cMonth; Day := cDay;
  325.       Hour := cHour; Min := cMin; Sec := 59;
  326.       PackTime(DT, p);
  327.     END;
  328.     SubtractPeriod := p;
  329.   END;
  330.  
  331. BEGIN
  332.   IF (ParamCount = 0) OR (ParamStr(1)='?') THEN BEGIN
  333.                                     (* Hilfetext ausgeben *)
  334.     WriteLn(^M^J,
  335.       'SEARCH v1.0'^M^J^M^J,
  336.       'Syntax:   SEARCH  Suchmaske  [Optionen]  [>Output]',
  337.       ^M^J^M^J,'Optionen:'^M^J,
  338.       '  /F(ull display)  zusätzliche Anzeige von Größe, ',
  339.       'Datum und Zeit'^M^J,
  340.       '  /C(urrent dir)   beginnt die Suche im aktuellen ',
  341.       'Verzeichnis'^M^J,
  342.       '  /A(ttr mask)     Attribut-Liste (ADHRS)'^M^J,
  343.       '  /S(ize mask)     nnn,mmm'^M^J,
  344.       '  /P(eriod mask)   HH:MM'^M^J,
  345.       '  /T(ime mask)     DD.MM.YY HH:MM, DD.MM.YY HH:MM');
  346.     Halt;
  347.   END;
  348.   Params := Ptr(PrefixSeg, $80);
  349.                               (* Zeiger auf Kommandozeile *)
  350.   FOR k:=1 TO Length(Params^) DO
  351.     Params^[k] := UpCase(Params^[k]);
  352.   IF Copy(ParamStr(1), 1, 1) = '/' THEN
  353.     FileMask := '*.*'    (* keine Angabe: alle Dateinamen *)
  354.   ELSE
  355.     FileMask := ParamStr(1);                (* Dateimaske *)
  356.   ErrorMessage := AttrError;
  357.   AttrMask := ParseAttributes;
  358.   FullDisplay := Pos('/F', Params^) > 0;
  359.                                        (* Art der Ausgabe *)
  360.   IF Pos('/C', Params^) > 0 THEN
  361.     GetDir(0, Dir)
  362.               (* Durchsuchen ab dem aktuellem Verzeichnis *)
  363.   ELSE
  364.     Dir := '';
  365.            (* Durchsuchen aller vorhandenen Verzeichnisse *)
  366.   s := Argument('S');                (* Dateigrößen-Maske *)
  367.   ErrorMessage := SizeError;
  368.   ParseRange(s, Lower, Upper);
  369.   MinSize := ParseSize(Lower, 0);
  370.   MaxSize := ParseSize(Upper, $7FFFFFFF);
  371.   s := Argument('P');                 (* Datum-Zeit-Maske *)
  372.   IF s <> '' THEN BEGIN        (* relative Bereichsangabe *)
  373.     ErrorMessage := PeriodError;
  374.     MinTime := SubtractPeriod(s);
  375.     MaxTime := ParseDateTime('', TRUE);
  376.   END ELSE BEGIN               (* absolute Bereichsangabe *)
  377.     s := Argument('T');
  378.     ErrorMessage := DateTimeError;
  379.     ParseRange(s, Lower, Upper);
  380.     MinTime := ParseDateTime(Lower, FALSE);
  381.     MaxTime := ParseDateTime(Upper, TRUE);
  382.   END;
  383. END;
  384.  
  385. BEGIN                                    (* Hauptprogramm *)
  386.   ParseArguments;
  387.   EntriesFound := 0;
  388.   ScanDir(Dir+'\');
  389.   IF FullDisplay THEN BEGIN
  390.     WriteLn;
  391.     IF EntriesFound = 0 THEN
  392.       Write('Keine')
  393.     ELSE
  394.       Write(EntriesFound);
  395.     WriteLn(' Einträge gefunden.');
  396.   END;
  397. END.
  398. (* ------------------------------------------------------ *)
  399. (*                 Ende von SEARCH.PAS                    *)