home *** CD-ROM | disk | FTP | other *** search
/ Chip 2001 October / Chip_2001-10_cd1.bin / zkuste / delphi / kompon / d56 / MSYSINFO.ZIP / Borland / Delphi5 / masks.pas < prev   
Pascal/Delphi Source File  |  1999-08-11  |  7KB  |  313 lines

  1. {*******************************************************}
  2. {                                                       }
  3. {       Borland Delphi Visual Component Library         }
  4. {                                                       }
  5. {       Copyright (c) 1995,99 Inprise Corporation       }
  6. {                                                       }
  7. {*******************************************************}
  8.  
  9. unit Masks;
  10.  
  11. interface
  12.  
  13. type
  14.   TMask = class
  15.   private
  16.     FMask: Pointer;
  17.     FSize: Integer;
  18.   public
  19.     constructor Create(const MaskValue: string);
  20.     destructor Destroy; override;
  21.     function Matches(const Filename: string): Boolean;
  22.   end;
  23.  
  24. function MatchesMask(const Filename, Mask: string): Boolean;
  25.  
  26. implementation
  27.  
  28. uses SysUtils, Consts;
  29.  
  30. const
  31.   MaxCards = 30;
  32.  
  33. type
  34.   PMaskSet = ^TMaskSet;
  35.   TMaskSet = set of Char;
  36.   TMaskStates = (msLiteral, msAny, msSet, msMBCSLiteral);
  37.   TMaskState = record
  38.     SkipTo: Boolean;
  39.     case State: TMaskStates of
  40.       msLiteral: (Literal: Char);
  41.       msAny: ();
  42.       msSet: (
  43.         Negate: Boolean;
  44.         CharSet: PMaskSet);
  45.       msMBCSLiteral: (LeadByte, TrailByte: Char);
  46.   end;
  47.   PMaskStateArray = ^TMaskStateArray;
  48.   TMaskStateArray = array[0..128] of TMaskState;
  49.  
  50. function InitMaskStates(const Mask: string;
  51.   var MaskStates: array of TMaskState): Integer;
  52. var
  53.   I: Integer;
  54.   SkipTo: Boolean;
  55.   Literal: Char;
  56.   LeadByte, TrailByte: Char;
  57.   P: PChar;
  58.   Negate: Boolean;
  59.   CharSet: TMaskSet;
  60.   Cards: Integer;
  61.  
  62.   procedure InvalidMask;
  63.   begin
  64.     raise Exception.CreateResFmt(@SInvalidMask, [Mask,
  65.       P - PChar(Mask) + 1]);
  66.   end;
  67.  
  68.   procedure Reset;
  69.   begin
  70.     SkipTo := False;
  71.     Negate := False;
  72.     CharSet := [];
  73.   end;
  74.  
  75.   procedure WriteScan(MaskState: TMaskStates);
  76.   begin
  77.     if I <= High(MaskStates) then
  78.     begin
  79.       if SkipTo then
  80.       begin
  81.         Inc(Cards);
  82.         if Cards > MaxCards then InvalidMask;
  83.       end;
  84.       MaskStates[I].SkipTo := SkipTo;
  85.       MaskStates[I].State := MaskState;
  86.       case MaskState of
  87.         msLiteral: MaskStates[I].Literal := UpCase(Literal);
  88.         msSet:
  89.           begin
  90.             MaskStates[I].Negate := Negate;
  91.             New(MaskStates[I].CharSet);
  92.             MaskStates[I].CharSet^ := CharSet;
  93.           end;
  94.         msMBCSLiteral:
  95.           begin
  96.             MaskStates[I].LeadByte := LeadByte;
  97.             MaskStates[I].TrailByte := TrailByte;
  98.           end;
  99.       end;
  100.     end;
  101.     Inc(I);
  102.     Reset;
  103.   end;
  104.  
  105.   procedure ScanSet;
  106.   var
  107.     LastChar: Char;
  108.     C: Char;
  109.   begin
  110.     Inc(P);
  111.     if P^ = '!' then
  112.     begin
  113.       Negate := True;
  114.       Inc(P);
  115.     end;
  116.     LastChar := #0;
  117.     while not (P^ in [#0, ']']) do
  118.     begin
  119.       // MBCS characters not supported in msSet!
  120.       if P^ in LeadBytes then
  121.          Inc(P)
  122.       else
  123.       case P^ of
  124.         '-':
  125.           if LastChar = #0 then InvalidMask
  126.           else
  127.           begin
  128.             Inc(P);
  129.             for C := LastChar to UpCase(P^) do Include(CharSet, C);
  130.           end;
  131.       else
  132.         LastChar := UpCase(P^);
  133.         Include(CharSet, LastChar);
  134.       end;
  135.       Inc(P);
  136.     end;
  137.     if (P^ <> ']') or (CharSet = []) then InvalidMask;
  138.     WriteScan(msSet);
  139.   end;
  140.  
  141. begin
  142.   P := PChar(Mask);
  143.   I := 0;
  144.   Cards := 0;
  145.   Reset;
  146.   while P^ <> #0 do
  147.   begin
  148.     case P^ of
  149.       '*': SkipTo := True;
  150.       '?': if not SkipTo then WriteScan(msAny);
  151.       '[':  ScanSet;
  152.     else
  153.       if P^ in LeadBytes then
  154.       begin
  155.         LeadByte := P^;
  156.         Inc(P);
  157.         TrailByte := P^;
  158.         WriteScan(msMBCSLiteral);
  159.       end
  160.       else
  161.       begin
  162.         Literal := P^;
  163.         WriteScan(msLiteral);
  164.       end;
  165.     end;
  166.     Inc(P);
  167.   end;
  168.   Literal := #0;
  169.   WriteScan(msLiteral);
  170.   Result := I;
  171. end;
  172.  
  173. function MatchesMaskStates(const Filename: string;
  174.   MaskStates: array of TMaskState): Boolean;
  175. type
  176.   TStackRec = record
  177.     sP: PChar;
  178.     sI: Integer;
  179.   end;
  180. var
  181.   T: Integer;
  182.   S: array[0..MaxCards - 1] of TStackRec;
  183.   I: Integer;
  184.   P: PChar;
  185.  
  186.   procedure Push(P: PChar; I: Integer);
  187.   begin
  188.     with S[T] do
  189.     begin
  190.       sP := P;
  191.       sI := I;
  192.     end;
  193.     Inc(T);
  194.   end;
  195.  
  196.   function Pop(var P: PChar; var I: Integer): Boolean;
  197.   begin
  198.     if T = 0 then
  199.       Result := False
  200.     else
  201.     begin
  202.       Dec(T);
  203.       with S[T] do
  204.       begin
  205.         P := sP;
  206.         I := sI;
  207.       end;
  208.       Result := True;
  209.     end;
  210.   end;
  211.  
  212.   function Matches(P: PChar; Start: Integer): Boolean;
  213.   var
  214.     I: Integer;
  215.   begin
  216.     Result := False;
  217.     for I := Start to High(MaskStates) do
  218.       with MaskStates[I] do
  219.       begin
  220.         if SkipTo then
  221.         begin
  222.           case State of
  223.             msLiteral:
  224.               while (P^ <> #0) and (UpperCase(P^) <> Literal) do Inc(P);
  225.             msSet:
  226.               while (P^ <> #0) and not (Negate xor (UpCase(P^) in CharSet^)) do Inc(P);
  227.             msMBCSLiteral:
  228.               while (P^ <> #0) do
  229.               begin
  230.                 if (P^ <> LeadByte) then Inc(P, 2)
  231.                 else
  232.                 begin
  233.                   Inc(P);
  234.                   if (P^ = TrailByte) then Break;
  235.                   Inc(P);
  236.                 end;
  237.               end;
  238.           end;
  239.           if P^ <> #0 then Push(@P[1], I);
  240.         end;
  241.         case State of
  242.           msLiteral: if UpperCase(P^) <> Literal then Exit;
  243.           msSet: if not (Negate xor (UpCase(P^) in CharSet^)) then Exit;
  244.           msMBCSLiteral:
  245.             begin
  246.               if P^ <> LeadByte then Exit;
  247.               Inc(P);
  248.               if P^ <> TrailByte then Exit;
  249.             end;
  250.         end;
  251.         Inc(P);
  252.       end;
  253.     Result := True;
  254.   end;
  255.  
  256. begin
  257.   Result := True;
  258.   T := 0;
  259.   P := PChar(Filename);
  260.   I := Low(MaskStates);
  261.   repeat
  262.     if Matches(P, I) then Exit;
  263.   until not Pop(P, I);
  264.   Result := False;
  265. end;
  266.  
  267. procedure DoneMaskStates(var MaskStates: array of TMaskState);
  268. var
  269.   I: Integer;
  270. begin
  271.   for I := Low(MaskStates) to High(MaskStates) do
  272.     if MaskStates[I].State = msSet then Dispose(MaskStates[I].CharSet);
  273. end;
  274.  
  275. { TMask }
  276.  
  277. constructor TMask.Create(const MaskValue: string);
  278. var
  279.   A: array[0..0] of TMaskState;
  280. begin
  281.   FSize := InitMaskStates(MaskValue, A);
  282.   FMask := AllocMem(FSize * SizeOf(TMaskState));
  283.   InitMaskStates(MaskValue, Slice(PMaskStateArray(FMask)^, FSize));
  284. end;
  285.  
  286. destructor TMask.Destroy;
  287. begin
  288.   if FMask <> nil then
  289.   begin
  290.     DoneMaskStates(Slice(PMaskStateArray(FMask)^, FSize));
  291.     FreeMem(FMask, FSize * SizeOf(TMaskState));
  292.   end;
  293. end;
  294.  
  295. function TMask.Matches(const Filename: string): Boolean;
  296. begin
  297.   Result := MatchesMaskStates(Filename, Slice(PMaskStateArray(FMask)^, FSize));
  298. end;
  299.  
  300. function MatchesMask(const Filename, Mask: string): Boolean;
  301. var
  302.   CMask: TMask;
  303. begin
  304.   CMask := TMask.Create(Mask);
  305.   try
  306.     Result := CMask.Matches(Filename);
  307.   finally
  308.     CMask.Free;
  309.   end;
  310. end;
  311.  
  312. end.
  313.