123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373 |
- {
- 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.
- **********************************************************************}
- {****************************************************************************}
- {* TStringsEnumerator *}
- {****************************************************************************}
- constructor TStringsEnumerator.Create(AStrings: TStrings);
- begin
- inherited Create;
- FStrings := AStrings;
- FPosition := -1;
- end;
- function TStringsEnumerator.GetCurrent: String;
- begin
- Result := FStrings[FPosition];
- end;
- function TStringsEnumerator.MoveNext: Boolean;
- begin
- Inc(FPosition);
- Result := FPosition < FStrings.Count;
- end;
- {****************************************************************************}
- {* 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; Const Quote : String) : String;
- Var
- I,J : Integer;
- begin
- J:=0;
- Result:=S;
- for i:=1 to 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:='=';
- FLBS:=DefaultTextLineBreakStyle;
- FSpecialCharsInited:=true;
- FLineBreak:=sLineBreak;
- end;
- end;
- Function TStrings.GetSkipLastLineBreak : Boolean;
- begin
- Result:=not TrailingLineBreak;
- end;
- procedure TStrings.SetSkipLastLineBreak(const AValue : Boolean);
- begin
- TrailingLineBreak:=not AValue;
- 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.SetEncoding(const AEncoding: TEncoding);
- begin
- if (FEncoding<>nil) and not TEncoding.IsStandardEncoding(FEncoding) then
- FEncoding.Free;
- if TEncoding.IsStandardEncoding(AEncoding) then
- FEncoding:=AEncoding
- else if AEncoding<>nil then
- FEncoding:=AEncoding.Clone
- else
- FEncoding:=nil;
- end;
- Function TStrings.GetDelimiter : Char;
- begin
- CheckSpecialChars;
- Result:=FDelimiter;
- end;
- procedure TStrings.SetLineBreak(Const S : String);
- begin
- CheckSpecialChars;
- FLineBreak:=S;
- end;
- Function TStrings.GetLineBreak : String;
- begin
- CheckSpecialChars;
- Result:=FLineBreak;
- end;
- procedure TStrings.SetQuoteChar(c:Char);
- begin
- CheckSpecialChars;
- FQuoteChar:=c;
- end;
- Function TStrings.GetQuoteChar :Char;
- begin
- CheckSpecialChars;
- Result:=FQuoteChar;
- end;
- procedure TStrings.SetNameValueSeparator(c:Char);
- begin
- CheckSpecialChars;
- FNameValueSeparator:=c;
- end;
- Function TStrings.GetNameValueSeparator :Char;
- begin
- CheckSpecialChars;
- Result:=FNameValueSeparator;
- 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.GetLineBreakCharLBS: string;
- begin
- CheckSpecialChars;
- if FLineBreak<>sLineBreak then
- Result:=FLineBreak
- else
- Case FLBS of
- tlbsLF : Result:=#10;
- tlbsCRLF : Result:=#13#10;
- tlbsCR : Result:=#13;
- end;
- end;
- function TStrings.GetMissingNameValueSeparatorAction: TMissingNameValueSeparatorAction;
- begin
- CheckSpecialChars;
- Result:=FMissingNameValueSeparatorAction;
- end;
- Function TStrings.GetDelimitedText: string;
- Var
- I : integer;
- p : pchar;
- BreakChars : set of char;
- S : String;
- doQuote : Boolean;
-
- begin
- CheckSpecialChars;
- result:='';
- if StrictDelimiter then
- BreakChars:=[#0,QuoteChar,Delimiter]
- else
- BreakChars:=[#0..' ',QuoteChar,Delimiter];
- // Check for break characters and quote if required.
- For i:=0 to count-1 do
- begin
- S:=Strings[i];
- doQuote:=FAlwaysQuote;
- If not DoQuote then
- begin
- p:=pchar(S);
- //Quote strings that include BreakChars:
- while not(p^ in BreakChars) do
- inc(p);
- DoQuote:=(p<>pchar(S)+length(S));
- end;
- if DoQuote and (QuoteChar<>#0) then
- Result:=Result+QuoteString(S,QuoteChar)
- else
- Result:=Result+S;
- if I<Count-1 then
- Result:=Result+Delimiter;
- end;
- // Quote empty string:
- If (Length(Result)=0) and (Count=1) and (QuoteChar<>#0) then
- Result:=QuoteChar+QuoteChar;
- end;
- procedure TStrings.GetNameValue(Index : Integer; Out AName,AValue : String);
- Var L : longint;
- begin
- aName:='';
- 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
- case FMissingNameValueSeparatorAction of
- mnvaValue : ;
- mnvaName :
- begin
- aName:=aValue;
- aValue:='';
- end;
- mnvaEmpty :
- aValue:='';
- mnvaError :
- Raise EStringListError.CreateFmt(SErrNoNameValuePairAt,[Index]);
- end;
- 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;
- procedure TStrings.Filter(aFilter: TStringsFilterMethod; aList: TStrings);
- var
- S : string;
- begin
- for S in self do
- if aFilter(S) then
- aList.Add(S);
- end;
- procedure TStrings.ForEach(aCallback: TStringsForeachMethod);
- var
- S : String;
- begin
- for S in self do
- aCallBack(S);
- end;
- procedure TStrings.ForEach(aCallback: TStringsForeachMethodEx);
- var
- i: integer;
- begin
- for i:=0 to Count-1 do
- aCallBack(Strings[i],i);
- end;
- procedure TStrings.ForEach(aCallback: TStringsForeachMethodExObj);
- var
- i: integer;
- begin
- for i:=0 to Count-1 do
- aCallback(Strings[i],i,Objects[i]);
- end;
- function TStrings.Filter(aFilter: TStringsFilterMethod): TStrings;
- begin
- Result:=TStringsClass(Self.ClassType).Create;
- try
- Filter(aFilter,Result);
- except
- FreeAndNil(Result);
- Raise;
- end;
- end;
- procedure TStrings.Fill(const aValue: String; aStart, aEnd: Integer);
- var
- i: integer;
- begin
- if aEnd<0 then
- aEnd:=Self.Count+aEnd;
- if aEnd>=Count then
- aEnd:=Count-1;
- for i:=aStart to aEnd do
- Strings[i]:=aValue;
- end;
- Procedure TStrings.Map(aMap: TStringsMapMethod; aList : TStrings);
- Var
- S : String;
- begin
- For S in self do
- aList.Add(aMap(S));
- end;
- Function TStrings.Map(aMap: TStringsMapMethod) : TStrings;
- begin
- Result:=TStringsClass(Self.ClassType).Create;
- try
- Map(aMap,Result);
- except
- FreeAndNil(Result);
- Raise;
- end;
- end;
- function TStrings.Reduce(aReduceMethod: TStringsReduceMethod; const startingValue: string): string;
- var
- S : String;
- begin
- Result:=startingValue;
- for S in self do
- Result:=aReduceMethod(Result, S);
- end;
- Function TStrings.Reverse : TStrings;
- begin
- Result:=TStringsClass(Self.ClassType).Create;
- try
- Reverse(Result);
- except
- FreeAndNil(Result);
- Raise;
- end;
- end;
- Procedure TStrings.Reverse(aList : TStrings);
- Var
- I : Integer;
- begin
- for I:=Count-1 downto 0 do
- aList.Add(Strings[i]);
- end;
- Procedure TStrings.Slice(fromIndex: integer; aList : TStrings);
- var
- i: integer;
- begin
- for i:=fromIndex to Count-1 do
- aList.Add(Self[i]);
- end;
- Function TStrings.Slice(fromIndex: integer) : TStrings;
- begin
- Result:=TStringsClass(Self.ClassType).Create;
- try
- Slice(FromIndex,Result);
- except
- FreeAndNil(Result);
- Raise;
- end;
- end;
- function TStrings.GetName(Index: Integer): string;
- Var
- V : String;
- begin
- GetNameValue(Index,Result,V);
- end;
- function TStrings.GetStrictDelimiter: Boolean;
- begin
- Result:=soStrictDelimiter in FOptions;
- end;
- function TStrings.GetTrailingLineBreak: Boolean;
- begin
- Result:=soTrailingLineBreak in FOptions;
- end;
- function TStrings.GetUseLocale: Boolean;
- begin
- Result:=soUseLocale in FOptions;
- end;
- function TStrings.GetWriteBOM: Boolean;
- begin
- Result:=soWriteBOM in FOptions;
- 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);
- begin
- CheckSpecialChars;
- DoSetDelimitedText(aValue,True,StrictDelimiter,FQuoteChar,FDelimiter);
- end;
- Procedure TStrings.DoSetDelimitedText(const AValue: string; DoClear,aStrictDelimiter : Boolean; aQuoteChar,aDelimiter : Char);
- var
- len,i,j: SizeInt;
- aNotFirst:boolean;
- Procedure AddQuoted;
- begin
- Add(StringReplace(Copy(AValue,i+1,j-i-1),aQuoteChar+aQuoteChar,aQuoteChar, [rfReplaceAll]));
- end;
- Function CheckQuoted : Boolean;
- { Paraphrased from Delphi XE2 help:
- Strings must be separated by Delimiter characters or spaces.
- They may be enclosed in QuoteChars.
- QuoteChars in the string must be repeated to distinguish them from the QuoteChars enclosing the string.
- }
- begin
- Result:=(AValue[i]=aQuoteChar) and (aQuoteChar<>#0);
- If Not Result then
- exit;
- // next string is quoted
- j:=i+1;
- while (j<=len) and
- ((AValue[j]<>aQuoteChar) or
- ((j+1<=len) and (AValue[j+1]=aQuoteChar))) do
- begin
- if (j<=len) and (AValue[j]=aQuoteChar) then
- inc(j,2)
- else
- inc(j);
- end;
- AddQuoted;
- i:=j+1;
- end;
- Procedure MaybeSkipSpaces; inline;
- begin
- if Not aStrictDelimiter then
- while (i<=len) and (Ord(AValue[i])<=Ord(' ')) do
- inc(i);
- end;
- begin
- BeginUpdate;
- i:=1;
- j:=1;
- aNotFirst:=false;
- try
- if DoClear then
- Clear;
- len:=length(AValue);
- while i<=len do
- begin
- // skip delimiter
- if aNotFirst and (i<=len) and (AValue[i]=aDelimiter) then
- inc(i);
- MaybeSkipSpaces;
- // read next string
- if i>len then
- begin
- if aNotFirst then Add('');
- end
- else
- begin
- // next string is quoted
- if not CheckQuoted then
- begin
- // next string is not quoted; read until control character/space/delimiter
- j:=i;
- while (j<=len) and
- (aStrictDelimiter or (Ord(AValue[j])>Ord(' '))) and
- (AValue[j]<>aDelimiter) do
- inc(j);
- Add( Copy(AValue,i,j-i));
- i:=j;
- end;
- end;
- MaybeSkipSpaces;
- aNotFirst:=true;
- end; // While I<=Len
- finally
- EndUpdate;
- end;
- end;
- Procedure TStrings.SetCommaText(const Value: string);
- begin
- CheckSpecialChars;
- DoSetDelimitedText(Value,True,StrictDelimiter,'"',',');
- end;
- procedure TStrings.SetMissingNameValueSeparatorAction(AValue: TMissingNameValueSeparatorAction);
- begin
- CheckSpecialChars;
- FMissingNameValueSeparatorAction:=aValue;
- end;
- Procedure TStrings.SetStringsAdapter(const Value: IStringsAdapter);
- begin
- end;
- procedure TStrings.SetStrictDelimiter(AValue: Boolean);
- begin
- if AValue then
- Include(FOptions,soStrictDelimiter)
- else
- Exclude(FOptions,soStrictDelimiter);
- end;
- procedure TStrings.SetTrailingLineBreak(AValue: Boolean);
- begin
- if AValue then
- Include(FOptions,soTrailingLineBreak)
- else
- Exclude(FOptions,soTrailingLineBreak);
- end;
- procedure TStrings.SetUseLocale(AValue: Boolean);
- begin
- if AValue then
- Include(FOptions,soUseLocale)
- else
- Exclude(FOptions,soUseLocale);
- end;
- procedure TStrings.SetWriteBOM(AValue: Boolean);
- begin
- if AValue then
- Include(FOptions,soWriteBOM)
- else
- Exclude(FOptions,soWriteBOM);
- end;
- Procedure TStrings.SetDefaultEncoding(const ADefaultEncoding: TEncoding);
- begin
- if (FDefaultEncoding<>nil) and not TEncoding.IsStandardEncoding(FDefaultEncoding) then
- FDefaultEncoding.Free;
- if TEncoding.IsStandardEncoding(ADefaultEncoding) then
- FDefaultEncoding:=ADefaultEncoding
- else if ADefaultEncoding<>nil then
- FDefaultEncoding:=ADefaultEncoding.Clone
- else
- FDefaultEncoding:=TEncoding.Default;
- end;
- 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;
- function TStrings.CompareStrings(const s1,s2 : string) : Integer;
- begin
- Result := DoCompareText(s1, s2);
- 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), get_caller_frame(get_frame);
- end;
- Procedure TStrings.Error(const Msg: pstring; Data: Integer);
- begin
- Raise EStringListError.CreateFmt(Msg^,[Data]) at get_caller_addr(get_frame), get_caller_frame(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 : SizeInt;
- S,NL : String;
- begin
- NL:=GetLineBreakCharLBS;
- // Determine needed place
- L:=0;
- NLS:=Length(NL);
- For I:=0 to count-1 do
- L:=L+Length(Strings[I])+NLS;
- if SkipLastLineBreak then
- Dec(L,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;
- if (I<Count-1) or Not SkipLastLineBreak then
- 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;
- Class Function TStrings.GetNextLine (Const Value : String; Var S : String; Var P : SizeInt) : Boolean;
- var
- LengthOfValue: SizeInt;
- StartPos, FuturePos: SizeInt;
- begin
- LengthOfValue := Length(Value);
- StartPos := P;
- if (StartPos <= 0) or (StartPos > LengthOfValue) then // True for LengthOfValue <= 0
- begin
- S := '';
- Exit(False);
- end;
- FuturePos := StartPos;
- while (FuturePos <= LengthOfValue) and not (Value[FuturePos] in [#10, #13]) do
- Inc(FuturePos);
- // If we use S := Copy(Value, StartPos, FuturePos - StartPos); then compiler
- // generate TempS := Copy(...); S := TempS to eliminate side effects and
- // implicit "try finally" for TempS finalization
- // When we use SetString then no TempS, no try finally generated,
- // but we must check case when Value and S is same (side effects)
- if Pointer(S) = Pointer(Value) then
- System.Delete(S, FuturePos, High(FuturePos))
- else
- begin
- SetString(S, @Value[StartPos], FuturePos - StartPos);
- if (FuturePos <= LengthOfValue) and (Value[FuturePos] = #13) then
- Inc(FuturePos);
- if (FuturePos <= LengthOfValue) and (Value[FuturePos] = #10) then
- Inc(FuturePos);
- end;
- P := FuturePos;
- Result := True;
- end;
- Function TStrings.GetNextLineBreak (Const Value : String; Var S : String; Var P : SizeInt) : Boolean;
- var
- StartPos, FuturePos: SizeInt;
-
- begin
- StartPos := P;
- if (StartPos <= 0) or (StartPos > Length(Value)) then // True for Length <= 0
- begin
- S := '';
- Exit(False);
- end;
- FuturePos := Pos(FLineBreak, Value, StartPos); // Use PosEx in old RTL
- // Why we don't use Copy but use SetString read in GetNextLine
- if FuturePos = 0 then // No line breaks
- begin
- FuturePos := Length(Value) + 1;
- if Pointer(S) = Pointer(Value) then
- // Nothing to do
- else
- SetString(S, @Value[StartPos], FuturePos - StartPos)
- end
- else
- if Pointer(S) = Pointer(Value) then
- System.Delete(S, FuturePos, High(FuturePos))
- else
- begin
- SetString(S, @Value[StartPos], FuturePos - StartPos);
- Inc(FuturePos, Length(FLineBreak));
- end;
- P := FuturePos;
- Result := True;
- end;
- {$IF (SizeOf(Integer) < SizeOf(SizeInt)) }
- class function TStrings.GetNextLine(const Value: string; var S: string; var P: Integer) : Boolean;
- var
- LP: SizeInt;
- begin
- LP := P;
- Result := GetNextLine(Value, S, LP);
- P := LP;
- end;
- function TStrings.GetNextLineBreak(const Value: string; var S: string; var P: Integer) : Boolean;
- var
- LP: SizeInt;
- begin
- LP := P;
- Result := GetNextLineBreak(Value, S, LP);
- P := LP;
- end;
- {$IFEND}
- Procedure TStrings.DoSetTextStr(const Value: string; DoClear : Boolean);
- Var
- S : String;
- P : SizeInt;
- begin
- Try
- beginUpdate;
- if DoClear then
- Clear;
- P:=1;
- if FLineBreak=sLineBreak then
- begin
- While GetNextLine (Value,S,P) do
- Add(S)
- end
- else
- While GetNextLineBreak (Value,S,P) do
- Add(S);
- finally
- EndUpdate;
- end;
- end;
- Procedure TStrings.SetTextStr(const Value: string);
- begin
- CheckSpecialChars;
- DoSetTextStr(Value,True);
- end;
- Procedure TStrings.AddText(const S: string);
- begin
- CheckSpecialChars;
- DoSetTextStr(S,False);
- end;
- procedure TStrings.AddCommaText(const S: String);
- begin
- DoSetDelimitedText(S,False,StrictDelimiter,'"',',');
- end;
- procedure TStrings.AddDelimitedText(const S: String; ADelimiter: Char; AStrictDelimiter: Boolean);
- begin
- CheckSpecialChars;
- DoSetDelimitedText(S,False,AStrictDelimiter,FQuoteChar,ADelimiter);
- end;
- procedure TStrings.AddDelimitedText(const S: String);
- begin
- CheckSpecialChars;
- DoSetDelimitedText(S,False,StrictDelimiter,FQuoteChar,FDelimiter);
- end;
- Procedure TStrings.SetUpdateState(Updating: Boolean);
- begin
- FPONotifyObservers(Self,ooChange,Nil);
- end;
- destructor TSTrings.Destroy;
- begin
- if (FEncoding<>nil) and not TEncoding.IsStandardEncoding(FEncoding) then
- FreeAndNil(FEncoding);
- if (FDefaultEncoding<>nil) and not TEncoding.IsStandardEncoding(FDefaultEncoding) then
- FreeAndNil(FDefaultEncoding);
- inherited destroy;
- end;
- function TStrings.ToObjectArray: TObjectDynArray;
- begin
- Result:=ToObjectArray(0,Count-1);
- end;
- function TStrings.ToObjectArray(aStart,aEnd : Integer): TObjectDynArray;
- Var
- I : Integer;
- begin
- Result:=Nil;
- if aStart>aEnd then exit;
- SetLength(Result,aEnd-aStart+1);
- For I:=aStart to aEnd do
- Result[i-aStart]:=Objects[i];
- end;
- function TStrings.ToStringArray: TStringDynArray;
- begin
- Result:=ToStringArray(0,Count-1);
- end;
- function TStrings.ToStringArray(aStart,aEnd : Integer): TStringDynArray;
- Var
- I : Integer;
- begin
- Result:=Nil;
- if aStart>aEnd then exit;
- SetLength(Result,aEnd-aStart+1);
- For I:=aStart to aEnd do
- Result[i-aStart]:=Strings[i];
- end;
- constructor TStrings.Create;
- begin
- inherited Create;
- FDefaultEncoding:=TEncoding.Default;
- FEncoding:=nil;
- FOptions := [soTrailingLineBreak,soUseLocale,soPreserveBOM];
- FAlwaysQuote:=False;
- end;
- Function TStrings.Add(const S: string): Integer;
- begin
- Result:=Count;
- Insert (Count,S);
- end;
- function TStrings.Add(const Fmt : string; const Args : Array of const): Integer;
- begin
- Result:=Add(Format(Fmt,Args));
- end;
- Function TStrings.AddObject(const S: string; AObject: TObject): Integer;
- begin
- Result:=Add(S);
- Objects[result]:=AObject;
- end;
- function TStrings.AddObject(const Fmt: string; Args : Array of const; AObject: TObject): Integer;
- begin
- Result:=AddObject(Format(Fmt,Args),AObject);
- end;
- function TStrings.AddPair(const AName, AValue: string): TStrings;
- begin
- Result:=AddPair(AName,AValue,Nil);
- end;
- function TStrings.AddPair(const AName, AValue: string; AObject: TObject): TStrings;
- begin
- Result := Self;
- AddObject(Concat(AName, NameValueSeparator, AValue), AObject);
- end;
- Procedure TStrings.Append(const S: string);
- begin
- Add (S);
- end;
- Procedure TStrings.AddStrings(TheStrings: TStrings; ClearFirst : Boolean);
- Var Runner : longint;
- begin
- beginupdate;
- try
- if ClearFirst then
- Clear;
- if Count + TheStrings.Count > Capacity then
- Capacity := Count + TheStrings.Count;
- For Runner:=0 to TheStrings.Count-1 do
- self.AddObject (Thestrings[Runner],TheStrings.Objects[Runner]);
- finally
- EndUpdate;
- end;
- end;
- Procedure TStrings.AddStrings(TheStrings: TStrings);
- begin
- AddStrings(TheStrings, False);
- end;
- Procedure TStrings.AddStrings(const TheStrings: array of string);
- begin
- AddStrings(TheStrings, False);
- end;
- Procedure TStrings.AddStrings(const TheStrings: array of string; ClearFirst : Boolean);
- Var Runner : longint;
- begin
- beginupdate;
- try
- if ClearFirst then
- Clear;
- if Count + High(TheStrings)+1 > Capacity then
- Capacity := Count + High(TheStrings)+1;
- For Runner:=Low(TheStrings) to High(TheStrings) do
- self.Add(Thestrings[Runner]);
- finally
- EndUpdate;
- end;
- end;
- procedure TStrings.SetStrings(TheStrings: TStrings);
- begin
- AddStrings(TheStrings,True);
- end;
- procedure TStrings.SetStrings(TheStrings: array of string);
- begin
- AddStrings(TheStrings,True);
- 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;
- FLineBreak:=S.FLineBreak;
- FOptions:=S.FOptions;
- DefaultEncoding:=S.DefaultEncoding;
- SetEncoding(S.Encoding);
- 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(Obj: TObject): Boolean;
- begin
- if Obj is TStrings then
- Result := Equals(TStrings(Obj))
- else
- Result := inherited Equals(Obj);
- 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
- beginUpdate;
- Try
- 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.GetEnumerator: TStringsEnumerator;
- begin
- Result:=TStringsEnumerator.Create(Self);
- end;
- Function TStrings.GetText: PChar;
- begin
- Result:=StrNew(Pchar(Self.Text));
- end;
- Function TStrings.DoCompareText(const s1,s2 : string) : PtrInt;
- begin
- if UseLocale then
- result:=AnsiCompareText(s1,s2)
- else
- 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.IndexOf(const S: string; aStart: Integer): Integer;
- begin
- if aStart<0 then
- begin
- aStart:=Count+aStart;
- if aStart<0 then
- aStart:=0;
- end;
- Result:=aStart;
- 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;
- function TStrings.LastIndexOf(const S: string): Integer;
- begin
- Result:=LastIndexOf(S,Count-1);
- end;
- function TStrings.LastIndexOf(const S: string; aStart : Integer): Integer;
- begin
- if aStart<0 then
- begin
- aStart:=Count+aStart;
- if aStart<0 then
- aStart:=0;
- end;
- Result:=aStart;
- if Result>=Count-1 then
- Result:=Count-1;
- While (Result>=0) and (DoCompareText(Strings[Result],S)<>0) do
- Result:=Result-1;
- end;
- Procedure TStrings.LoadFromFile(const FileName: string);
- begin
- LoadFromFile(FileName,False)
- end;
- Procedure TStrings.LoadFromFile(const FileName: string; IgnoreEncoding : Boolean);
- Var
- TheStream : TFileStream;
- begin
- TheStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
- try
- LoadFromStream(TheStream, IgnoreEncoding);
- finally
- TheStream.Free;
- end;
- end;
- Procedure TStrings.LoadFromFile(const FileName: string; AEncoding: TEncoding);
- Var
- TheStream : TFileStream;
- begin
- TheStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
- try
- LoadFromStream(TheStream,AEncoding);
- finally
- TheStream.Free;
- end;
- end;
- Procedure TStrings.LoadFromStream(Stream: TStream);
- begin
- LoadFromStream(Stream,False);
- end;
- Const
- LoadBufSize = 1024;
- LoadMaxGrow = MaxInt Div 2;
- Procedure TStrings.LoadFromStream(Stream: TStream; IgnoreEncoding : Boolean);
- {
- Borlands method is no good, since a pipe for
- instance doesn't have a size.
- So we must do it the hard way.
- }
- Var
- Buffer : AnsiString;
- BufLen : SizeInt;
- BytesRead, I, BufDelta : Longint;
- begin
- if not IgnoreEncoding then
- begin
- LoadFromStream(Stream,Nil);
- Exit;
- end;
- // reread into a buffer
- beginupdate;
- try
- Buffer:='';
- BufLen:=0;
- I:=1;
- Repeat
- BufDelta:=LoadBufSize*I;
- SetLength(Buffer,BufLen+BufDelta);
- BytesRead:=Stream.Read(Buffer[BufLen+1],BufDelta);
- inc(BufLen,BufDelta);
- If I<LoadMaxGrow then
- I:=I shl 1;
- Until BytesRead<>BufDelta;
- SetLength(Buffer, BufLen-BufDelta+BytesRead);
- SetTextStr(Buffer);
- SetLength(Buffer,0);
- finally
- EndUpdate;
- end;
- if soPreserveBOM in FOptions then
- WriteBOM:=False;
- end;
- Procedure TStrings.LoadFromStream(Stream: TStream; AEncoding: TEncoding);
- {
- Borlands method is no good, since a pipe for
- instance doesn't have a size.
- So we must do it the hard way.
- }
- Var
- Buffer : TBytes;
- T : string;
- BufLen : SizeInt;
- BytesRead, I, BufDelta, PreambleLength : Longint;
- begin
- // reread into a buffer
- beginupdate;
- try
- SetLength(Buffer,0);
- BufLen:=0;
- I:=1;
- Repeat
- BufDelta:=LoadBufSize*I;
- SetLength(Buffer,BufLen+BufDelta);
- BytesRead:=Stream.Read(Buffer[BufLen],BufDelta);
- inc(BufLen,BufDelta);
- If I<LoadMaxGrow then
- I:=I shl 1;
- Until BytesRead<>BufDelta;
- SetLength(Buffer,BufLen-BufDelta+BytesRead);
- PreambleLength:=TEncoding.GetBufferEncoding(Buffer,AEncoding,FDefaultEncoding);
- T:=AEncoding.GetAnsiString(Buffer,PreambleLength,Length(Buffer)-PreambleLength);
- if soPreserveBOM in FOptions then
- WriteBOM:=PreambleLength>0;
- SetEncoding(AEncoding);
- SetLength(Buffer,0);
- SetTextStr(T);
- finally
- EndUpdate;
- end;
- end;
- Procedure TStrings.Move(CurIndex, NewIndex: Integer);
- Var
- Obj : TObject;
- Str : String;
- begin
- BeginUpdate;
- Try
- Obj:=Objects[CurIndex];
- Str:=Strings[CurIndex];
- Objects[CurIndex]:=Nil; // Prevent Delete from freeing.
- Delete(Curindex);
- InsertObject(NewIndex,Str,Obj);
- finally
- EndUpdate;
- end;
- end;
- function TStrings.Pop: string;
- var
- C : Integer;
- begin
- Result:='';
- C:=Count-1;
- if (C>=0) then
- begin
- Result:=Strings[C];
- Delete(C);
- end;
- end;
- function TStrings.Shift: String;
- begin
- Result:='';
- if (Count > 0) then
- begin
- Result:=Strings[0];
- Delete(0);
- end;
- end;
- Procedure TStrings.SaveToFile(const FileName: string);
- Var TheStream : TFileStream;
- begin
- TheStream:=TFileStream.Create(FileName,fmCreate);
- try
- SaveToStream(TheStream);
- finally
- TheStream.Free;
- end;
- end;
- Procedure TStrings.SaveToFile(const FileName: string; IgnoreEncoding : Boolean);
- Var TheStream : TFileStream;
- begin
- TheStream:=TFileStream.Create(FileName,fmCreate);
- try
- SaveToStream(TheStream, IgnoreEncoding);
- finally
- TheStream.Free;
- end;
- end;
- Procedure TStrings.SaveToFile(const FileName: string; AEncoding: TEncoding);
- Var TheStream : TFileStream;
- begin
- TheStream:=TFileStream.Create(FileName,fmCreate);
- try
- SaveToStream(TheStream,AEncoding);
- finally
- TheStream.Free;
- end;
- end;
- Procedure TStrings.SaveToStream(Stream: TStream);
- begin
- SaveToStream(Stream,False)
- end;
- Procedure TStrings.SaveToStream(Stream: TStream; IgnoreEncoding: Boolean);
- Var
- I,L,NLS : SizeInt;
- S,NL : String;
- begin
- if not IgnoreEncoding then
- begin
- SaveToStream(Stream,FEncoding);
- Exit;
- end;
- NL:=GetLineBreakCharLBS;
- NLS:=Length(NL)*SizeOf(Char);
- For i:=0 To count-1 do
- begin
- S:=Strings[I];
- L:=Length(S);
- if L<>0 then
- Stream.WriteBuffer(S[1], L*SizeOf(Char));
- if (I<Count-1) or Not SkipLastLineBreak then
- Stream.WriteBuffer(NL[1], NLS);
- end;
- end;
- Procedure TStrings.SaveToStream(Stream: TStream; AEncoding: TEncoding);
- Var B,BNL : TBytes;
- NL,S: string;
- i,BNLS: SizeInt;
- begin
- if AEncoding=nil then
- AEncoding:=FDefaultEncoding;
- if WriteBOM then
- begin
- B:=AEncoding.GetPreamble;
- if Length(B)>0 then
- Stream.WriteBuffer(B[0],Length(B));
- end;
- NL := GetLineBreakCharLBS;
- BNL:=AEncoding.GetAnsiBytes(NL);
- BNLS:=Length(BNL);
- For i:=0 To count-1 do
- begin
- S:=Strings[I];
- if S<>'' then
- begin
- B:=AEncoding.GetAnsiBytes(S);
- Stream.WriteBuffer(B[0],Length(B));
- end;
- if (I<Count-1) or Not SkipLastLineBreak then
- Stream.WriteBuffer(BNL[0],BNLS);
- end;
- end;
- Procedure TStrings.SetText(TheText: PChar);
- Var S : String;
- begin
- If TheText<>Nil then
- S:=StrPas(TheText)
- else
- S:='';
- SetTextStr(S);
- end;
- {****************************************************************************}
- {* TStringList *}
- {****************************************************************************}
- {$if not defined(FPC_TESTGENERICS)}
- procedure TStringList.ExchangeItemsInt(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;
- function TStringList.GetSorted: Boolean;
- begin
- Result:=FSortStyle in [sslUser,sslAuto];
- end;
- procedure TStringList.ExchangeItems(Index1, Index2: Integer);
- begin
- ExchangeItemsInt(Index1, Index2);
- 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.InternalClear(FromIndex: Integer; ClearOnly: Boolean);
- Var
- I: Integer;
- begin
- if FromIndex < FCount then
- begin
- if FOwnsObjects then
- begin
- For I:=FromIndex to FCount-1 do
- begin
- Flist^[I].FString:='';
- freeandnil(Flist^[i].FObject);
- end;
- end
- else
- begin
- For I:=FromIndex to FCount-1 do
- Flist^[I].FString:='';
- end;
- FCount:=FromIndex;
- end;
- if Not ClearOnly then
- SetCapacity(0);
- end;
- procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare
- );
- var
- Pivot, vL, vR: Integer;
- ExchangeProc: procedure(Left, Right: Integer) of object;
- begin
- //if ExchangeItems is override call that, else call (faster) ExchangeItemsInt
- if TMethod(@Self.ExchangeItems).Code = CodePointer(@TStringList.ExchangeItems) then
- ExchangeProc := @ExchangeItemsInt
- else
- ExchangeProc := @ExchangeItems;
- if R - L <= 1 then begin // a little bit of time saver
- if L < R then
- if CompareFn(Self, L, R) > 0 then
- ExchangeProc(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);
- ExchangeProc(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
- InsertItem(Index, S, nil);
- 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 Value then
- SortStyle:=sslAuto
- else
- SortStyle:=sslNone
- end;
- procedure TStringList.Changed;
- begin
- If (FUpdateCount=0) Then
- begin
- If Assigned(FOnChange) then
- FOnchange(Self);
- FPONotifyObservers(Self,ooChange,Nil);
- end;
- end;
- procedure TStringList.Changing;
- begin
- If FUpdateCount=0 then
- if Assigned(FOnChanging) then
- FOnchanging(Self);
- end;
- function TStringList.Get(Index: Integer): string;
- begin
- CheckIndex(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
- CheckIndex(Index);
- Result:=Flist^[Index].FObject;
- end;
- procedure TStringList.Put(Index: Integer; const S: string);
- begin
- If Sorted then
- Error(SSortedListError,0);
- CheckIndex(Index);
- Changing;
- Flist^[Index].FString:=S;
- Changed;
- end;
- procedure TStringList.PutObject(Index: Integer; AObject: TObject);
- begin
- CheckIndex(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)*(SizeOf(TStringItem) div SizeOf(Word)), 0);
- FreeMem (Flist,MSize);
- end;
- Flist:=NewList;
- FCapacity:=NewCapacity;
- end
- else if NewCapacity<FCapacity then
- begin
- if NewCapacity = 0 then
- begin
- if FCount > 0 then
- InternalClear(0,True);
- FreeMem(FList);
- FList := nil;
- end else
- begin
- InternalClear(NewCapacity,True);
- 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
- Changed
- end;
- Constructor TStringList.Create;
- begin
- inherited Create;
- end;
- Constructor TStringList.Create(anOwnsObjects : Boolean);
- begin
- inherited Create;
- FOwnsObjects:=anOwnsObjects;
- end;
- destructor TStringList.Destroy;
- begin
- InternalClear;
- Inherited destroy;
- end;
- function TStringList.Add(const S: string): Integer;
- begin
- If (SortStyle<>sslAuto) 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;
- begin
- if FCount = 0 then Exit;
- Changing;
- InternalClear;
- Changed;
- end;
- procedure TStringList.Delete(Index: Integer);
- begin
- CheckIndex(Index);
- Changing;
- Flist^[Index].FString:='';
- if FOwnsObjects then
- FreeAndNil(Flist^[Index].FObject);
- 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
- CheckIndex(Index1);
- CheckIndex(Index2);
- Changing;
- ExchangeItemsInt(Index1,Index2);
- changed;
- end;
- procedure TStringList.SetCaseSensitive(b : boolean);
- begin
- if b=FCaseSensitive then
- Exit;
- FCaseSensitive:=b;
- if FSortStyle=sslAuto then
- begin
- FForceSort:=True;
- try
- Sort;
- finally
- FForceSort:=False;
- end;
- end;
- end;
- procedure TStringList.SetSortStyle(AValue: TStringsSortStyle);
- begin
- if FSortStyle=AValue then Exit;
- if (AValue=sslAuto) then
- Sort;
- FSortStyle:=AValue;
- end;
- procedure TStringList.CheckIndex(AIndex: Integer);
- begin
- If (AIndex<0) or (AIndex>=FCount) then
- Error(SListIndexError,AIndex);
- end;
- function TStringList.DoCompareText(const s1, s2: string): PtrInt;
- begin
- if FCaseSensitive then
- begin
- if UseLocale then
- result:=AnsiCompareStr(s1,s2)
- else
- result:=CompareStr(s1,s2);
- end else
- begin
- if UseLocale then
- result:=AnsiCompareText(s1,s2)
- else
- result:=CompareText(s1,s2);
- end;
- end;
- function TStringList.Find(const S: string; out Index: Integer): Boolean;
- var
- L, R, I: Integer;
- CompareRes: PtrInt;
- begin
- Result := false;
- Index:=-1;
- if Not Sorted then
- Raise EListError.Create(SErrFindNeedsSortedList);
- // 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 SortStyle=sslAuto then
- Error (SSortedListError,0)
- else
- begin
- If (Index<0) or (Index>FCount) then
- Error(SListIndexError,Index); // Cannot use CheckIndex, because there >= FCount...
- InsertItem (Index,S);
- end;
- end;
- procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
- begin
- If (FCount>1) and (FForceSort or (FSortStyle<>sslAuto)) 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;
- FOwnsObjects:=false;
- FMap := TFPStrObjMap.Create;
- FMap.OnPtrCompare := @MapPtrCompare;
- FOnCompareText := @DefaultCompareText;
- NameValueSeparator:='=';
- CheckSpecialChars;
- 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
- Changed
- end;
- 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}
|