You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
RnQ/for.RnQ/RTL/AnsiClasses.pas

1267 lines
34 KiB
Plaintext

unit AnsiClasses;
interface
{$I NoRTTI.inc}
uses
Windows, Messages, Classes, SysUtils, TypInfo, ActiveX, AnsiStrings;
type
TAnsiStrings = class(TPersistent)
private
FDefined: TStringsDefined;
FDelimiter: AnsiChar;
FLineBreak: AnsiString;
FQuoteChar: AnsiChar;
FNameValueSeparator: AnsiChar;
FStrictDelimiter: Boolean;
FUpdateCount: Integer;
// FAdapter: IStringsAdapter;
// function GetCommaText: AnsiString;
// function GetDelimitedText: AnsiString;
function GetName(Index: Integer): AnsiString;
function GetValue(const Name: AnsiString): AnsiString;
// procedure ReadData(Reader: TReader);
// procedure SetCommaText(const Value: AnsiString);
// procedure SetDelimitedText(const Value: AnsiString);
// procedure SetAnsiStringsAdapter(const Value: IStringsAdapter);
procedure SetValue(const Name, Value: AnsiString);
// procedure WriteData(Writer: TWriter);
function GetDelimiter: AnsiChar;
procedure SetDelimiter(const Value: AnsiChar);
function GetLineBreak: AnsiString;
procedure SetLineBreak(const Value: AnsiString);
function GetQuoteChar: AnsiChar;
procedure SetQuoteChar(const Value: AnsiChar);
function GetNameValueSeparator: AnsiChar;
procedure SetNameValueSeparator(const Value: AnsiChar);
function GetStrictDelimiter: Boolean;
procedure SetStrictDelimiter(const Value: Boolean);
function GetValueFromIndex(Index: Integer): AnsiString;
procedure SetValueFromIndex(Index: Integer; const Value: AnsiString);
protected
// procedure DefineProperties(Filer: TFiler); override;
procedure Error(const Msg: string; Data: Integer); overload;
procedure Error(Msg: PResStringRec; Data: Integer); overload;
function ExtractName(const S: AnsiString): AnsiString;
function Get(Index: Integer): AnsiString; virtual; abstract;
function GetCapacity: Integer; virtual;
function GetCount: Integer; virtual; abstract;
function GetObject(Index: Integer): TObject; virtual;
function GetTextStr: AnsiString; virtual;
procedure Put(Index: Integer; const S: AnsiString); virtual;
procedure PutObject(Index: Integer; AObject: TObject); virtual;
procedure SetCapacity(NewCapacity: Integer); virtual;
procedure SetTextStr(const Value: AnsiString); virtual;
procedure SetUpdateState(Updating: Boolean); virtual;
property UpdateCount: Integer read FUpdateCount;
function CompareAnsiStrings(const S1, S2: AnsiString): Integer; virtual;
public
destructor Destroy; override;
function Add(const S: AnsiString): Integer; virtual;
function AddObject(const S: AnsiString; AObject: TObject): Integer; virtual;
procedure Append(const S: AnsiString);
procedure AddAnsiStrings(AnsiStrings: TAnsiStrings); virtual;
procedure Assign(Source: TPersistent); override;
procedure BeginUpdate;
procedure Clear; virtual; abstract;
procedure Delete(Index: Integer); virtual; abstract;
procedure EndUpdate;
function Equals(AnsiStrings: TAnsiStrings): Boolean; reintroduce;
procedure Exchange(Index1, Index2: Integer); virtual;
// function GetEnumerator: TStringsEnumerator;
function GetText: PAnsiChar; virtual;
function IndexOf(const S: AnsiString): Integer; virtual;
function IndexOfName(const Name: AnsiString): Integer; virtual;
function IndexOfObject(AObject: TObject): Integer; virtual;
procedure Insert(Index: Integer; const S: AnsiString); virtual; abstract;
procedure InsertObject(Index: Integer; const S: AnsiString;
AObject: TObject); virtual;
procedure LoadFromFile(const FileName: string); overload; virtual;
procedure LoadFromFile(const FileName: string; Encoding: TEncoding); overload; virtual;
procedure LoadFromStream(Stream: TStream); overload; virtual;
procedure LoadFromStream(Stream: TStream; Encoding: TEncoding); overload; virtual;
procedure Move(CurIndex, NewIndex: Integer); virtual;
procedure SaveToFile(const FileName: string); overload; virtual;
procedure SaveToFile(const FileName: string; Encoding: TEncoding); overload; virtual;
procedure SaveToStream(Stream: TStream); overload; virtual;
procedure SaveToStream(Stream: TStream; Encoding: TEncoding); overload; virtual;
procedure SetText(Text: PAnsiChar); virtual;
property Capacity: Integer read GetCapacity write SetCapacity;
// property CommaText: AnsiString read GetCommaText write SetCommaText;
property Count: Integer read GetCount;
property Delimiter: AnsiChar read GetDelimiter write SetDelimiter;
// property DelimitedText: AnsiString read GetDelimitedText write SetDelimitedText;
property LineBreak: AnsiString read GetLineBreak write SetLineBreak;
property Names[Index: Integer]: AnsiString read GetName;
property Objects[Index: Integer]: TObject read GetObject write PutObject;
property QuoteChar: AnsiChar read GetQuoteChar write SetQuoteChar;
property Values[const Name: AnsiString]: AnsiString read GetValue write SetValue;
property ValueFromIndex[Index: Integer]: AnsiString read GetValueFromIndex write SetValueFromIndex;
property NameValueSeparator: AnsiChar read GetNameValueSeparator write SetNameValueSeparator;
property StrictDelimiter: Boolean read GetStrictDelimiter write SetStrictDelimiter;
// property AnsiStrings[Index: Integer]: AnsiString read Get write Put; default;
property Strings[Index: Integer]: AnsiString read Get write Put; default;
property Text: AnsiString read GetTextStr write SetTextStr;
// property AnsiStringsAdapter: IStringsAdapter read FAdapter write SetAnsiStringsAdapter;
end;
{ TAnsiStringList class }
TAnsiStringList = class;
PAnsiStringItem = ^TAnsiStringItem;
TAnsiStringItem = record
FAnsiString: AnsiString;
FObject: TObject;
end;
PAnsiStringItemList = ^TAnsiStringItemList;
// TAnsiStringItemList = array[0..MaxListSize] of TAnsiStringItem;
TAnsiStringItemList = array of TAnsiStringItem;
TAnsiStringListSortCompare = function(List: TAnsiStringList; Index1, Index2: Integer): Integer;
TAnsiStringList = class(TAnsiStrings)
private
// FList: PAnsiStringItemList;
FList: TAnsiStringItemList;
FCount: Integer;
FCapacity: Integer;
FSorted: Boolean;
FDuplicates: TDuplicates;
FCaseSensitive: Boolean;
FOnChange: TNotifyEvent;
FOnChanging: TNotifyEvent;
FOwnsObject: Boolean;
procedure ExchangeItems(Index1, Index2: Integer);
procedure Grow;
procedure QuickSort(L, R: Integer; SCompare: TAnsiStringListSortCompare);
procedure SetSorted(Value: Boolean);
procedure SetCaseSensitive(const Value: Boolean);
protected
procedure Changed; virtual;
procedure Changing; virtual;
function Get(Index: Integer): AnsiString; override;
function GetCapacity: Integer; override;
function GetCount: Integer; override;
function GetObject(Index: Integer): TObject; override;
procedure Put(Index: Integer; const S: AnsiString); override;
procedure PutObject(Index: Integer; AObject: TObject); override;
procedure SetCapacity(NewCapacity: Integer); override;
procedure SetUpdateState(Updating: Boolean); override;
function CompareAnsiStrings(const S1, S2: AnsiString): Integer; override;
procedure InsertItem(Index: Integer; const S: AnsiString; AObject: TObject); virtual;
public
constructor Create; overload;
constructor Create(OwnsObjects: Boolean); overload;
destructor Destroy; override;
function Add(const S: AnsiString): Integer; override;
function AddObject(const S: AnsiString; AObject: TObject): Integer; override;
procedure Clear; override;
procedure Delete(Index: Integer); override;
procedure Exchange(Index1, Index2: Integer); override;
function Find(const S: AnsiString; var Index: Integer): Boolean; virtual;
function IndexOf(const S: AnsiString): Integer; override;
procedure Insert(Index: Integer; const S: AnsiString); override;
procedure InsertObject(Index: Integer; const S: AnsiString;
AObject: TObject); override;
procedure Sort; virtual;
procedure CustomSort(Compare: TAnsiStringListSortCompare); virtual;
property Duplicates: TDuplicates read FDuplicates write FDuplicates;
property Sorted: Boolean read FSorted write SetSorted;
property CaseSensitive: Boolean read FCaseSensitive write SetCaseSensitive;
property OnChange: TNotifyEvent read FOnChange write FOnChange;
property OnChanging: TNotifyEvent read FOnChanging write FOnChanging;
property OwnsObjects: Boolean read FOwnsObject write FOwnsObject;
end;
implementation
uses
Character, RTLConsts, SysConst, Types;
{ TAnsiStrings }
destructor TAnsiStrings.Destroy;
begin
// AnsiStringsAdapter := nil;
inherited Destroy;
end;
function TAnsiStrings.Add(const S: AnsiString): Integer;
begin
Result := GetCount;
Insert(Result, S);
end;
function TAnsiStrings.AddObject(const S: AnsiString; AObject: TObject): Integer;
begin
Result := Add(S);
PutObject(Result, AObject);
end;
procedure TAnsiStrings.Append(const S: AnsiString);
begin
Add(S);
end;
procedure TAnsiStrings.AddAnsiStrings(AnsiStrings: TAnsiStrings);
var
I: Integer;
begin
BeginUpdate;
try
for I := 0 to AnsiStrings.Count - 1 do
AddObject(AnsiStrings[I], AnsiStrings.Objects[I]);
finally
EndUpdate;
end;
end;
procedure TAnsiStrings.Assign(Source: TPersistent);
begin
if Source is TAnsiStrings then
begin
BeginUpdate;
try
Clear;
FDefined := TAnsiStrings(Source).FDefined;
FNameValueSeparator := TAnsiStrings(Source).FNameValueSeparator;
FQuoteChar := TAnsiStrings(Source).FQuoteChar;
FDelimiter := TAnsiStrings(Source).FDelimiter;
FLineBreak := TAnsiStrings(Source).FLineBreak;
FStrictDelimiter := TAnsiStrings(Source).FStrictDelimiter;
AddAnsiStrings(TAnsiStrings(Source));
finally
EndUpdate;
end;
Exit;
end;
inherited Assign(Source);
end;
procedure TAnsiStrings.BeginUpdate;
begin
if FUpdateCount = 0 then SetUpdateState(True);
Inc(FUpdateCount);
end;
//procedure TAnsiStrings.DefineProperties(Filer: TFiler);
//
// function DoWrite: Boolean;
// begin
// if Filer.Ancestor <> nil then
// begin
// Result := True;
// if Filer.Ancestor is TAnsiStrings then
// Result := not Equals(TAnsiStrings(Filer.Ancestor))
// end
// else Result := Count > 0;
// end;
//
//begin
// Filer.DefineProperty('AnsiStrings', ReadData, WriteData, DoWrite);
//end;
procedure TAnsiStrings.EndUpdate;
begin
Dec(FUpdateCount);
if FUpdateCount = 0 then SetUpdateState(False);
end;
function TAnsiStrings.Equals(AnsiStrings: TAnsiStrings): Boolean;
var
I, Count: Integer;
begin
Result := False;
Count := GetCount;
if Count <> AnsiStrings.GetCount then Exit;
for I := 0 to Count - 1 do if Get(I) <> AnsiStrings.Get(I) then Exit;
Result := True;
end;
procedure TAnsiStrings.Error(const Msg: string; Data: Integer);
function ReturnAddr: Pointer;
asm
MOV EAX,[EBP+4]
end;
begin
raise EStringListError.CreateFmt(Msg, [Data]) at ReturnAddr;
end;
procedure TAnsiStrings.Error(Msg: PResStringRec; Data: Integer);
begin
Error(LoadResString(Msg), Data);
end;
procedure TAnsiStrings.Exchange(Index1, Index2: Integer);
var
TempObject: TObject;
TempAnsiString: AnsiString;
begin
BeginUpdate;
try
TempAnsiString := Strings[Index1];
TempObject := Objects[Index1];
Strings[Index1] := Strings[Index2];
Objects[Index1] := Objects[Index2];
Strings[Index2] := TempAnsiString;
Objects[Index2] := TempObject;
finally
EndUpdate;
end;
end;
function TAnsiStrings.ExtractName(const S: AnsiString): AnsiString;
var
P: Integer;
begin
Result := S;
P := Pos(NameValueSeparator, Result);
if P <> 0 then
SetLength(Result, P-1) else
SetLength(Result, 0);
end;
function TAnsiStrings.GetCapacity: Integer;
begin // descendents may optionally override/replace this default implementation
Result := Count;
end;
//function TAnsiStrings.GetCommaText: AnsiString;
//var
// LOldDefined: TStringsDefined;
// LOldDelimiter: AnsiChar;
// LOldQuoteChar: AnsiChar;
//begin
// LOldDefined := FDefined;
// LOldDelimiter := FDelimiter;
// LOldQuoteChar := FQuoteChar;
// Delimiter := ',';
// QuoteChar := '"';
// try
// Result := GetDelimitedText;
// finally
// FDelimiter := LOldDelimiter;
// FQuoteChar := LOldQuoteChar;
// FDefined := LOldDefined;
// end;
//end;
//function TAnsiStrings.GetDelimitedText: AnsiString;
//var
// S: AnsiString;
// P: PAnsiChar;
// I, Count: Integer;
// LDelimiters: TSysCharSet;
//begin
// Count := GetCount;
// if (Count = 1) and (Get(0) = '') then
// Result := QuoteChar + QuoteChar
// else
// begin
// Result := '';
// LDelimiters := [AnsiChar(#0), AnsiChar(QuoteChar), AnsiChar(Delimiter)];
// if not StrictDelimiter then
// LDelimiters := LDelimiters + [AnsiChar(#1)..AnsiChar(' ')];
// for I := 0 to Count - 1 do
// begin
// S := Get(I);
// P := PAnsiChar(S);
// while not (P^ in LDelimiters) do
// {$IFDEF MSWINDOWS}
// P := CharNext(P);
// {$ELSE}
// Inc(P);
// {$ENDIF}
// if (P^ <> #0) then S := AnsiQuotedStr(S, QuoteChar);
// Result := Result + S + Delimiter;
// end;
// System.Delete(Result, Length(Result), 1);
// end;
//end;
//function TAnsiStrings.GetEnumerator: TStringsEnumerator;
//begin
// Result := TStringsEnumerator.Create(Self);
//end;
function TAnsiStrings.GetName(Index: Integer): AnsiString;
begin
Result := ExtractName(Get(Index));
end;
function TAnsiStrings.GetObject(Index: Integer): TObject;
begin
Result := nil;
end;
function TAnsiStrings.GetText: PAnsiChar;
begin
Result := AnsiStrings.StrNew(PAnsiChar(GetTextStr));
end;
function TAnsiStrings.GetTextStr: AnsiString;
var
I, L, Size, Count: Integer;
P: PAnsiChar;
S, LB: AnsiString;
begin
Count := GetCount;
Size := 0;
LB := LineBreak;
for I := 0 to Count - 1 do Inc(Size, Length(Get(I)) + Length(LB));
SetString(Result, nil, Size);
P := Pointer(Result);
for I := 0 to Count - 1 do
begin
S := Get(I);
L := Length(S);
if L <> 0 then
begin
System.Move(Pointer(S)^, P^, L * SizeOf(AnsiChar));
Inc(P, L);
end;
L := Length(LB);
if L <> 0 then
begin
System.Move(Pointer(LB)^, P^, L * SizeOf(AnsiChar));
Inc(P, L);
end;
end;
end;
function TAnsiStrings.GetValue(const Name: AnsiString): AnsiString;
var
I: Integer;
begin
I := IndexOfName(Name);
if I >= 0 then
Result := Copy(Get(I), Length(Name) + 2, MaxInt) else
Result := '';
end;
function TAnsiStrings.IndexOf(const S: AnsiString): Integer;
begin
if getCount > 0 then
for Result := 0 to GetCount - 1 do
if CompareAnsiStrings(Get(Result), S) = 0 then Exit;
Result := -1;
end;
function TAnsiStrings.IndexOfName(const Name: AnsiString): Integer;
var
P: Integer;
S: AnsiString;
begin
for Result := 0 to GetCount - 1 do
begin
S := Get(Result);
P := Pos(NameValueSeparator, S);
if (P <> 0) and (CompareAnsiStrings(Copy(S, 1, P - 1), Name) = 0) then Exit;
end;
Result := -1;
end;
function TAnsiStrings.IndexOfObject(AObject: TObject): Integer;
begin
for Result := 0 to GetCount - 1 do
if GetObject(Result) = AObject then Exit;
Result := -1;
end;
procedure TAnsiStrings.InsertObject(Index: Integer; const S: AnsiString; AObject: TObject);
begin
Insert(Index, S);
PutObject(Index, AObject);
end;
procedure TAnsiStrings.LoadFromFile(const FileName: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
procedure TAnsiStrings.LoadFromFile(const FileName: string; Encoding: TEncoding);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmOpenRead or fmShareDenyWrite);
try
LoadFromStream(Stream, Encoding);
finally
Stream.Free;
end;
end;
procedure TAnsiStrings.LoadFromStream(Stream: TStream);
begin
LoadFromStream(Stream, nil);
end;
procedure TAnsiStrings.LoadFromStream(Stream: TStream; Encoding: TEncoding);
var
Size: Integer;
S: AnsiString;
begin
BeginUpdate;
try
Size := Stream.Size - Stream.Position;
SetString(S, nil, Size);
Stream.Read(Pointer(S)^, Size);
SetTextStr(S);
finally
EndUpdate;
end;
end;
//procedure TAnsiStrings.LoadFromStream(Stream: TStream; Encoding: TEncoding);
//var
// Size: Integer;
// Buffer: TBytes;
//begin
// BeginUpdate;
// try
// Size := Stream.Size - Stream.Position;
// SetLength(Buffer, Size);
// Stream.Read(Buffer[0], Size);
//
// Size := TEncoding.GetBufferEncoding(Buffer, Encoding);
// SetTextStr(Encoding.GetString(Buffer, Size, Length(Buffer) - Size));
// finally
// EndUpdate;
// end;
//end;
procedure TAnsiStrings.Move(CurIndex, NewIndex: Integer);
var
TempObject: TObject;
TempAnsiString: AnsiString;
begin
if CurIndex <> NewIndex then
begin
BeginUpdate;
try
TempAnsiString := Get(CurIndex);
TempObject := GetObject(CurIndex);
Delete(CurIndex);
InsertObject(NewIndex, TempAnsiString, TempObject);
finally
EndUpdate;
end;
end;
end;
procedure TAnsiStrings.Put(Index: Integer; const S: AnsiString);
var
TempObject: TObject;
begin
TempObject := GetObject(Index);
Delete(Index);
InsertObject(Index, S, TempObject);
end;
procedure TAnsiStrings.PutObject(Index: Integer; AObject: TObject);
begin
end;
//procedure TAnsiStrings.ReadData(Reader: TReader);
//begin
// Reader.ReadListBegin;
// BeginUpdate;
// try
// Clear;
// while not Reader.EndOfList do Add(Reader.ReadString);
// finally
// EndUpdate;
// end;
// Reader.ReadListEnd;
//end;
procedure TAnsiStrings.SaveToFile(const FileName: string);
begin
SaveToFile(FileName, nil);
end;
procedure TAnsiStrings.SaveToFile(const FileName: string; Encoding: TEncoding);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmCreate);
try
SaveToStream(Stream, Encoding);
finally
Stream.Free;
end;
end;
//procedure TAnsiStrings.SaveToStream(Stream: TStream);
//begin
// SaveToStream(Stream, nil);
//end;
procedure TAnsiStrings.SaveToStream(Stream: TStream);
var
S: AnsiString;
begin
S := GetTextStr;
Stream.WriteBuffer(Pointer(S)^, Length(S));
end;
procedure TAnsiStrings.SaveToStream(Stream: TStream; Encoding: TEncoding);
var
Buffer, Preamble: TBytes;
begin
if Encoding = nil then
Encoding := TEncoding.Default;
Buffer := Encoding.GetBytes(string(GetTextStr));
Preamble := Encoding.GetPreamble;
if Length(Preamble) > 0 then
Stream.WriteBuffer(Preamble[0], Length(Preamble));
Stream.WriteBuffer(Buffer[0], Length(Buffer));
end;
procedure TAnsiStrings.SetCapacity(NewCapacity: Integer);
begin
// do nothing - descendents may optionally implement this method
end;
//procedure TAnsiStrings.SetCommaText(const Value: AnsiString);
//begin
// Delimiter := ',';
// QuoteChar := '"';
// SetDelimitedText(Value);
//end;
//procedure TAnsiStrings.SetAnsiStringsAdapter(const Value: IStringsAdapter);
//begin
// if FAdapter <> nil then FAdapter.ReleaseStrings;
// FAdapter := Value;
// if FAdapter <> nil then FAdapter.ReferenceStrings(Self);
//end;
procedure TAnsiStrings.SetText(Text: PAnsiChar);
begin
SetTextStr(Text);
end;
procedure TAnsiStrings.SetTextStr(const Value: AnsiString);
var
P, Start, LB: PAnsiChar;
S: AnsiString;
LineBreakLen: Integer;
begin
BeginUpdate;
try
Clear;
P := Pointer(Value);
if P <> nil then
if LineBreak = sLineBreak then
begin
// This is a lot faster than using StrPos/AnsiStrPos when
// LineBreak is the default (#13#10)
while P^ <> #0 do
begin
Start := P;
while not (P^ in [#0, #10, #13]) do Inc(P);
SetString(S, Start, P - Start);
Add(S);
if P^ = #13 then Inc(P);
if P^ = #10 then Inc(P);
end;
end
else
begin
LineBreakLen := Length(LineBreak);
while P^ <> #0 do
begin
Start := P;
LB := AnsiStrings.AnsiStrPos(P, PAnsiChar(LineBreak));
while (P^ <> #0) and (P <> LB) do Inc(P);
SetString(S, Start, P - Start);
Add(S);
if P = LB then
Inc(P, LineBreakLen);
end;
end;
finally
EndUpdate;
end;
end;
procedure TAnsiStrings.SetUpdateState(Updating: Boolean);
begin
end;
procedure TAnsiStrings.SetValue(const Name, Value: AnsiString);
var
I: Integer;
begin
I := IndexOfName(Name);
if Value <> '' then
begin
if I < 0 then I := Add('');
Put(I, Name + NameValueSeparator + Value);
end else
begin
if I >= 0 then Delete(I);
end;
end;
//procedure TAnsiStrings.WriteData(Writer: TWriter);
//var
// I: Integer;
//begin
// Writer.WriteListBegin;
// for I := 0 to Count - 1 do Writer.WriteString(Get(I));
// Writer.WriteListEnd;
//end;
//procedure TAnsiStrings.SetDelimitedText(const Value: AnsiString);
//var
// P, P1: PAnsiChar;
// S: AnsiString;
//begin
// BeginUpdate;
// try
// Clear;
// P := PAnsiChar(Value);
// if not StrictDelimiter then
// while (P^ in [#1..' ']) do
// {$IFDEF MSWINDOWS}
// P := CharNext(P);
// {$ELSE}
// Inc(P);
// {$ENDIF}
// while P^ <> #0 do
// begin
// if P^ = QuoteChar then
// S := AnsiExtractQuotedStr(P, QuoteChar)
// else
// begin
// P1 := P;
// while ((not FStrictDelimiter and (P^ > ' ')) or
// (FStrictDelimiter and (P^ <> #0))) and (P^ <> Delimiter) do
// {$IFDEF MSWINDOWS}
// P := CharNext(P);
// {$ELSE}
// Inc(P);
// {$ENDIF}
// SetString(S, P1, P - P1);
// end;
// Add(S);
// if not FStrictDelimiter then
// while (P^ in [#1..' ']) do
// {$IFDEF MSWINDOWS}
// P := CharNext(P);
// {$ELSE}
// Inc(P);
// {$ENDIF}
//
// if P^ = Delimiter then
// begin
// P1 := P;
// {$IFDEF MSWINDOWS}
// if CharNext(P1)^ = #0 then
// {$ELSE}
// Inc(P1);
// if P1^ = #0 then
// {$ENDIF}
// Add('');
// repeat
// {$IFDEF MSWINDOWS}
// P := CharNext(P);
// {$ELSE}
// Inc(P);
// {$ENDIF}
// until not (not FStrictDelimiter and (P^ in [#1..' ']));
// end;
// end;
// finally
// EndUpdate;
// end;
//end;
function TAnsiStrings.GetDelimiter: AnsiChar;
begin
if not (sdDelimiter in FDefined) then
Delimiter := ',';
Result := FDelimiter;
end;
function TAnsiStrings.GetLineBreak: AnsiString;
begin
if not (sdLineBreak in FDefined) then
LineBreak := sLineBreak;
Result := FLineBreak;
end;
function TAnsiStrings.GetQuoteChar: AnsiChar;
begin
if not (sdQuoteChar in FDefined) then
QuoteChar := '"';
Result := FQuoteChar;
end;
function TAnsiStrings.GetStrictDelimiter: Boolean;
begin
if not (sdStrictDelimiter in FDefined) then
StrictDelimiter := False;
Result := FStrictDelimiter;
end;
procedure TAnsiStrings.SetDelimiter(const Value: AnsiChar);
begin
if (FDelimiter <> Value) or not (sdDelimiter in FDefined) then
begin
Include(FDefined, sdDelimiter);
FDelimiter := Value;
end
end;
procedure TAnsiStrings.SetLineBreak(const Value: AnsiString);
begin
if (FLineBreak <> Value) or not (sdLineBreak in FDefined) then
begin
Include(FDefined, sdLineBreak);
FLineBreak := Value;
end
end;
procedure TAnsiStrings.SetQuoteChar(const Value: AnsiChar);
begin
if (FQuoteChar <> Value) or not (sdQuoteChar in FDefined) then
begin
Include(FDefined, sdQuoteChar);
FQuoteChar := Value;
end
end;
procedure TAnsiStrings.SetStrictDelimiter(const Value: Boolean);
begin
if (FStrictDelimiter <> Value) or not (sdStrictDelimiter in FDefined) then
begin
Include(FDefined, sdStrictDelimiter);
FStrictDelimiter := Value;
end
end;
function TAnsiStrings.CompareAnsiStrings(const S1, S2: AnsiString): Integer;
begin
Result := AnsiStrings.AnsiStrComp(PAnsiChar(S1), PAnsiChar(S2));
end;
function TAnsiStrings.GetNameValueSeparator: AnsiChar;
begin
if not (sdNameValueSeparator in FDefined) then
NameValueSeparator := '=';
Result := FNameValueSeparator;
end;
procedure TAnsiStrings.SetNameValueSeparator(const Value: AnsiChar);
begin
if (FNameValueSeparator <> Value) or not (sdNameValueSeparator in FDefined) then
begin
Include(FDefined, sdNameValueSeparator);
FNameValueSeparator := Value;
end
end;
function TAnsiStrings.GetValueFromIndex(Index: Integer): AnsiString;
begin
if Index >= 0 then
Result := Copy(Get(Index), Length(Names[Index]) + 2, MaxInt) else
Result := '';
end;
procedure TAnsiStrings.SetValueFromIndex(Index: Integer; const Value: AnsiString);
begin
if Value <> '' then
begin
if Index < 0 then Index := Add('');
Put(Index, Names[Index] + NameValueSeparator + Value);
end
else
if Index >= 0 then Delete(Index);
end;
{ TAnsiStringList }
destructor TAnsiStringList.Destroy;
var
I: Integer;
Temp: TArray;
begin
FOnChange := nil;
FOnChanging := nil;
// If the list owns the Objects gather them and free after the list is disposed
if OwnsObjects then
begin
SetLength(Temp, FCount);
for I := 0 to FCount - 1 do
Temp[I] := FList[I].FObject;
end;
inherited Destroy;
// if FCount <> 0 then Finalize(FList^[0], FCount);
FCount := 0;
SetCapacity(0);
// Free the objects that were owned by the list
if Length(Temp) > 0 then
for I := 0 to Length(Temp) - 1 do
Temp[I].Free;
end;
function TAnsiStringList.Add(const S: AnsiString): Integer;
begin
Result := AddObject(S, nil);
end;
function TAnsiStringList.AddObject(const S: AnsiString; AObject: TObject): Integer;
begin
if not Sorted then
Result := FCount
else
if Find(S, Result) then
case Duplicates of
dupIgnore: Exit;
dupError: Error(@SDuplicateString, 0);
end;
InsertItem(Result, S, AObject);
end;
procedure TAnsiStringList.Changed;
begin
if (FUpdateCount = 0) and Assigned(FOnChange) then
FOnChange(Self);
end;
procedure TAnsiStringList.Changing;
begin
if (FUpdateCount = 0) and Assigned(FOnChanging) then
FOnChanging(Self);
end;
procedure TAnsiStringList.Clear;
var
I: Integer;
Temp: TArray;
begin
if FCount <> 0 then
begin
Changing;
// If the list owns the Objects gather them and free after the list is disposed
if OwnsObjects then
begin
SetLength(Temp, FCount);
for I := 0 to FCount - 1 do
Temp[I] := FList[I].FObject;
end;
FCount := 0;
SetCapacity(0);
// Free the objects that were owned by the list
if Length(Temp) > 0 then
for I := 0 to Length(Temp) - 1 do
Temp[I].Free;
Changed;
end;
end;
procedure TAnsiStringList.Delete(Index: Integer);
var
Obj: TObject;
begin
if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index);
Changing;
// If this list owns its objects then free the associated TObject with this index
if OwnsObjects then
Obj := FList[Index].FObject
else
Obj := nil;
// Direct memory writing to managed array follows
// see http://dn.embarcadero.com/article/33423
// Explicitly finalize the element we about to stomp on with move
Finalize(FList[Index]);
Dec(FCount);
if Index < FCount then
begin
System.Move(FList[Index + 1], FList[Index],
(FCount - Index) * SizeOf(TStringItem));
// Make sure there is no danglng pointer in the last (now unused) element
PPointer(@FList[FCount])^ := nil;
end;
if Obj <> nil then
Obj.Free;
Changed;
end;
procedure TAnsiStringList.Exchange(Index1, Index2: Integer);
begin
if (Index1 < 0) or (Index1 >= FCount) then Error(@SListIndexError, Index1);
if (Index2 < 0) or (Index2 >= FCount) then Error(@SListIndexError, Index2);
Changing;
ExchangeItems(Index1, Index2);
Changed;
end;
procedure TAnsiStringList.ExchangeItems(Index1, Index2: Integer);
var
Temp: Pointer;
Item1, Item2: PStringItem;
begin
Item1 := @FList[Index1];
Item2 := @FList[Index2];
Temp := Pointer(Item1^.FString);
Pointer(Item1^.FString) := Pointer(Item2^.FString);
Pointer(Item2^.FString) := Temp;
Temp := Item1^.FObject;
Item1^.FObject := Item2^.FObject;
Item2^.FObject := Temp;
end;
function TAnsiStringList.Find(const S: AnsiString; var Index: Integer): Boolean;
var
L, H, I, C: Integer;
begin
Result := False;
L := 0;
H := FCount - 1;
while L <= H do
begin
I := (L + H) shr 1;
C := CompareAnsiStrings(FList[I].FAnsiString, S);
if C < 0 then L := I + 1 else
begin
H := I - 1;
if C = 0 then
begin
Result := True;
if Duplicates <> dupAccept then L := I;
end;
end;
end;
Index := L;
end;
function TAnsiStringList.Get(Index: Integer): AnsiString;
begin
if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index);
Result := FList[Index].FAnsiString;
end;
function TAnsiStringList.GetCapacity: Integer;
begin
Result := FCapacity;
end;
function TAnsiStringList.GetCount: Integer;
begin
Result := FCount;
end;
function TAnsiStringList.GetObject(Index: Integer): TObject;
begin
if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index);
Result := FList[Index].FObject;
end;
procedure TAnsiStringList.Grow;
var
Delta: Integer;
begin
if FCapacity > 64 then Delta := FCapacity div 4 else
if FCapacity > 8 then Delta := 16 else
Delta := 4;
SetCapacity(FCapacity + Delta);
end;
function TAnsiStringList.IndexOf(const S: AnsiString): Integer;
begin
if GetCount > 0 then
begin
if not Sorted then
Result := inherited IndexOf(S)
else
if not Find(S, Result) then
Result := -1;
end
else
Result := -1;
end;
procedure TAnsiStringList.Insert(Index: Integer; const S: AnsiString);
begin
InsertObject(Index, S, nil);
end;
procedure TAnsiStringList.InsertObject(Index: Integer; const S: AnsiString;
AObject: TObject);
begin
if Sorted then Error(@SSortedListError, 0);
if (Index < 0) or (Index > FCount) then Error(@SListIndexError, Index);
InsertItem(Index, S, AObject);
end;
procedure TAnsiStringList.InsertItem(Index: Integer; const S: AnsiString; AObject: TObject);
begin
Changing;
if FCount = FCapacity then Grow;
if Index < FCount then
System.Move(FList[Index], FList[Index + 1],
(FCount - Index) * SizeOf(TAnsiStringItem));
with FList[Index] do
begin
Pointer(FAnsiString) := nil;
FObject := AObject;
FAnsiString := S;
end;
Inc(FCount);
Changed;
end;
procedure TAnsiStringList.Put(Index: Integer; const S: AnsiString);
begin
if Sorted then Error(@SSortedListError, 0);
if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index);
Changing;
FList[Index].FAnsiString := S;
Changed;
end;
procedure TAnsiStringList.PutObject(Index: Integer; AObject: TObject);
begin
if (Index < 0) or (Index >= FCount) then Error(@SListIndexError, Index);
Changing;
FList[Index].FObject := AObject;
Changed;
end;
procedure TAnsiStringList.QuickSort(L, R: Integer; SCompare: TAnsiStringListSortCompare);
var
I, J, P: Integer;
begin
repeat
I := L;
J := R;
P := (L + R) shr 1;
repeat
while SCompare(Self, I, P) < 0 do Inc(I);
while SCompare(Self, J, P) > 0 do Dec(J);
if I <= J then
begin
if I <> J then
ExchangeItems(I, J);
if P = I then
P := J
else if P = J then
P := I;
Inc(I);
Dec(J);
end;
until I > J;
if L < J then QuickSort(L, J, SCompare);
L := I;
until I >= R;
end;
procedure TAnsiStringList.SetCapacity(NewCapacity: Integer);
begin
if (NewCapacity < FCount) then
Error(@SListCapacityError, NewCapacity);
if NewCapacity <> FCapacity then
begin
// ReallocMem(FList, NewCapacity * SizeOf(TAnsiStringItem));
SetLength(FList, NewCapacity);
FCapacity := NewCapacity;
end;
end;
procedure TAnsiStringList.SetSorted(Value: Boolean);
begin
if FSorted <> Value then
begin
if Value then Sort;
FSorted := Value;
end;
end;
procedure TAnsiStringList.SetUpdateState(Updating: Boolean);
begin
if Updating then Changing else Changed;
end;
function AnsiStringListCompareAnsiStrings(List: TAnsiStringList; Index1, Index2: Integer): Integer;
begin
Result := List.CompareAnsiStrings(List.FList[Index1].FAnsiString,
List.FList[Index2].FAnsiString);
end;
procedure TAnsiStringList.Sort;
begin
CustomSort(AnsiStringListCompareAnsiStrings);
end;
procedure TAnsiStringList.CustomSort(Compare: TAnsiStringListSortCompare);
begin
if not Sorted and (FCount > 1) then
begin
Changing;
QuickSort(0, FCount - 1, Compare);
Changed;
end;
end;
function TAnsiStringList.CompareAnsiStrings(const S1, S2: AnsiString): Integer;
begin
// if CaseSensitive then
Result := AnsiStrings.AnsiStrComp(PAnsiChar(S1), PAnsiChar(S2))
// else
// Result := AnsiCompareText(S1, S2);
end;
constructor TAnsiStringList.Create;
begin
inherited;
end;
constructor TAnsiStringList.Create(OwnsObjects: Boolean);
begin
inherited Create;
FOwnsObject := OwnsObjects;
end;
procedure TAnsiStringList.SetCaseSensitive(const Value: Boolean);
begin
if Value <> FCaseSensitive then
begin
FCaseSensitive := Value;
if Sorted then
begin
// Calling Sort won't sort the list because CustomSort will
// only sort the list if it's not already sorted
Sorted := False;
Sorted := True;
end;
end;
end;
end.