| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494 | {    This file is part of the Free Component Library (FCL)    Copyright (c) 1999-2000 by the Free Pascal development team    See the file COPYING.FPC, included in this distribution,    for details about the copyright.    This program is distributed in the hope that it will be useful,    but WITHOUT ANY WARRANTY; without even the implied warranty of    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. **********************************************************************}{****************************************************************************}{*                             TStrings                                     *}{****************************************************************************}// Function to quote text. Should move maybe to sysutils !!// Also, it is not clear at this point what exactly should be done.{ //!! is used to mark unsupported things. }Function QuoteString (Const S : String; Quote : String) : String;Var  I,J : Integer;begin  J:=0;  Result:=S;  for i:=1to length(s) do   begin     inc(j);     if S[i]=Quote then      begin        System.Insert(Quote,Result,J);        inc(j);      end;   end;  Result:=Quote+Result+Quote;end;{  For compatibility we can't add a Constructor to TSTrings to initialize  the special characters. Therefore we add a routine which is called whenever  the special chars are needed.}Procedure Tstrings.CheckSpecialChars;begin  If Not FSpecialCharsInited then    begin    FQuoteChar:='"';    FDelimiter:=',';    FNameValueSeparator:='=';    FSpecialCharsInited:=true;    FLBS:=DefaultTextLineBreakStyle;    end;end;Function TStrings.GetLBS : TTextLineBreakStyle;begin  CheckSpecialChars;  Result:=FLBS;end;Procedure TStrings.SetLBS (AValue : TTextLineBreakStyle);begin  CheckSpecialChars;  FLBS:=AValue;end;procedure TStrings.SetDelimiter(c:Char);begin  CheckSpecialChars;  FDelimiter:=c;end;procedure TStrings.SetQuoteChar(c:Char);begin  CheckSpecialChars;  FQuoteChar:=c;end;procedure TStrings.SetNameValueSeparator(c:Char);begin  CheckSpecialChars;  FNameValueSeparator:=c;end;function TStrings.GetCommaText: string;Var  C1,C2 : Char;  FSD : Boolean;begin  CheckSpecialChars;  FSD:=StrictDelimiter;  C1:=Delimiter;  C2:=QuoteChar;  Delimiter:=',';  QuoteChar:='"';  StrictDelimiter:=False;  Try    Result:=GetDelimitedText;  Finally    Delimiter:=C1;    QuoteChar:=C2;    StrictDelimiter:=FSD;  end;end;Function TStrings.GetDelimitedText: string;Var  I : integer;  p : pchar;  c : set of char;  S : String;  begin  CheckSpecialChars;  result:='';  if StrictDelimiter then    c:=[#0,Delimiter]  else      c:=[#0..' ',QuoteChar,Delimiter];  For i:=0 to count-1 do    begin    S:=Strings[i];    p:=pchar(S);    while not(p^ in c) do     inc(p);// strings in list may contain #0    if (p<>pchar(S)+length(S)) and not StrictDelimiter then      Result:=Result+QuoteString(S,QuoteChar)    else      Result:=Result+S;    if I<Count-1 then       Result:=Result+Delimiter;    end;  If (Length(Result)=0) and (Count=1) then    Result:=QuoteChar+QuoteChar;end;procedure TStrings.GetNameValue(Index : Integer; Out AName,AValue : String);Var L : longint;begin  CheckSpecialChars;  AValue:=Strings[Index];  L:=Pos(FNameValueSeparator,AValue);  If L<>0 then    begin    AName:=Copy(AValue,1,L-1);    System.Delete(AValue,1,L);    end  else    AName:='';end;function TStrings.ExtractName(const s:String):String;var  L: Longint;begin  CheckSpecialChars;  L:=Pos(FNameValueSeparator,S);  If L<>0 then    Result:=Copy(S,1,L-1)  else    Result:='';end;function TStrings.GetName(Index: Integer): string;Var  V : String;begin  GetNameValue(Index,Result,V);end;Function TStrings.GetValue(const Name: string): string;Var  L : longint;  N : String;begin  Result:='';  L:=IndexOfName(Name);  If L<>-1 then    GetNameValue(L,N,Result);end;Function TStrings.GetValueFromIndex(Index: Integer): string;Var  N : String;begin  GetNameValue(Index,N,Result);end;Procedure TStrings.SetValueFromIndex(Index: Integer; const Value: string);begin  If (Value='') then    Delete(Index)  else    begin    If (Index<0) then      Index:=Add('');    CheckSpecialChars;    Strings[Index]:=GetName(Index)+FNameValueSeparator+Value;    end;end;procedure TStrings.ReadData(Reader: TReader);begin  Reader.ReadListBegin;  BeginUpdate;  try    Clear;    while not Reader.EndOfList do      Add(Reader.ReadString);  finally    EndUpdate;  end;  Reader.ReadListEnd;end;Procedure TStrings.SetDelimitedText(const AValue: string);var i,j:integer;    aNotFirst:boolean;begin CheckSpecialChars; BeginUpdate; i:=1; j:=1; aNotFirst:=false; try  Clear;  If StrictDelimiter then    begin    // Easier, faster loop.    While I<=Length(AValue) do      begin      If (AValue[I] in [FDelimiter,#0]) then        begin        Add(Copy(AValue,J,I-J));        J:=I+1;        end;      Inc(i);      end;    If (Length(AValue)>0) then      Add(Copy(AValue,J,I-J));      end  else     begin    while i<=length(AValue) do begin     // skip delimiter     if aNotFirst and (i<=length(AValue)) and (AValue[i]=FDelimiter) then inc(i);     // skip spaces     while (i<=length(AValue)) and (Ord(AValue[i])<=Ord(' ')) do inc(i);         // read next string     if i<=length(AValue) then begin      if AValue[i]=FQuoteChar then begin       // next string is quoted       j:=i+1;       while (j<=length(AValue)) and             ( (AValue[j]<>FQuoteChar) or               ( (j+1<=length(AValue)) and (AValue[j+1]=FQuoteChar) ) ) do begin        if (j<=length(AValue)) and (AValue[j]=FQuoteChar) then inc(j,2)                                                          else inc(j);       end;       // j is position of closing quote       Add( StringReplace (Copy(AValue,i+1,j-i-1),                           FQuoteChar+FQuoteChar,FQuoteChar, [rfReplaceAll]));       i:=j+1;      end else begin       // next string is not quoted       j:=i;       while (j<=length(AValue)) and             (Ord(AValue[j])>Ord(' ')) and             (AValue[j]<>FDelimiter) do inc(j);       Add( Copy(AValue,i,j-i));       i:=j;      end;     end else begin      if aNotFirst then Add('');     end;     // skip spaces     while (i<=length(AValue)) and (Ord(AValue[i])<=Ord(' ')) do inc(i);     aNotFirst:=true;    end;    end; finally   EndUpdate; end;end;Procedure TStrings.SetCommaText(const Value: string);Var  C1,C2 : Char;begin  CheckSpecialChars;  C1:=Delimiter;  C2:=QuoteChar;  Delimiter:=',';  QuoteChar:='"';  Try    SetDelimitedText(Value);  Finally    Delimiter:=C1;    QuoteChar:=C2;  end;end;Procedure TStrings.SetStringsAdapter(const Value: IStringsAdapter);beginend;Procedure TStrings.SetValue(const Name, Value: string);Var L : longint;begin  CheckSpecialChars;  L:=IndexOfName(Name);  if L=-1 then   Add (Name+FNameValueSeparator+Value)  else   Strings[L]:=Name+FNameValueSeparator+value;end;procedure TStrings.WriteData(Writer: TWriter);var  i: Integer;begin  Writer.WriteListBegin;  for i := 0 to Count - 1 do    Writer.WriteString(Strings[i]);  Writer.WriteListEnd;end;procedure TStrings.DefineProperties(Filer: TFiler);var  HasData: Boolean;begin  if Assigned(Filer.Ancestor) then    // Only serialize if string list is different from ancestor    if Filer.Ancestor.InheritsFrom(TStrings) then      HasData := not Equals(TStrings(Filer.Ancestor))    else      HasData := True  else    HasData := Count > 0;  Filer.DefineProperty('Strings', @ReadData, @WriteData, HasData);end;Procedure TStrings.Error(const Msg: string; Data: Integer);begin  Raise EStringListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);end;Procedure TStrings.Error(const Msg: pstring; Data: Integer);begin  Raise EStringListError.CreateFmt(Msg^,[Data]) at get_caller_addr(get_frame);end;Function TStrings.GetCapacity: Integer;begin  Result:=Count;end;Function TStrings.GetObject(Index: Integer): TObject;begin  Result:=Nil;end;Function TStrings.GetTextStr: string;Var P : Pchar;    I,L,NLS : Longint;    S,NL : String;begin  CheckSpecialChars;  // Determine needed place  Case FLBS of    tlbsLF   : NL:=#10;    tlbsCRLF : NL:=#13#10;    tlbsCR   : NL:=#13;   end;  L:=0;  NLS:=Length(NL);  For I:=0 to count-1 do    L:=L+Length(Strings[I])+NLS;  Setlength(Result,L);  P:=Pointer(Result);  For i:=0 To count-1 do    begin    S:=Strings[I];    L:=Length(S);    if L<>0 then      System.Move(Pointer(S)^,P^,L);    P:=P+L;    For L:=1 to NLS do      begin      P^:=NL[L];      inc(P);      end;    end;end;Procedure TStrings.Put(Index: Integer; const S: string);Var Obj : TObject;begin  Obj:=Objects[Index];  Delete(Index);  InsertObject(Index,S,Obj);end;Procedure TStrings.PutObject(Index: Integer; AObject: TObject);begin  // Empty.end;Procedure TStrings.SetCapacity(NewCapacity: Integer);begin  // Empty.end;Function GetNextLine (Const Value : String; Var S : String; Var P : Integer) : Boolean;Var   PS : PChar;  IP,L : Integer;  begin  L:=Length(Value);  S:='';  Result:=False;  If ((L-P)<0) then     exit;  if ((L-P)=0) and (not (value[P] in [#10,#13])) Then    Begin      s:=value[P];      inc(P);      Exit(True);    End;  PS:=PChar(Value)+P-1;  IP:=P;  While ((L-P)>=0) and (not (PS^ in [#10,#13])) do     begin    P:=P+1;    Inc(PS);    end;  SetLength (S,P-IP);  System.Move (Value[IP],Pointer(S)^,P-IP);  If (P<=L) and (Value[P]=#13) then     Inc(P);  If (P<=L) and (Value[P]=#10) then    Inc(P); // Point to character after #10(#13)  Result:=True;end;Procedure TStrings.SetTextStr(const Value: string);Var  S : String;  P : Integer;begin  Try    beginUpdate;    Clear;    P:=1;    While GetNextLine (Value,S,P) do      Add(S);  finally    EndUpdate;  end;end;Procedure TStrings.SetUpdateState(Updating: Boolean);beginend;destructor TSTrings.Destroy;begin  inherited destroy;end;Function TStrings.Add(const S: string): Integer;begin  Result:=Count;  Insert (Count,S);end;Function TStrings.AddObject(const S: string; AObject: TObject): Integer;begin  Result:=Add(S);  Objects[result]:=AObject;end;Procedure TStrings.Append(const S: string);begin  Add (S);end;Procedure TStrings.AddStrings(TheStrings: TStrings);Var Runner : longint;begin  try    beginupdate;    For Runner:=0 to TheStrings.Count-1 do      self.AddObject (Thestrings[Runner],TheStrings.Objects[Runner]);  finally    EndUpdate;  end;end;Procedure TStrings.Assign(Source: TPersistent);Var  S : TStrings;begin  If Source is TStrings then    begin    S:=TStrings(Source);    BeginUpdate;    Try      clear;      FSpecialCharsInited:=S.FSpecialCharsInited;      FQuoteChar:=S.FQuoteChar;      FDelimiter:=S.FDelimiter;      FNameValueSeparator:=S.FNameValueSeparator;      FLBS:=S.FLBS;      AddStrings(S);    finally      EndUpdate;    end;    end  else    Inherited Assign(Source);end;Procedure TStrings.BeginUpdate;begin   if FUpdateCount = 0 then SetUpdateState(true);   inc(FUpdateCount);end;Procedure TStrings.EndUpdate;begin  If FUpdateCount>0 then     Dec(FUpdateCount);  if FUpdateCount=0 then    SetUpdateState(False);end;Function TStrings.Equals(TheStrings: TStrings): Boolean;Var Runner,Nr : Longint;begin  Result:=False;  Nr:=Self.Count;  if Nr<>TheStrings.Count then exit;  For Runner:=0 to Nr-1 do    If Strings[Runner]<>TheStrings[Runner] then exit;  Result:=True;end;Procedure TStrings.Exchange(Index1, Index2: Integer);Var  Obj : TObject;  Str : String;begin  Try    beginUpdate;    Obj:=Objects[Index1];    Str:=Strings[Index1];    Objects[Index1]:=Objects[Index2];    Strings[Index1]:=Strings[Index2];    Objects[Index2]:=Obj;    Strings[Index2]:=Str;  finally    EndUpdate;  end;end;Function TStrings.GetText: PChar;begin  Result:=StrNew(Pchar(Self.Text));end;Function TStrings.DoCompareText(const s1,s2 : string) : PtrInt;  begin    result:=CompareText(s1,s2);  end;Function TStrings.IndexOf(const S: string): Integer;begin  Result:=0;  While (Result<Count) and (DoCompareText(Strings[Result],S)<>0) do Result:=Result+1;  if Result=Count then Result:=-1;end;Function TStrings.IndexOfName(const Name: string): Integer;Var  len : longint;  S : String;begin  CheckSpecialChars;  Result:=0;  while (Result<Count) do    begin    S:=Strings[Result];    len:=pos(FNameValueSeparator,S)-1;    if (len>0) and (DoCompareText(Name,Copy(S,1,Len))=0) then      exit;    inc(result);    end;  result:=-1;end;Function TStrings.IndexOfObject(AObject: TObject): Integer;begin  Result:=0;  While (Result<count) and (Objects[Result]<>AObject) do Result:=Result+1;  If Result=Count then Result:=-1;end;Procedure TStrings.InsertObject(Index: Integer; const S: string;  AObject: TObject);begin  Insert (Index,S);  Objects[Index]:=AObject;end;Procedure TStrings.LoadFromFile(const FileName: string);Var        TheStream : TFileStream;begin  TheStream:=TFileStream.Create(FileName,fmOpenRead);  LoadFromStream(TheStream);  TheStream.Free;end;Procedure TStrings.LoadFromStream(Stream: TStream);{   Borlands method is no good, since a pipe for   instance doesn't have a size.   So we must do it the hard way.}Const  BufSize = 1024;  MaxGrow = 1 shl 29;Var  Buffer     : AnsiString;  BytesRead,  BufLen,  I,BufDelta     : Longint;begin  // reread into a buffer  try    beginupdate;    Buffer:='';    BufLen:=0;    I:=1;    Repeat      BufDelta:=BufSize*I;      SetLength(Buffer,BufLen+BufDelta);      BytesRead:=Stream.Read(Buffer[BufLen+1],BufDelta);      inc(BufLen,BufDelta);      If I<MaxGrow then        I:=I shl 1;    Until BytesRead<>BufDelta;    SetLength(Buffer, BufLen-BufDelta+BytesRead);    SetTextStr(Buffer);    SetLength(Buffer,0);  finally    EndUpdate;  end;end;Procedure TStrings.Move(CurIndex, NewIndex: Integer);Var  Obj : TObject;  Str : String;begin  BeginUpdate;  Obj:=Objects[CurIndex];  Str:=Strings[CurIndex];  Delete(Curindex);  InsertObject(NewIndex,Str,Obj);  EndUpdate;end;Procedure TStrings.SaveToFile(const FileName: string);Var TheStream : TFileStream;begin  TheStream:=TFileStream.Create(FileName,fmCreate);  SaveToStream(TheStream);  TheStream.Free;end;Procedure TStrings.SaveToStream(Stream: TStream);Var  S : String;begin  S:=Text;  Stream.WriteBuffer(Pointer(S)^,Length(S));end;Procedure TStrings.SetText(TheText: PChar);Var S : String;begin  If TheText<>Nil then    S:=StrPas(TheText)  else    S:='';  SetTextStr(S);  end;{****************************************************************************}{*                             TStringList                                  *}{****************************************************************************}{$if defined(VER2_0) or not defined(FPC_TESTGENERICS)}Procedure TStringList.ExchangeItems(Index1, Index2: Integer);Var P1,P2 : Pointer;begin  P1:=Pointer(Flist^[Index1].FString);  P2:=Pointer(Flist^[Index1].FObject);  Pointer(Flist^[Index1].Fstring):=Pointer(Flist^[Index2].Fstring);  Pointer(Flist^[Index1].FObject):=Pointer(Flist^[Index2].FObject);  Pointer(Flist^[Index2].Fstring):=P1;  Pointer(Flist^[Index2].FObject):=P2;end;Procedure TStringList.Grow;Var  NC : Integer;begin  NC:=FCapacity;  If NC>=256 then    NC:=NC+(NC Div 4)  else if NC=0 then    NC:=4  else    NC:=NC*4;  SetCapacity(NC);end;Procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);var  Pivot, vL, vR: Integer;begin  if R - L <= 1 then begin // a little bit of time saver    if L < R then      if CompareFn(Self, L, R) > 0 then        ExchangeItems(L, R);    Exit;  end;  vL := L;  vR := R;  Pivot := L + Random(R - L); // they say random is best  while vL < vR do begin    while (vL < Pivot) and (CompareFn(Self, vL, Pivot) <= 0) do      Inc(vL);    while (vR > Pivot) and (CompareFn(Self, vR, Pivot) > 0) do      Dec(vR);    ExchangeItems(vL, vR);    if Pivot = vL then // swap pivot if we just hit it from one side      Pivot := vR    else if Pivot = vR then      Pivot := vL;  end;  if Pivot - 1 >= L then    QuickSort(L, Pivot - 1, CompareFn);  if Pivot + 1 <= R then    QuickSort(Pivot + 1, R, CompareFn);end;Procedure TStringList.InsertItem(Index: Integer; const S: string);begin  Changing;  If FCount=Fcapacity then Grow;  If Index<FCount then    System.Move (FList^[Index],FList^[Index+1],                 (FCount-Index)*SizeOf(TStringItem));  Pointer(Flist^[Index].Fstring):=Nil;  // Needed to initialize...  Flist^[Index].FString:=S;  Flist^[Index].Fobject:=Nil;  Inc(FCount);  Changed;end;Procedure TStringList.InsertItem(Index: Integer; const S: string; O: TObject);begin  Changing;  If FCount=Fcapacity then Grow;  If Index<FCount then    System.Move (FList^[Index],FList^[Index+1],                 (FCount-Index)*SizeOf(TStringItem));  Pointer(Flist^[Index].Fstring):=Nil;  // Needed to initialize...  Flist^[Index].FString:=S;  Flist^[Index].FObject:=O;  Inc(FCount);  Changed;end;Procedure TStringList.SetSorted(Value: Boolean);begin  If FSorted<>Value then    begin    If Value then sort;    FSorted:=VAlue    end;end;Procedure TStringList.Changed;begin  If (FUpdateCount=0) Then   If Assigned(FOnChange) then     FOnchange(Self);end;Procedure TStringList.Changing;begin  If FUpdateCount=0 then    if Assigned(FOnChanging) then      FOnchanging(Self);end;Function TStringList.Get(Index: Integer): string;begin  If (Index<0) or (INdex>=Fcount)  then    Error (SListIndexError,Index);  Result:=Flist^[Index].FString;end;Function TStringList.GetCapacity: Integer;begin  Result:=FCapacity;end;Function TStringList.GetCount: Integer;begin  Result:=FCount;end;Function TStringList.GetObject(Index: Integer): TObject;begin  If (Index<0) or (INdex>=Fcount)  then    Error (SListIndexError,Index);  Result:=Flist^[Index].FObject;end;Procedure TStringList.Put(Index: Integer; const S: string);begin  If Sorted then    Error(SSortedListError,0);  If (Index<0) or (INdex>=Fcount)  then    Error (SListIndexError,Index);  Changing;  Flist^[Index].FString:=S;  Changed;end;Procedure TStringList.PutObject(Index: Integer; AObject: TObject);begin  If (Index<0) or (INdex>=Fcount)  then    Error (SListIndexError,Index);  Changing;  Flist^[Index].FObject:=AObject;  Changed;end;Procedure TStringList.SetCapacity(NewCapacity: Integer);Var NewList : Pointer;    MSize : Longint;begin  If (NewCapacity<0) then     Error (SListCapacityError,NewCapacity);  If NewCapacity>FCapacity then    begin    GetMem (NewList,NewCapacity*SizeOf(TStringItem));    If NewList=Nil then      Error (SListCapacityError,NewCapacity);    If Assigned(FList) then      begin      MSize:=FCapacity*Sizeof(TStringItem);      System.Move (FList^,NewList^,MSize);      FillWord (Pchar(NewList)[MSize],(NewCapacity-FCapacity)*WordRatio, 0);      FreeMem (Flist,MSize);      end;    Flist:=NewList;    FCapacity:=NewCapacity;    end  else if NewCapacity<FCapacity then    begin    if NewCapacity = 0 then    begin      FreeMem(FList);      FList := nil;    end else    begin      GetMem(NewList, NewCapacity * SizeOf(TStringItem));      System.Move(FList^, NewList^, NewCapacity * SizeOf(TStringItem));      FreeMem(FList);      FList := NewList;    end;    FCapacity:=NewCapacity;    end;end;Procedure TStringList.SetUpdateState(Updating: Boolean);begin  If Updating then    Changing  else    Changedend;destructor TStringList.Destroy;Var I : Longint;begin  FOnChange:=Nil;  FOnChanging:=Nil;  // This will force a dereference. Can be done better...  For I:=0 to FCount-1 do    FList^[I].FString:='';  FCount:=0;  SetCapacity(0);  Inherited destroy;end;Function TStringList.Add(const S: string): 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);end;Procedure TStringList.Clear;Var I : longint;begin  if FCount = 0 then Exit;  Changing;  For I:=0 to FCount-1 do    Flist^[I].FString:='';  FCount:=0;  SetCapacity(0);  Changed;end;Procedure TStringList.Delete(Index: Integer);begin  If (Index<0) or (Index>=FCount) then    Error(SlistINdexError,Index);  Changing;  Flist^[Index].FString:='';  Dec(FCount);  If Index<FCount then    System.Move(Flist^[Index+1],                Flist^[Index],                (Fcount-Index)*SizeOf(TStringItem));  Changed;end;Procedure TStringList.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 TStringList.SetCaseSensitive(b : boolean);  begin        if b<>FCaseSensitive then          begin                FCaseSensitive:=b;            if FSorted then              sort;          end;  end;Function TStringList.DoCompareText(const s1,s2 : string) : PtrInt;  begin        if FCaseSensitive then          result:=AnsiCompareStr(s1,s2)        else          result:=AnsiCompareText(s1,s2);  end;Function TStringList.Find(const S: string; var Index: Integer): Boolean;var  L, R, I: Integer;  CompareRes: PtrInt;begin  Result := false;  // Use binary search.  L := 0;  R := Count - 1;  while (L<=R) do  begin    I := L + (R - L) div 2;    CompareRes := DoCompareText(S, Flist^[I].FString);    if (CompareRes>0) then      L := I+1    else begin      R := I-1;      if (CompareRes=0) then begin         Result := true;         if (Duplicates<>dupAccept) then            L := I; // forces end of while loop      end;    end;  end;  Index := L;end;Function TStringList.IndexOf(const S: string): Integer;begin  If Not Sorted then    Result:=Inherited indexOf(S)  else    // faster using binary search...    If Not Find (S,Result) then      Result:=-1;end;Procedure TStringList.Insert(Index: Integer; const S: string);begin  If Sorted then    Error (SSortedListError,0)  else    If (Index<0) or (Index>FCount) then      Error (SListIndexError,Index)    else      InsertItem (Index,S);end;Procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);begin  If Not Sorted and (FCount>1) then    begin    Changing;    QuickSort(0,FCount-1, CompareFn);    Changed;    end;end;function StringListAnsiCompare(List: TStringList; Index1, Index: Integer): Integer;begin  Result := List.DoCompareText(List.FList^[Index1].FString,    List.FList^[Index].FString);end;Procedure TStringList.Sort;begin  CustomSort(@StringListAnsiCompare);end;{$else}{ generics based implementation of TStringList follows }function StringListAnsiCompare(List: TStringList; Index1, Index2: Integer): Integer;begin  Result := List.DoCompareText(List.Strings[Index1], List.Strings[Index2]);end;constructor TStringList.Create;begin  inherited;  FMap := TFPStrObjMap.Create;  FMap.OnPtrCompare := @MapPtrCompare;  FOnCompareText := @DefaultCompareText;end;destructor TStringList.Destroy;begin  FMap.Free;  inherited;end;function TStringList.GetDuplicates: TDuplicates;begin  Result := FMap.Duplicates;end;function TStringList.GetSorted: boolean;begin  Result := FMap.Sorted;end;procedure TStringList.SetDuplicates(NewDuplicates: TDuplicates);begin  FMap.Duplicates := NewDuplicates;end;procedure TStringList.SetSorted(NewSorted: Boolean);begin  FMap.Sorted := NewSorted;end;procedure TStringList.Changed;begin  if FUpdateCount = 0 then   if Assigned(FOnChange) then     FOnChange(Self);end;procedure TStringList.Changing;begin  if FUpdateCount = 0 then    if Assigned(FOnChanging) then      FOnChanging(Self);end;function TStringList.Get(Index: Integer): string;begin  Result := FMap.Keys[Index];end;function TStringList.GetCapacity: Integer;begin  Result := FMap.Capacity;end;function TStringList.GetCount: Integer;begin  Result := FMap.Count;end;function TStringList.GetObject(Index: Integer): TObject;begin  Result := FMap.Data[Index];end;procedure TStringList.Put(Index: Integer; const S: string);begin  Changing;  FMap.Keys[Index] := S;  Changed;end;procedure TStringList.PutObject(Index: Integer; AObject: TObject);begin  Changing;  FMap.Data[Index] := AObject;  Changed;end;procedure TStringList.SetCapacity(NewCapacity: Integer);begin  FMap.Capacity := NewCapacity;end;procedure TStringList.SetUpdateState(Updating: Boolean);begin  if Updating then    Changing  else    Changedend;function TStringList.Add(const S: string): Integer;begin  Result := FMap.Add(S);end;procedure TStringList.Clear;begin  if FMap.Count = 0 then exit;  Changing;  FMap.Clear;  Changed;end;procedure TStringList.Delete(Index: Integer);begin  if (Index < 0) or (Index >= FMap.Count) then    Error(SListIndexError, Index);  Changing;  FMap.Delete(Index);  Changed;end;procedure TStringList.Exchange(Index1, Index2: Integer);begin  if (Index1 < 0) or (Index1 >= FMap.Count) then    Error(SListIndexError, Index1);  if (Index2 < 0) or (Index2 >= FMap.Count) then    Error(SListIndexError, Index2);  Changing;  FMap.InternalExchange(Index1, Index2);  Changed;end;procedure TStringList.SetCaseSensitive(NewSensitive: Boolean);begin  if NewSensitive <> FCaseSensitive then  begin    FCaseSensitive := NewSensitive;    if Sorted then      Sort;  end;end;function TStringList.MapPtrCompare(Key1, Key2: Pointer): Integer;begin  Result := FOnCompareText(string(Key1^), string(Key2^));end;function TStringList.DefaultCompareText(const s1, s2: string): PtrInt;begin  if FCaseSensitive then    Result := AnsiCompareStr(s1, s2)  else    Result := AnsiCompareText(s1, s2);end;function TStringList.DoCompareText(const s1, s2: string): PtrInt;begin  Result := FOnCompareText(s1, s2);end;function TStringList.Find(const S: string; var Index: Integer): Boolean;begin  Result := FMap.Find(S, Index);end;function TStringList.IndexOf(const S: string): Integer;begin  Result := FMap.IndexOf(S);end;procedure TStringList.Insert(Index: Integer; const S: string);begin  if not Sorted and (0 <= Index) and (Index < FMap.Count) then    Changing;  FMap.InsertKey(Index, S);  Changed;end;procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);var   I, J, Pivot: Integer;begin  repeat    I := L;    J := R;    Pivot := (L + R) div 2;    repeat      while CompareFn(Self, I, Pivot) < 0 do Inc(I);      while CompareFn(Self, J, Pivot) > 0 do Dec(J);      if I <= J then      begin        FMap.InternalExchange(I, J); // No check, indices are correct.        if Pivot = I then          Pivot := J        else if Pivot = J then          Pivot := I;        Inc(I);        Dec(j);      end;    until I > J;    if L < J then       QuickSort(L,J, CompareFn);    L := I;  until I >= R;end;procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);begin  if not Sorted and (FMap.Count > 1) then  begin    Changing;    QuickSort(0, FMap.Count-1, CompareFn);    Changed;  end;end;procedure TStringList.Sort;begin  if not Sorted and (FMap.Count > 1) then  begin    Changing;    FMap.Sort;    Changed;  end;end;{$endif}
 |