mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-11-28 14:57:17 +01:00
Masks: implement specific matching for Windows filemasks like foo*.* and other Windows oddities.
git-svn-id: trunk@40970 -
This commit is contained in:
parent
04a4b1e14f
commit
fe79a8fdff
@ -26,7 +26,7 @@ interface
|
|||||||
|
|
||||||
uses
|
uses
|
||||||
// For Smart Linking: Do not use the LCL!
|
// For Smart Linking: Do not use the LCL!
|
||||||
Classes, SysUtils, Contnrs, LazUtilsStrConsts;
|
Classes, SysUtils, Contnrs, StrUtils, LazUtilsStrConsts;
|
||||||
|
|
||||||
type
|
type
|
||||||
TMaskCharType = (mcChar, mcCharSet, mcAnyChar, mcAnyText);
|
TMaskCharType = (mcChar, mcCharSet, mcAnyChar, mcAnyText);
|
||||||
@ -53,11 +53,15 @@ type
|
|||||||
private
|
private
|
||||||
FMask: TMaskString;
|
FMask: TMaskString;
|
||||||
fCaseSensitive: Boolean;
|
fCaseSensitive: Boolean;
|
||||||
|
fInitialMask: String;
|
||||||
|
procedure InitMaskString(const AValue: String; const CaseSensitive: Boolean);
|
||||||
|
procedure ClearMaskString;
|
||||||
public
|
public
|
||||||
constructor Create(const AValue: String; const CaseSensitive: Boolean = False);
|
constructor Create(const AValue: String; const CaseSensitive: Boolean = False);
|
||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
|
|
||||||
function Matches(const AFileName: String): Boolean;
|
function Matches(const AFileName: String): Boolean;
|
||||||
|
function MatchesWindowsMask(const AFileName: String): Boolean;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TParseStringList }
|
{ TParseStringList }
|
||||||
@ -79,13 +83,16 @@ type
|
|||||||
destructor Destroy; override;
|
destructor Destroy; override;
|
||||||
|
|
||||||
function Matches(const AFileName: String): Boolean;
|
function Matches(const AFileName: String): Boolean;
|
||||||
|
function MatchesWindowsMask(const AFileName: String): Boolean;
|
||||||
|
|
||||||
property Count: Integer read GetCount;
|
property Count: Integer read GetCount;
|
||||||
property Items[Index: Integer]: TMask read GetItem;
|
property Items[Index: Integer]: TMask read GetItem;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function MatchesMask(const FileName, Mask: String; const CaseSensitive: Boolean = False): Boolean;
|
function MatchesMask(const FileName, Mask: String; const CaseSensitive: Boolean = False): Boolean;
|
||||||
|
function MatchesWindowsMask(const FileName, Mask: String; const CaseSensitive: Boolean = False): Boolean;
|
||||||
function MatchesMaskList(const FileName, Mask: String; Separator: Char = ';'; const CaseSensitive: Boolean = False): Boolean;
|
function MatchesMaskList(const FileName, Mask: String; Separator: Char = ';'; const CaseSensitive: Boolean = False): Boolean;
|
||||||
|
function MatchesWindowsMaskList(const FileName, Mask: String; Separator: Char = ';'; const CaseSensitive: Boolean = False): Boolean;
|
||||||
|
|
||||||
implementation
|
implementation
|
||||||
|
|
||||||
@ -101,6 +108,18 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function MatchesWindowsMask(const FileName, Mask: String; const CaseSensitive: Boolean): Boolean;
|
||||||
|
var
|
||||||
|
AMask: TMask;
|
||||||
|
begin
|
||||||
|
AMask := TMask.Create(Mask, CaseSensitive);
|
||||||
|
try
|
||||||
|
Result := AMask.MatchesWindowsMask(FileName);
|
||||||
|
finally
|
||||||
|
AMask.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
function MatchesMaskList(const FileName, Mask: String; Separator: Char; const CaseSensitive: Boolean): Boolean;
|
function MatchesMaskList(const FileName, Mask: String; Separator: Char; const CaseSensitive: Boolean): Boolean;
|
||||||
var
|
var
|
||||||
AMaskList: TMaskList;
|
AMaskList: TMaskList;
|
||||||
@ -113,9 +132,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function MatchesWindowsMaskList(const FileName, Mask: String; Separator: Char; const CaseSensitive: Boolean): Boolean;
|
||||||
|
var
|
||||||
|
AMaskList: TMaskList;
|
||||||
|
begin
|
||||||
|
AMaskList := TMaskList.Create(Mask, Separator, CaseSensitive);
|
||||||
|
try
|
||||||
|
Result := AMaskList.MatchesWindowsMask(FileName);
|
||||||
|
finally
|
||||||
|
AMaskList.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TMask }
|
{ TMask }
|
||||||
|
|
||||||
constructor TMask.Create(const AValue: String; const CaseSensitive: Boolean);
|
procedure TMask.InitMaskString(const AValue: String; const CaseSensitive: Boolean);
|
||||||
var
|
var
|
||||||
I: Integer;
|
I: Integer;
|
||||||
SkipAnyText: Boolean;
|
SkipAnyText: Boolean;
|
||||||
@ -246,7 +277,6 @@ var
|
|||||||
end;
|
end;
|
||||||
|
|
||||||
begin
|
begin
|
||||||
fCaseSensitive := CaseSensitive;
|
|
||||||
SetLength(FMask.Chars, 0);
|
SetLength(FMask.Chars, 0);
|
||||||
FMask.MinLength := 0;
|
FMask.MinLength := 0;
|
||||||
FMask.MaxLength := 0;
|
FMask.MaxLength := 0;
|
||||||
@ -264,14 +294,26 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TMask.Destroy;
|
procedure TMask.ClearMaskString;
|
||||||
var
|
var
|
||||||
I: Integer;
|
I: Integer;
|
||||||
begin
|
begin
|
||||||
for I := 0 to High(FMask.Chars) do
|
for I := 0 to High(FMask.Chars) do
|
||||||
if FMask.Chars[I].CharType = mcCharSet then
|
if FMask.Chars[I].CharType = mcCharSet then
|
||||||
Dispose(FMask.Chars[I].SetValue);
|
Dispose(FMask.Chars[I].SetValue);
|
||||||
|
end;
|
||||||
|
|
||||||
|
constructor TMask.Create(const AValue: String; const CaseSensitive: Boolean);
|
||||||
|
|
||||||
|
begin
|
||||||
|
fInitialMask := AValue;
|
||||||
|
fCaseSensitive := CaseSensitive;
|
||||||
|
InitMaskString(AValue, CaseSensitive);
|
||||||
|
end;
|
||||||
|
|
||||||
|
destructor TMask.Destroy;
|
||||||
|
begin
|
||||||
|
ClearMaskString;
|
||||||
inherited Destroy;
|
inherited Destroy;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
@ -346,6 +388,68 @@ begin
|
|||||||
Result := MatchToEnd(0, 1);
|
Result := MatchToEnd(0, 1);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TMask.MatchesWindowsMask(const AFileName: String): Boolean;
|
||||||
|
var
|
||||||
|
NewMaskValue, Ext: String;
|
||||||
|
begin
|
||||||
|
// treat initial mask differently for special cases:
|
||||||
|
// foo*.* -> foo*
|
||||||
|
// foo*. -> match foo*, but muts not have an extension
|
||||||
|
// *. -> any file without extension ( .foo is a filename without extension according to Windows)
|
||||||
|
// foo. matches only foo but not foo.txt
|
||||||
|
// foo.* -> match either foo or foo.*
|
||||||
|
|
||||||
|
if (Length(fInitialMask) > 2) and (RightStr(fInitialMask,3) = '*.*') then
|
||||||
|
// foo*.*
|
||||||
|
begin
|
||||||
|
NewMaskValue := Copy(fInitialMask,1,Length(fInitialMask)-2);
|
||||||
|
ClearMaskString;
|
||||||
|
InitMaskString(NewMaskValue, fCaseSensitive);
|
||||||
|
Result := Matches(AFileName);
|
||||||
|
//Restore initial state of FMask
|
||||||
|
ClearMaskString;
|
||||||
|
InitMaskString(fInitialMask, fCaseSensitive);
|
||||||
|
end
|
||||||
|
//else if (Length(fInitialMask) > 1) and (RightStr(fInitialMask,2) = '*.') then
|
||||||
|
else if (Length(fInitialMask) > 1) and (fInitialMask[Length(fInitialMask)] = '.') then
|
||||||
|
|
||||||
|
//foo*. or *. or foo.
|
||||||
|
begin
|
||||||
|
//if AFileName has an extension then Result is False, otherwise see if it matches foo*/foo
|
||||||
|
//a filename like .foo under Windows is considered to be a file without an extension
|
||||||
|
Ext := ExtractFileExt(AFileName);
|
||||||
|
if (Ext = '') or (Ext = AFileName) then
|
||||||
|
begin
|
||||||
|
NewMaskValue := Copy(fInitialMask,1,Length(fInitialMask)-1);
|
||||||
|
ClearMaskString;
|
||||||
|
InitMaskString(NewMaskValue, fCaseSensitive);
|
||||||
|
Result := Matches(AFileName);
|
||||||
|
//Restore initial state of FMask
|
||||||
|
ClearMaskString;
|
||||||
|
InitMaskString(fInitialMask, fCaseSensitive);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
end;
|
||||||
|
end
|
||||||
|
else if (Length(fInitialMask) > 2) and (RightStr(fInitialMask,2) = '.*') then
|
||||||
|
//foo.* (but not '.*')
|
||||||
|
begin
|
||||||
|
//First see if we have 'foo'
|
||||||
|
if fCaseSensitive then
|
||||||
|
Result := (AFileName = Copy(fInitialMask,1,Length(fInitialMask)-2))
|
||||||
|
else
|
||||||
|
Result := (CompareText(AFileName,Copy(fInitialMask,1,Length(fInitialMask)-2)) = 0);
|
||||||
|
if not Result then Result := Matches(AFileName);
|
||||||
|
end
|
||||||
|
else
|
||||||
|
//all other cases just call Matches()
|
||||||
|
begin
|
||||||
|
Result := Matches(AFileName);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
{ TParseStringList }
|
{ TParseStringList }
|
||||||
|
|
||||||
constructor TParseStringList.Create(const AText, ASeparators: String);
|
constructor TParseStringList.Create(const AText, ASeparators: String);
|
||||||
@ -418,5 +522,21 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function TMaskList.MatchesWindowsMask(const AFileName: String): Boolean;
|
||||||
|
var
|
||||||
|
I: Integer;
|
||||||
|
begin
|
||||||
|
Result := False;
|
||||||
|
|
||||||
|
for I := 0 to FMasks.Count - 1 do
|
||||||
|
begin
|
||||||
|
if TMask(FMasks.Items[I]).MatchesWindowsMask(AFileName) then
|
||||||
|
begin
|
||||||
|
Result := True;
|
||||||
|
Exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user