Componentes.Terceros.jcl/official/1.100/source/common/JclStringLists.pas

1380 lines
44 KiB
ObjectPascal

{**************************************************************************************************}
{ }
{ Project JEDI Code Library (JCL) }
{ }
{ The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); }
{ you may not use this file except in compliance with the License. You may obtain a copy of the }
{ License at http://www.mozilla.org/MPL/ }
{ }
{ Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF }
{ ANY KIND, either express or implied. See the License for the specific language governing rights }
{ and limitations under the License. }
{ }
{ The Original Code is NewStringListUnit.pas. }
{ }
{ The Initial Developer of the Original Code is Romullo Sousa. }
{ Portions created by Romullo Sousa are Copyright (C) Romullo Sousa. All rights reserved. }
{ }
{ Contributor(s): }
{ Romullo Sousa (romullobr) }
{ Leo Simas (Leh_U) }
{ }
{**************************************************************************************************}
// Last modified: $Date: 2006-12-30 10:04:59 +0100 (Sa, 30 Dez 2006) $
unit JclStringLists;
{$I jcl.inc}
interface
uses
{$IFDEF UNITVERSIONING}
JclUnitVersioning,
{$ENDIF UNITVERSIONING}
{$IFDEF MSWINDOWS}
Windows,
{$ENDIF MSWINDOWS}
{$IFDEF HAS_UNIT_VARIANTS}
Variants,
{$ENDIF HAS_UNIT_VARIANTS}
Classes, SysUtils,
JclBase;
type
IJclStringList = interface;
TJclStringListObjectsMode = (omNone, omObjects, omVariants, omInterfaces);
TJclStringListSortCompare = function(List: IJclStringList; Index1, Index2: Integer): Integer;
IJclStringList = interface(IInterface)
['{8DC5B71C-4756-404D-8636-7872CD299796}']
{ From TStrings/TStringList }
function Add(const S: string): Integer; overload;
function AddObject(const S: string; AObject: TObject): Integer;
function Get(Index: Integer): string;
function GetCapacity: Integer;
function GetCount: Integer;
function GetObjects(Index: Integer): TObject;
function GetTextStr: string;
function GetValue(const Name: string): string;
function Find(const S: string; var Index: Integer): Boolean;
function IndexOf(const S: string): Integer;
{$IFDEF COMPILER6_UP}
function GetCaseSensitive: Boolean;
{$ENDIF COMPILER6_UP}
function GetDuplicates: TDuplicates;
function GetOnChange: TNotifyEvent;
function GetOnChanging: TNotifyEvent;
function GetSorted: Boolean;
function Equals(Strings: TStrings): Boolean;
function IndexOfName(const Name: string): Integer;
function IndexOfObject(AObject: TObject): Integer;
function LoadFromFile(const FileName: string): IJclStringList;
function LoadFromStream(Stream: TStream): IJclStringList;
function SaveToFile(const FileName: string): IJclStringList;
function SaveToStream(Stream: TStream): IJclStringList;
function GetCommaText: string;
{$IFDEF COMPILER6_UP}
function GetDelimitedText: string;
function GetDelimiter: Char;
{$ENDIF COMPILER6_UP}
function GetName(Index: Integer): string;
{$IFDEF COMPILER7_UP}
function GetNameValueSeparator: Char;
function GetValueFromIndex(Index: Integer): string;
{$ENDIF COMPILER7_UP}
{$IFDEF COMPILER6_UP}
function GetQuoteChar: Char;
{$ENDIF COMPILER6_UP}
procedure SetCommaText(const Value: string);
{$IFDEF COMPILER6_UP}
procedure SetDelimitedText(const Value: string);
procedure SetDelimiter(const Value: Char);
{$ENDIF COMPILER6_UP}
{$IFDEF COMPILER7_UP}
procedure SetNameValueSeparator(const Value: Char);
procedure SetValueFromIndex(Index: Integer; const Value: string);
{$ENDIF COMPILER7_UP}
{$IFDEF COMPILER6_UP}
procedure SetQuoteChar(const Value: Char);
{$ENDIF COMPILER6_UP}
procedure AddStrings(Strings: TStrings); overload;
procedure SetObjects(Index: Integer; const Value: TObject);
procedure Put(Index: Integer; const S: string);
procedure SetCapacity(NewCapacity: Integer);
procedure SetTextStr(const Value: string);
procedure SetValue(const Name, Value: string);
{$IFDEF COMPILER6_UP}
procedure SetCaseSensitive(const Value: Boolean);
{$ENDIF COMPILER6_UP}
procedure SetDuplicates(const Value: TDuplicates);
procedure SetOnChange(const Value: TNotifyEvent);
procedure SetOnChanging(const Value: TNotifyEvent);
procedure SetSorted(const Value: Boolean);
property Count: Integer read GetCount;
property Strings[Index: Integer]: string read Get write Put; default;
property Text: string read GetTextStr write SetTextStr;
property Objects[Index: Integer]: TObject read GetObjects write SetObjects;
property Capacity: Integer read GetCapacity write SetCapacity;
property Values[const Name: string]: string read GetValue write SetValue;
property Duplicates: TDuplicates read GetDuplicates write SetDuplicates;
property Sorted: Boolean read GetSorted write SetSorted;
{$IFDEF COMPILER6_UP}
property CaseSensitive: Boolean read GetCaseSensitive write SetCaseSensitive;
{$ENDIF COMPILER6_UP}
property OnChange: TNotifyEvent read GetOnChange write SetOnChange;
property OnChanging: TNotifyEvent read GetOnChanging write SetOnChanging;
{$IFDEF COMPILER6_UP}
property DelimitedText: string read GetDelimitedText write SetDelimitedText;
property Delimiter: Char read GetDelimiter write SetDelimiter;
{$ENDIF COMPILER6_UP}
property Names[Index: Integer]: string read GetName;
{$IFDEF COMPILER6_UP}
property QuoteChar: Char read GetQuoteChar write SetQuoteChar;
{$ENDIF COMPILER6_UP}
property CommaText: string read GetCommaText write SetCommaText;
{$IFDEF COMPILER7_UP}
property ValueFromIndex[Index: Integer]: string read GetValueFromIndex write SetValueFromIndex;
property NameValueSeparator: Char read GetNameValueSeparator write SetNameValueSeparator;
{$ENDIF COMPILER7_UP}
{ New }
function Assign(Source: TPersistent): IJclStringList;
function LoadExeParams: IJclStringList;
function Exists(const S: string): Boolean;
function ExistsName(const S: string): Boolean;
function DeleteBlanks: IJclStringList;
function KeepIntegers: IJclStringList;
function DeleteIntegers: IJclStringList;
function ReleaseInterfaces: IJclStringList;
function FreeObjects(AFreeAndNil: Boolean = False): IJclStringList;
function Clone: IJclStringList;
function Insert(Index: Integer; const S: string): IJclStringList;
function InsertObject(Index: Integer; const S: string; AObject: TObject): IJclStringList;
function Sort(ACompareFunction: TJclStringListSortCompare = nil): IJclStringList;
function SortAsInteger: IJclStringList;
function SortByName: IJclStringList;
function Delete(AIndex: Integer): IJclStringList; overload;
function Delete(const AString: string): IJclStringList; overload;
function Exchange(Index1, Index2: Integer): IJclStringList;
function Add(const A: array of const): IJclStringList; overload;
function AddStrings(const A: array of string): IJclStringList; overload;
function BeginUpdate: IJclStringList;
function EndUpdate: IJclStringList;
function Trim: IJclStringList;
function Join(const ASeparator: string = ''): string;
function Split(const AText, ASeparator: string; AClearBeforeAdd: Boolean = True): IJclStringList;
function ExtractWords(const AText: string; const ADelims: TSetOfChar = [#0..' ']; AClearBeforeAdd: Boolean = True): IJclStringList;
function Last: string;
function First: string;
function LastIndex: Integer;
function Clear: IJclStringList;
function DeleteRegEx(const APattern: string): IJclStringList;
function KeepRegEx(const APattern: string): IJclStringList;
function Files(const APattern: string = '*'; ARecursive: Boolean = False; const ARegExPattern: string = ''): IJclStringList;
function Directories(const APattern: string = '*'; ARecursive: Boolean = False; const ARegExPattern: string = ''): IJclStringList;
function GetStringsRef: TStrings;
function ConfigAsSet: IJclStringList;
function Delimit(const ADelimiter: string): IJclStringList;
function GetInterfaceByIndex(Index: Integer): IInterface;
function GetLists(Index: Integer): IJclStringList;
function GetVariants(AIndex: Integer): Variant;
function GetKeyInterface(const AKey: string): IInterface;
function GetKeyObject(const AKey: string): TObject;
function GetKeyVariant(const AKey: string): Variant;
function GetKeyList(const AKey: string): IJclStringList;
function GetObjectsMode: TJclStringListObjectsMode;
procedure SetInterfaceByIndex(Index: Integer; const Value: IInterface);
procedure SetLists(Index: Integer; const Value: IJclStringList);
procedure SetVariants(Index: Integer; const Value: Variant);
procedure SetKeyInterface(const AKey: string; const Value: IInterface);
procedure SetKeyObject(const AKey: string; const Value: TObject);
procedure SetKeyVariant(const AKey: string; const Value: Variant);
procedure SetKeyList(const AKey: string; const Value: IJclStringList);
property Interfaces[Index: Integer]: IInterface read GetInterfaceByIndex write SetInterfaceByIndex;
property Lists[Index: Integer]: IJclStringList read GetLists write SetLists;
property Variants[Index: Integer]: Variant read GetVariants write SetVariants;
property KeyList[const AKey: string]: IJclStringList read GetKeyList write SetKeyList;
property KeyObject[const AKey: string]: TObject read GetKeyObject write SetKeyObject;
property KeyInterface[const AKey: string]: IInterface read GetKeyInterface write SetKeyInterface;
property KeyVariant[const AKey: string]: Variant read GetKeyVariant write SetKeyVariant;
property ObjectsMode: TJclStringListObjectsMode read GetObjectsMode;
end;
function JclStringList: IJclStringList; overload;
function JclStringListStrings(AStrings: TStrings): IJclStringList; overload;
function JclStringListStrings(const A: array of string): IJclStringList; overload;
function JclStringList(const A: array of const): IJclStringList; overload;
function JclStringList(const AText: string): IJclStringList; overload;
{$IFDEF UNITVERSIONING}
const
UnitVersioning: TUnitVersionInfo = (
RCSfile: '$URL: https://svn.sourceforge.net:443/svnroot/jcl/trunk/jcl/source/common/JclStringLists.pas $';
Revision: '$Revision: 1856 $';
Date: '$Date: 2006-12-30 10:04:59 +0100 (Sa, 30 Dez 2006) $';
LogPath: 'JCL\source\common'
);
{$ENDIF UNITVERSIONING}
implementation
uses
TypInfo,
JclFileUtils, JclPCRE, JclStrings;
type
TUpdateControl = class(TObject, IInterface)
private
FStrings: TStrings;
protected
function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
public
constructor Create(AStrings: TStrings);
end;
TVariantWrapper = class(TObject)
private
FValue: Variant;
end;
TInterfaceWrapper = class(TObject)
private
FValue: IInterface;
end;
TJclStringListImpl = class(TStringList, IJclStringList)
private
FObjectsMode: TJclStringListObjectsMode;
FSelfAsInterface: IJclStringList;
FLastRegExPattern: string;
FRegEx: TJclAnsiRegEx;
FUpdateControl: TUpdateControl;
function AutoUpdateControl: IInterface;
function CanFreeObjects: Boolean;
function MatchRegEx(const S, APattern: string): Boolean;
function GetLists(Index: Integer): IJclStringList;
function GetKeyInterface(const AKey: string): IInterface;
function GetKeyObject(const AKey: string): TObject;
function GetKeyVariant(const AKey: string): Variant;
function GetValue(const Name: string): string;
function GetVariants(AIndex: Integer): Variant;
function GetKeyList(const AKey: string): IJclStringList;
{$IFDEF COMPILER6_UP}
function GetCaseSensitive: Boolean;
{$ENDIF COMPILER6_UP}
function GetDuplicates: TDuplicates;
function GetOnChange: TNotifyEvent;
function GetOnChanging: TNotifyEvent;
function GetSorted: Boolean;
function GetCommaText: string;
{$IFDEF COMPILER6_UP}
function GetDelimitedText: string;
function GetDelimiter: Char;
{$ENDIF COMPILER6_UP}
function GetName(Index: Integer): string;
{$IFDEF COMPILER7_UP}
function GetNameValueSeparator: Char;
function GetValueFromIndex(Index: Integer): string;
{$ENDIF COMPILER7_UP}
{$IFDEF COMPILER6_UP}
function GetQuoteChar: Char;
{$ENDIF COMPILER6_UP}
function GetInterfaceByIndex(AIndex: Integer): IInterface;
function GetObjects(Index: Integer): TObject;
procedure SetValue(const Name, Value: string);
procedure SetKeyList(const AKey: string; const Value: IJclStringList);
procedure SetKeyInterface(const AKey: string; const Value: IInterface);
procedure SetKeyObject(const AKey: string; const Value: TObject);
procedure SetKeyVariant(const AKey: string; const Value: Variant);
procedure SetLists(Index: Integer; const Value: IJclStringList);
procedure SetVariants(Index: Integer; const Value: Variant);
{$IFDEF COMPILER6_UP}
procedure SetCaseSensitive(const Value: Boolean);
{$ENDIF COMPILER6_UP}
procedure SetDuplicates(const Value: TDuplicates);
procedure SetOnChange(const Value: TNotifyEvent);
procedure SetOnChanging(const Value: TNotifyEvent);
procedure SetSorted(const Value: Boolean);
procedure SetCommaText(const Value: string);
{$IFDEF COMPILER6_UP}
procedure SetDelimitedText(const Value: string);
procedure SetDelimiter(const Value: Char);
{$ENDIF COMPILER6_UP}
{$IFDEF COMPILER7_UP}
procedure SetNameValueSeparator(const Value: Char);
procedure SetValueFromIndex(Index: Integer; const Value: string);
{$ENDIF COMPILER7_UP}
{$IFDEF COMPILER6_UP}
procedure SetQuoteChar(const Value: Char);
{$ENDIF COMPILER6_UP}
procedure SetInterfaceByIndex(Index: Integer; const Value: IInterface);
procedure SetObjects(Index: Integer; const Value: TObject);
procedure EnsureObjectsMode(AMode: TJclStringListObjectsMode);
function GetObjectsMode: TJclStringListObjectsMode;
protected
FRefCount: Integer;
function QueryInterface(const IID: TGUID; out Obj): HRESULT; stdcall;
function _AddRef: Integer; stdcall;
function _Release: Integer; stdcall;
{$IFDEF COMPILER5}
function CompareStrings(const S1, S2: string): Integer; virtual;
{$ENDIF COMPILER5}
public
constructor Create;
destructor Destroy; override;
function LoadExeParams: IJclStringList;
function Exists(const S: string): Boolean;
function ExistsName(const S: string): Boolean;
function DeleteBlanks: IJclStringList;
function KeepIntegers: IJclStringList;
function DeleteIntegers: IJclStringList;
function ReleaseInterfaces: IJclStringList;
function FreeObjects(AFreeAndNil: Boolean = False): IJclStringList;
function Clone: IJclStringList;
function Add(const A: array of const): IJclStringList; reintroduce; overload;
function AddStrings(const A: array of string): IJclStringList; reintroduce; overload;
function BeginUpdate: IJclStringList;
function EndUpdate: IJclStringList;
function Trim: IJclStringList;
function Delimit(const ADelimiter: string): IJclStringList;
function Join(const ASeparator: string = ''): string;
function Split(const AText, ASeparator: string; AClearBeforeAdd: Boolean = True): IJclStringList;
function ExtractWords(const AText: string; const ADelims: TSetOfChar = [#0..' '];
AClearBeforeAdd: Boolean = True): IJclStringList;
function Last: string;
function First: string;
function LastIndex: Integer;
function Clear: IJclStringList; reintroduce;
function DeleteRegEx(const APattern: string): IJclStringList;
function KeepRegEx(const APattern: string): IJclStringList;
function Files(const APattern: string = '*'; ARecursive: Boolean = False;
const ARegExPattern: string = ''): IJclStringList;
function Directories(const APattern: string = '*'; ARecursive: Boolean = False;
const ARegExPattern: string = ''): IJclStringList;
function GetStringsRef: TStrings;
function ConfigAsSet: IJclStringList;
function Delete(AIndex: Integer): IJclStringList; reintroduce; overload;
function Delete(const AString: string): IJclStringList; reintroduce; overload;
function Exchange(Index1, Index2: Integer): IJclStringList; reintroduce;
function Sort(ACompareFunction: TJclStringListSortCompare = nil): IJclStringList; reintroduce;
function SortAsInteger: IJclStringList;
function SortByName: IJclStringList;
function Insert(Index: Integer; const S: string): IJclStringList; reintroduce;
function InsertObject(Index: Integer; const S: string; AObject: TObject): IJclStringList; reintroduce;
function LoadFromFile(const FileName: string): IJclStringList; reintroduce;
function LoadFromStream(Stream: TStream): IJclStringList; reintroduce;
function SaveToFile(const FileName: string): IJclStringList; reintroduce;
function SaveToStream(Stream: TStream): IJclStringList; reintroduce;
function Assign(Source: TPersistent): IJclStringList; reintroduce;
{ From TStrings/TStringList }
property Values[const Name: string]: string read GetValue write SetValue;
{$IFDEF COMPILER6_UP}
property DelimitedText: string read GetDelimitedText write SetDelimitedText;
property Delimiter: Char read GetDelimiter write SetDelimiter;
{$ENDIF COMPILER6_UP}
property Names[Index: Integer]: string read GetName;
{$IFDEF COMPILER6_UP}
property QuoteChar: Char read GetQuoteChar write SetQuoteChar;
{$ENDIF COMPILER6_UP}
property CommaText: string read GetCommaText write SetCommaText;
{$IFDEF COMPILER7_UP}
property ValueFromIndex[Index: Integer]: string read GetValueFromIndex write SetValueFromIndex;
property NameValueSeparator: Char read GetNameValueSeparator write SetNameValueSeparator;
{$ENDIF COMPILER7_UP}
property Duplicates: TDuplicates read GetDuplicates write SetDuplicates;
property Sorted: Boolean read GetSorted write SetSorted;
{$IFDEF COMPILER6_UP}
property CaseSensitive: Boolean read GetCaseSensitive write SetCaseSensitive;
{$ENDIF COMPILER6_UP}
property OnChange: TNotifyEvent read GetOnChange write SetOnChange;
property OnChanging: TNotifyEvent read GetOnChanging write SetOnChanging;
{ New }
property Objects[Index: Integer]: TObject read GetObjects write SetObjects;
property Interfaces[Index: Integer]: IInterface read GetInterfaceByIndex write SetInterfaceByIndex;
property Lists[Index: Integer]: IJclStringList read GetLists write SetLists;
property Variants[Index: Integer]: Variant read GetVariants write SetVariants;
property KeyList[const AKey: string]: IJclStringList read GetKeyList write SetKeyList;
property KeyObject[const AKey: string]: TObject read GetKeyObject write SetKeyObject;
property KeyInterface[const AKey: string]: IInterface read GetKeyInterface write SetKeyInterface;
property KeyVariant[const AKey: string]: Variant read GetKeyVariant write SetKeyVariant;
property ObjectsMode: TJclStringListObjectsMode read GetObjectsMode;
end;
function JclStringList: IJclStringList;
begin
Result := TJclStringListImpl.Create;
end;
function JclStringList(const AText: string): IJclStringList; overload;
begin
Result := JclStringList;
Result.Text := AText;
end;
function JclStringListStrings(AStrings: TStrings): IJclStringList; overload;
begin
Result := JclStringList;
Result.AddStrings(AStrings);
end;
function JclStringListStrings(const A: array of string): IJclStringList;
begin
Result := JclStringList.AddStrings(A);
end;
function JclStringList(const A: array of const): IJclStringList;
begin
Result := JclStringList.Add(A);
end;
//=== { TJclStringListImpl } =================================================
function TJclStringListImpl.Add(const A: array of const): IJclStringList;
const
BoolToStr: array [Boolean] of string[5] = ('false', 'true');
var
I: Integer;
begin
AutoUpdateControl;
for I := Low(A) to High(A) do
with A[I] do
case VType of
vtInteger:
Add(IntToStr(VInteger));
vtBoolean:
Add(BoolToStr[VBoolean]);
vtChar:
Add(VChar);
vtExtended:
Add(FloatToStr(VExtended^));
vtString:
Add(VString^);
vtPChar:
Add(VPChar);
vtObject:
Add(VObject.ClassName);
vtClass:
Add(VClass.ClassName);
vtAnsiString:
Add(string(VAnsiString));
vtCurrency:
Add(CurrToStr(VCurrency^));
vtVariant:
Add(string(VVariant^));
vtInt64:
Add(IntToStr(VInt64^));
end;
Result := FSelfAsInterface;
end;
function TJclStringListImpl.AddStrings(const A: array of string): IJclStringList;
var
I: Integer;
begin
AutoUpdateControl;
for I := Low(A) to High(A) do
Add(A[I]);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.BeginUpdate: IJclStringList;
begin
inherited BeginUpdate;
Result := FSelfAsInterface;
end;
function TJclStringListImpl.AutoUpdateControl: IInterface;
begin
Result := FUpdateControl as IInterface;
end;
function TJclStringListImpl.Clear: IJclStringList;
begin
if CanFreeObjects then
FreeObjects(False);
inherited Clear;
Result := FSelfAsInterface;
end;
function TJclStringListImpl.EndUpdate: IJclStringList;
begin
inherited EndUpdate;
Result := FSelfAsInterface;
end;
function TJclStringListImpl.ExtractWords(const AText: string; const ADelims: TSetOfChar;
AClearBeforeAdd: Boolean): IJclStringList;
var
L, I, X: Integer;
begin
AutoUpdateControl;
if AClearBeforeAdd then
Clear;
I := 1;
L := Length(AText);
while I <= L do
begin
while (I <= L) and (AText[I] in ADelims) do
Inc(I);
X := I;
while (I <= L) and not (AText[I] in ADelims) do
Inc(I);
if X <> I then
Add(Copy(AText, X, I - X));
end;
Result := FSelfAsInterface;
end;
function TJclStringListImpl.First: string;
begin
Result := Strings[0];
end;
function TJclStringListImpl.Join(const ASeparator: string): string;
var
I: Integer;
begin
Result := '';
for I := 0 to LastIndex - 1 do
Result := Result + Strings[I] + ASeparator;
if Count > 0 then
Result := Result + Last;
end;
function TJclStringListImpl.Last: string;
begin
Result := Strings[LastIndex];
end;
function TJclStringListImpl.QueryInterface(const IID: TGUID; out Obj): HRESULT;
begin
if GetInterface(IID, Obj) then
Result := 0
else
Result := E_NOINTERFACE;
end;
function TJclStringListImpl.Split(const AText, ASeparator: string;
AClearBeforeAdd: Boolean = True): IJclStringList;
var
LStartIndex, LEndIndex: Integer;
LLengthSeparator: Integer;
begin
if AText <> '' then
begin
AutoUpdateControl;
if AClearBeforeAdd then
Clear;
LLengthSeparator := Length(ASeparator);
LStartIndex := 1;
LEndIndex := StrSearch(ASeparator, AText, LStartIndex);
while LEndIndex > 0 do
begin
Add(Copy(AText, LStartIndex, LEndIndex - LStartIndex));
LStartIndex := LEndIndex + LLengthSeparator;
LEndIndex := StrSearch(ASeparator, AText, LStartIndex);
end;
Add(Copy(AText, LStartIndex, MaxInt));
end;
Result := FSelfAsInterface;
end;
function TJclStringListImpl.Trim: IJclStringList;
var
I: Integer;
begin
AutoUpdateControl;
for I := 0 to LastIndex do
Strings[I] := SysUtils.Trim(Strings[I]);
Result := FSelfAsInterface;
end;
function TJclStringListImpl._AddRef: Integer;
begin
Result := InterlockedIncrement(FRefCount);
end;
function TJclStringListImpl._Release: Integer;
begin
Result := InterlockedDecrement(FRefCount);
if Result = 1 then
begin
// When there is only one reference, it is the internal reference,
// so we release it. The compiler will call _Release again and
// the object will be destroyed.
FSelfAsInterface := nil;
end
else
if Result = 0 then
Destroy;
end;
function TJclStringListImpl.DeleteRegEx(const APattern: string): IJclStringList;
var
I: Integer;
begin
AutoUpdateControl;
for I := LastIndex downto 0 do
if MatchRegEx(Strings[I], APattern) then
Delete(I);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.KeepRegEx(const APattern: string): IJclStringList;
var
I: Integer;
begin
AutoUpdateControl;
for I := LastIndex downto 0 do
if not MatchRegEx(Strings[I], APattern) then
Delete(I);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.MatchRegEx(const S, APattern: string): Boolean;
begin
if FRegEx = nil then
FRegEx := TJclAnsiRegEx.Create;
if FLastRegExPattern <> APattern then
begin
{$IFDEF COMPILER6_UP}
if CaseSensitive then
FRegEx.Options := FRegEx.Options - [roIgnoreCase]
else
FRegEx.Options := FRegEx.Options + [roIgnoreCase];
{$ENDIF COMPILER6_UP}
FRegEx.Compile(APattern, False, True);
FLastRegExPattern := APattern;
end;
Result := FRegEx.Match(S);
end;
destructor TJclStringListImpl.Destroy;
begin
if CanFreeObjects then
FreeObjects(False);
FreeAndNil(FUpdateControl);
FreeAndNil(FRegEx);
inherited Destroy;
end;
function TJclStringListImpl.Directories(const APattern: string = '*';
ARecursive: Boolean = False; const ARegExPattern: string = ''): IJclStringList;
procedure DoDirectories(const APattern: string);
var
LSearchRec: TSearchRec;
LFullName: string;
LPath: string;
begin
LPath := ExtractFilePath(APattern);
if FindFirst(APattern, faAnyFile, LSearchRec) = 0 then
try
repeat
if (LSearchRec.Attr and faDirectory = 0) or
(LSearchRec.Name = '.') or (LSearchRec.Name = '..') then
Continue;
LFullName := LPath + LSearchRec.Name;
if (ARegExPattern = '') or MatchRegEx(LFullName, ARegExPattern) then
Add(LFullName);
if ARecursive then
DoDirectories(PathAddSeparator(LFullName) + ExtractFileName(APattern));
until FindNext(LSearchRec) <> 0;
finally
FindClose(LSearchRec);
end;
end;
begin
AutoUpdateControl;
if DirectoryExists(APattern) then
DoDirectories(PathAddSeparator(APattern) + '*')
else
DoDirectories(APattern);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.Files(const APattern: string = '*';
ARecursive: Boolean = False; const ARegExPattern: string = ''): IJclStringList;
procedure DoFiles(const APattern: string);
var
LSearchRec: TSearchRec;
LFullName: string;
LDirectories: IJclStringList;
LPath: string;
I: Integer;
begin
LPath := ExtractFilePath(APattern);
if FindFirst(APattern, faAnyFile and not faDirectory, LSearchRec) = 0 then
begin
try
repeat
if (LSearchRec.Attr and faDirectory <> 0) or
(LSearchRec.Name = '.') or (LSearchRec.Name = '..') then
Continue;
LFullName := LPath + LSearchRec.Name;
if (ARegExPattern = '') or MatchRegEx(LFullName, ARegExPattern) then
Add(LFullName);
until FindNext(LSearchRec) <> 0;
finally
FindClose(LSearchRec);
end;
end;
if ARecursive then
begin
LDirectories := JclStringList.Directories(LPath + '*', False);
for I := 0 to LDirectories.LastIndex do
DoFiles(PathAddSeparator(LDirectories[I]) + ExtractFileName(APattern));
end;
end;
begin
AutoUpdateControl;
if DirectoryExists(APattern) then
DoFiles(PathAddSeparator(APattern) + '*')
else
DoFiles(APattern);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.LastIndex: Integer;
begin
{ The code bellow is more optimized than "Result := Count - 1". }
Result := Count;
Dec(Result);
end;
constructor TJclStringListImpl.Create;
begin
inherited Create;
FUpdateControl := TUpdateControl.Create(Self);
if QueryInterface(IJclStringList, FSelfAsInterface) <> 0 then
{$IFDEF COMPILER5}
RunError(228 { reIntfCastError });
{$ELSE}
System.Error(reIntfCastError);
{$ENDIF COMPILER5}
end;
function TJclStringListImpl.GetLists(Index: Integer): IJclStringList;
begin
Result := Interfaces[Index] as IJclStringList;
if Result = nil then
begin
Result := JclStringList;
Interfaces[Index] := Result;
end;
end;
procedure TJclStringListImpl.SetLists(Index: Integer; const Value: IJclStringList);
begin
Interfaces[Index] := Value;
end;
function TJclStringListImpl.GetStringsRef: TStrings;
begin
Result := Self;
end;
function TJclStringListImpl.GetKeyInterface(const AKey: string): IInterface;
var
I: Integer;
begin
I := IndexOf(AKey);
if I >= 0 then
Result := Interfaces[I]
else
Result := nil;
end;
function TJclStringListImpl.GetKeyObject(const AKey: string): TObject;
var
I: Integer;
begin
I := IndexOf(AKey);
if I >= 0 then
Result := Objects[I]
else
Result := nil;
end;
procedure TJclStringListImpl.SetKeyInterface(const AKey: string; const Value: IInterface);
var
I: Integer;
begin
I := IndexOf(AKey);
if I < 0 then
I := Add(AKey);
Interfaces[I] := Value
end;
procedure TJclStringListImpl.SetKeyObject(const AKey: string; const Value: TObject);
var
I: Integer;
begin
I := IndexOf(AKey);
if I < 0 then
AddObject(AKey, Value)
else
Objects[I] := Value;
end;
function TJclStringListImpl.ConfigAsSet: IJclStringList;
begin
Sorted := True;
Duplicates := dupIgnore;
Result := FSelfAsInterface;
end;
function TJclStringListImpl.GetKeyVariant(const AKey: string): Variant;
var
I: Integer;
begin
I := IndexOf(AKey);
if I >= 0 then
Result := Variants[I]
else
Result := Unassigned;
end;
procedure TJclStringListImpl.SetKeyVariant(const AKey: string; const Value: Variant);
var
I: Integer;
begin
I := IndexOf(AKey);
if I < 0 then
I := Add(AKey);
Variants[I] := Value
end;
function TJclStringListImpl.GetValue(const Name: string): string;
begin
Result := inherited Values[Name];
end;
procedure TJclStringListImpl.SetValue(const Name, Value: string);
begin
inherited Values[Name] := Value;
end;
function TJclStringListImpl.GetInterfaceByIndex(AIndex: Integer): IInterface;
var
V: TInterfaceWrapper;
begin
if FObjectsMode <> omInterfaces then
EnsureObjectsMode(omInterfaces);
V := TInterfaceWrapper(inherited Objects[AIndex]);
if V = nil then
Result := nil
else
Result := V.FValue;
end;
procedure TJclStringListImpl.SetInterfaceByIndex(Index: Integer; const Value: IInterface);
var
V: TInterfaceWrapper;
begin
if FObjectsMode <> omInterfaces then
EnsureObjectsMode(omInterfaces);
V := TInterfaceWrapper(inherited Objects[Index]);
if V = nil then
begin
V := TInterfaceWrapper.Create;
inherited Objects[Index] := V;
end;
V.FValue := Value;
end;
function TJclStringListImpl.GetObjects(Index: Integer): TObject;
begin
if FObjectsMode <> omObjects then
EnsureObjectsMode(omObjects);
Result := inherited Objects[Index];
end;
procedure TJclStringListImpl.SetObjects(Index: Integer; const Value: TObject);
begin
if FObjectsMode <> omObjects then
EnsureObjectsMode(omObjects);
inherited Objects[Index] := Value;
end;
function TJclStringListImpl.GetVariants(AIndex: Integer): Variant;
var
V: TVariantWrapper;
begin
if FObjectsMode <> omVariants then
EnsureObjectsMode(omVariants);
V := TVariantWrapper(inherited Objects[AIndex]);
if V = nil then
Result := Unassigned
else
Result := V.FValue;
end;
procedure TJclStringListImpl.SetVariants(Index: Integer; const Value: Variant);
var
V: TVariantWrapper;
begin
if FObjectsMode <> omVariants then
EnsureObjectsMode(omVariants);
V := TVariantWrapper(inherited Objects[Index]);
if V = nil then
begin
V := TVariantWrapper.Create;
inherited Objects[Index] := V;
end;
V.FValue := Value;
end;
procedure TJclStringListImpl.EnsureObjectsMode(AMode: TJclStringListObjectsMode);
begin
if FObjectsMode <> AMode then
begin
if FObjectsMode <> omNone then
begin
raise Exception.CreateFmt('Objects cannot be used as "%s" because it has been used as "%s".',
[GetEnumName(TypeInfo(TJclStringListObjectsMode), Ord(AMode)),
GetEnumName(TypeInfo(TJclStringListObjectsMode), Ord(FObjectsMode))]);
end;
FObjectsMode := AMode;
end;
end;
function TJclStringListImpl.GetKeyList(const AKey: string): IJclStringList;
begin
Result := KeyInterface[AKey] as IJclStringList;
if Result = nil then
begin
Result := JclStringList;
KeyInterface[AKey] := Result;
end;
end;
procedure TJclStringListImpl.SetKeyList(const AKey: string; const Value: IJclStringList);
begin
KeyInterface[AKey] := Value;
end;
function TJclStringListImpl.Delete(AIndex: Integer): IJclStringList;
begin
if CanFreeObjects then
inherited Objects[AIndex].Free;
inherited Delete(AIndex);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.Delete(const AString: string): IJclStringList;
begin
Result := Delete(IndexOf(AString));
end;
function TJclStringListImpl.Exchange(Index1, Index2: Integer): IJclStringList;
begin
inherited Exchange(Index1, Index2);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.Sort(ACompareFunction: TJclStringListSortCompare = nil): IJclStringList;
function LocalSort(List: TStringList; Index1, Index2: Integer): Integer;
begin
Result := ACompareFunction(FSelfAsInterface, Index1, Index2);
end;
begin
if not Assigned(ACompareFunction) then
inherited Sort
else
inherited CustomSort(@LocalSort);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.SortAsInteger: IJclStringList;
function LocalSortAsInteger(List: TStringList; Index1, Index2: Integer): Integer;
begin
Result := StrToInt(List[Index1]) - StrToInt(List[Index2]);
end;
begin
inherited CustomSort(@LocalSortAsInteger);
Result := FSelfAsInterface;
end;
{$IFDEF COMPILER5}
function TJclStringListImpl.CompareStrings(const S1, S2: string): Integer;
begin
Result := AnsiCompareText(S1, S2);
end;
{$ENDIF COMPILER5}
function TJclStringListImpl.SortByName: IJclStringList;
function LocalSortByName(List: TStringList; Index1, Index2: Integer): Integer;
begin
Result := TJclStringListImpl(List).CompareStrings(List.Names[Index1], List.Names[Index2]);
end;
begin
inherited CustomSort(@LocalSortByName);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.Insert(Index: Integer; const S: string): IJclStringList;
begin
inherited Insert(Index, S);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.InsertObject(Index: Integer; const S: string; AObject: TObject): IJclStringList;
begin
inherited InsertObject(Index, S, AObject);
Result := FSelfAsInterface;
end;
{$IFDEF COMPILER6_UP}
function TJclStringListImpl.GetCaseSensitive: Boolean;
begin
Result := inherited CaseSensitive;
end;
{$ENDIF COMPILER6_UP}
function TJclStringListImpl.GetDuplicates: TDuplicates;
begin
Result := inherited Duplicates;
end;
function TJclStringListImpl.GetOnChange: TNotifyEvent;
begin
Result := inherited OnChange;
end;
function TJclStringListImpl.GetOnChanging: TNotifyEvent;
begin
Result := inherited OnChanging;
end;
function TJclStringListImpl.GetSorted: Boolean;
begin
Result := inherited Sorted;
end;
{$IFDEF COMPILER6_UP}
procedure TJclStringListImpl.SetCaseSensitive(const Value: Boolean);
begin
inherited CaseSensitive := Value;
end;
{$ENDIF COMPILER6_UP}
procedure TJclStringListImpl.SetDuplicates(const Value: TDuplicates);
begin
inherited Duplicates := Value;
end;
procedure TJclStringListImpl.SetOnChange(const Value: TNotifyEvent);
begin
inherited OnChange := Value;
end;
procedure TJclStringListImpl.SetOnChanging(const Value: TNotifyEvent);
begin
inherited OnChanging := Value;
end;
procedure TJclStringListImpl.SetSorted(const Value: Boolean);
begin
inherited Sorted := Value;
end;
function TJclStringListImpl.LoadFromFile(const FileName: string): IJclStringList;
begin
inherited LoadFromFile(FileName);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.LoadFromStream(Stream: TStream): IJclStringList;
begin
inherited LoadFromStream(Stream);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.SaveToFile(const FileName: string): IJclStringList;
begin
inherited SaveToFile(FileName);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.SaveToStream(Stream: TStream): IJclStringList;
begin
inherited SaveToStream(Stream);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.GetCommaText: string;
begin
Result := inherited CommaText;
end;
{$IFDEF COMPILER6_UP}
function TJclStringListImpl.GetDelimitedText: string;
begin
Result := inherited DelimitedText;
end;
function TJclStringListImpl.GetDelimiter: Char;
begin
Result := inherited Delimiter;
end;
{$ENDIF COMPILER6_UP}
function TJclStringListImpl.GetName(Index: Integer): string;
begin
Result := inherited Names[Index];
end;
{$IFDEF COMPILER7_UP}
function TJclStringListImpl.GetNameValueSeparator: Char;
begin
Result := inherited NameValueSeparator;
end;
function TJclStringListImpl.GetValueFromIndex(Index: Integer): string;
begin
Result := inherited ValueFromIndex[Index];
end;
{$ENDIF COMPILER7_UP}
{$IFDEF COMPILER6_UP}
function TJclStringListImpl.GetQuoteChar: Char;
begin
Result := inherited QuoteChar;
end;
{$ENDIF COMPILER6_UP}
procedure TJclStringListImpl.SetCommaText(const Value: string);
begin
inherited CommaText := Value;
end;
{$IFDEF COMPILER6_UP}
procedure TJclStringListImpl.SetDelimitedText(const Value: string);
begin
inherited DelimitedText := Value;
end;
procedure TJclStringListImpl.SetDelimiter(const Value: Char);
begin
inherited Delimiter := Value;
end;
{$ENDIF COMPILER6_UP}
{$IFDEF COMPILER7_UP}
procedure TJclStringListImpl.SetNameValueSeparator(const Value: Char);
begin
inherited NameValueSeparator := Value;
end;
procedure TJclStringListImpl.SetValueFromIndex(Index: Integer; const Value: string);
begin
inherited ValueFromIndex[Index] := Value;
end;
{$ENDIF COMPILER7_UP}
{$IFDEF COMPILER6_UP}
procedure TJclStringListImpl.SetQuoteChar(const Value: Char);
begin
inherited QuoteChar := Value;
end;
{$ENDIF COMPILER6_UP}
function TJclStringListImpl.Delimit(const ADelimiter: string): IJclStringList;
var
I: Integer;
begin
AutoUpdateControl;
for I := 0 to LastIndex do
Strings[I] := ADelimiter + Strings[I] + ADelimiter;
Result := FSelfAsInterface;
end;
function TJclStringListImpl.LoadExeParams: IJclStringList;
var
I: Integer;
S: string;
begin
AutoUpdateControl;
Clear;
for I := 1 to ParamCount do
begin
S := ParamStr(I);
if S[1] in ['-', '/'] then
System.Delete(S, 1, 1);
Add(S);
end;
Result := FSelfAsInterface;
end;
function TJclStringListImpl.Exists(const S: string): Boolean;
begin
Result := IndexOf(S) >= 0;
end;
function TJclStringListImpl.ExistsName(const S: string): Boolean;
begin
Result := IndexOfName(S) >= 0;
end;
function TJclStringListImpl.DeleteBlanks: IJclStringList;
var
I: Integer;
begin
AutoUpdateControl;
for I := LastIndex downto 0 do
if SysUtils.Trim(Strings[I]) = '' then
Delete(I);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.KeepIntegers: IJclStringList;
var
I, X: Integer;
begin
AutoUpdateControl;
for I := LastIndex downto 0 do
if not TryStrToInt(Strings[I], X) then
Delete(I);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.DeleteIntegers: IJclStringList;
var
I, X: Integer;
begin
AutoUpdateControl;
for I := LastIndex downto 0 do
if TryStrToInt(Strings[I], X) then
Delete(I);
Result := FSelfAsInterface;
end;
function TJclStringListImpl.FreeObjects(AFreeAndNil: Boolean = False): IJclStringList;
var
I: Integer;
begin
if AFreeAndNil then
AutoUpdateControl;
for I := 0 to LastIndex do
begin
inherited Objects[I].Free;
if AFreeAndNil then
inherited Objects[I] := nil;
end;
Result := FSelfAsInterface;
end;
function TJclStringListImpl.ReleaseInterfaces: IJclStringList;
var
I: Integer;
begin
AutoUpdateControl;
for I := 0 to LastIndex do
Interfaces[I] := nil;
Result := FSelfAsInterface;
end;
function TJclStringListImpl.Clone: IJclStringList;
begin
Result := JclStringList.Assign(Self);
end;
function TJclStringListImpl.Assign(Source: TPersistent): IJclStringList;
var
L: TJclStringListImpl;
I: Integer;
begin
inherited Assign(Source);
if Source is TJclStringListImpl then
begin
L := TJclStringListImpl(Source);
FObjectsMode := L.FObjectsMode;
if not (FObjectsMode in [omNone, omObjects]) then
begin
AutoUpdateControl;
for I := 0 to LastIndex do
begin
inherited Objects[I] := nil;
case FObjectsMode of
omVariants:
Variants[I] := L.Variants[I];
omInterfaces:
Interfaces[I] := L.Interfaces[I];
end;
end;
end;
end;
Result := FSelfAsInterface;
end;
function TJclStringListImpl.CanFreeObjects: Boolean;
begin
Result := not (FObjectsMode in [omNone, omObjects]);
end;
function TJclStringListImpl.GetObjectsMode: TJclStringListObjectsMode;
begin
Result := FObjectsMode;
end;
//=== { TUpdateControl } =====================================================
constructor TUpdateControl.Create(AStrings: TStrings);
begin
inherited Create;
FStrings := AStrings;
end;
function TUpdateControl._AddRef: Integer;
begin
FStrings.BeginUpdate;
Result := 0;
end;
function TUpdateControl._Release: Integer;
begin
FStrings.EndUpdate;
Result := 0;
end;
function TUpdateControl.QueryInterface(const IID: TGUID; out Obj): HRESULT;
begin
if GetInterface(IID, Obj) then
Result := S_OK
else
Result := E_NOINTERFACE;
end;
{$IFDEF UNITVERSIONING}
initialization
RegisterUnitVersion(HInstance, UnitVersioning);
finalization
UnregisterUnitVersion(HInstance);
{$ENDIF UNITVERSIONING}
end.