home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 September / Chip_2001-09_cd1.bin / zkuste / delphi / kolekce / d123456 / DFS.ZIP / MaskSearch.pas < prev    next >
Pascal/Delphi Source File  |  1998-12-10  |  5KB  |  186 lines

  1. {
  2.   Basic pattern matching.  Supports '*' and '?' only.
  3.  
  4.   This code is based on a unit by Markus Stephany (mirbir.st@t-online.de) that
  5.   I found on DSP (http://sunsite.icm.edu.pl/delphi/).  Please DO NOT email
  6.   Markus about any problems you may find in it.  All problems with it should be
  7.   reported to me, since I'm the last one who mucked with it.
  8.  
  9.   The original did a bunch of stuff that I didn't need (like searching inside
  10.   of files), didn't do some stuff that I did need (like handling spaces in the
  11.   filename), and had a few bugs, too.  In order to help me find the bugs more
  12.   quickly, I stripped out the stuff I didn't need, renamed things to be a little
  13.   more clear, and generally tried to clean up the mess that comes from stripping
  14.   out stuff you don't need.  :)
  15. }
  16. unit MaskSearch;
  17.  
  18. interface
  19.  
  20. uses
  21.   Classes, SysUtils;
  22.  
  23.  
  24. procedure BuildMask(Str: string; MaskList: TStringList);
  25.  
  26. function FileMatches(AFile: string; MaskList: TStringList): boolean;
  27.  
  28.  
  29. implementation
  30.  
  31.  
  32. // fills the grep_list with the parts of 's' (divided by ';')
  33. procedure BuildMask(Str: string; MaskList: TStringList);
  34. var
  35.   ct: integer;
  36. begin
  37.   MaskList.clear;
  38.   MaskList.sorted := false;
  39.   if Str = '' then
  40.   begin
  41.     MaskList.add('*');
  42.   end else begin
  43.     if Str[length(Str)] <> ';' then
  44.       Str := Str + ';';
  45.  
  46.     // divide the string
  47.     ct := Pos(';', Str);
  48.     while ct > 0 do
  49.     begin
  50.       MaskList.Add(AnsiLowerCase(Copy(Str, 1, ct-1)));
  51.       Delete(Str, 1, ct);
  52.       ct := Pos(';', Str);
  53.     end;
  54.  
  55.     MaskList.sorted := TRUE;
  56.     MaskList.duplicates := dupIgnore;
  57.   end;
  58. end;
  59.  
  60. // tests whether the string 'Str' fits to the search mask in 'Mask'
  61. function SimpleGrep(Str, Mask: string):boolean;
  62. var
  63.   sr, s2: string;
  64.   ps1,ps2,ps3: integer;
  65.   DontCare: boolean;
  66.   OneChar: char;
  67.   TmpList: TStringList;
  68. begin
  69.   if (Mask = '*') or // fits always
  70.      ((Mask = '*.*') and (Pos('.', Str) > 0)) then // always fits, too
  71.     Result := TRUE
  72.   else begin
  73.     if (Pos('*', Mask) = 0) and (Pos('?', Mask) = 0) and (Mask = Str) then
  74.       // searched text was found (searchstring IN text)
  75.       Result := TRUE
  76.     else begin
  77.       Result := FALSE;
  78.       if Mask = '' then
  79.         exit;
  80.  
  81.       TmpList := TStringList.Create;
  82.       try
  83.         // divide partial strings ('?','*' or text) to TmpList
  84.         repeat
  85.           OneChar := Mask[1];
  86.           if (OneChar in ['*', '?']) then
  87.           begin
  88.             TmpList.Add(OneChar);
  89.             Delete(Mask, 1, 1);
  90.           end else begin
  91.             ps1 := Pos('?', Mask);
  92.             if ps1 = 0 then
  93.               ps1 := MaxInt;
  94.             ps2 := Pos('*', Mask);
  95.             if ps2 = 0 then
  96.               ps2 := MaxInt;
  97.             if ps2 > ps1 then
  98.               ps2 := ps1;
  99.  
  100.             TmpList.Add(Copy(Mask, 1, ps2-1));
  101.             Delete(Mask, 1, ps2-1);
  102.           end;
  103.         until Mask = '';
  104.  
  105.         // now compare the string with the partial search masks
  106.         DontCare := FALSE;
  107.         ps2 := 1;
  108.         if TmpList.Count > 0 then
  109.         begin
  110.           for ps1 := 0 to pred(TmpList.Count) do
  111.           begin
  112.             sr := TmpList[ps1];
  113.             if sr = '?' then
  114.             begin
  115.               inc(ps2);
  116.               if ps2 > length(Str)+1 then
  117.                 exit;
  118.             end else begin
  119.               if sr = '*' then
  120.                 DontCare := TRUE
  121.               else begin
  122.                 if DontCare then
  123.                 begin
  124.                   if ps1 = pred(TmpList.Count) then
  125.                   begin
  126.                     s2 := Copy(Str, ps2, maxint);
  127.                     ps2 := length(Str); // just something to make the thing fail
  128.                     if Length(s2) >= Length(SR) then
  129.                       if sr = Copy(s2, Length(s2)-Length(SR)+1, MaxInt) then
  130.                         ps2 := length(Str) + 1;
  131.                   end else begin
  132.                     ps3:= Pos(sr, Copy(Str, ps2, maxint));
  133.                     if ps3 = 0 then
  134.                       exit;
  135.                     ps2 := ps2 + ps3 + length(sr) - 1;
  136.                   end;
  137.                   DontCare := FALSE;
  138.                 end else begin
  139.                   if Copy(Str, ps2, length(sr)) <> sr then
  140.                     exit;
  141.                   ps2 := ps2 + length(sr);
  142.                 end;
  143.               end;
  144.             end;
  145.           end;
  146.         end;
  147.  
  148.         if (not DontCare) and (ps2 <> length(Str)+1) then
  149.           Result := FALSE
  150.         else
  151.           Result := TRUE;
  152.       finally
  153.         TmpList.free;
  154.       end;
  155.     end;
  156.   end;
  157. end;
  158.  
  159. // tests whether the filename fits the search masks in MaskList
  160. function FileMatches(AFile: string; MaskList: TStringList): boolean;
  161. var
  162.   ct: integer;
  163. begin
  164.   AFile := AnsiLowerCase(AFile);
  165.   if (MaskList = NIL) or (MaskList.Count = 0) then
  166.     Result := TRUE // if no search AFileing, the always return TRUE
  167.   else begin
  168.     if Pos('.', AFile) = 0 then
  169.       AFile := AFile + '.'; // '.' is implied for filenames
  170.  
  171.     Result := FALSE;
  172.     // compare with the whole MaskList until one fits
  173.     for ct := 0 to Pred(MaskList.Count) do
  174.     begin
  175.       if SimpleGrep(AFile, MaskList[ct]) then
  176.       begin
  177.         Result := TRUE;
  178.         break;
  179.       end;
  180.     end;
  181.   end;
  182. end;
  183.  
  184.  
  185. end.
  186.