stringl.inc 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {****************************************************************************}
  11. {* TStringsEnumerator *}
  12. {****************************************************************************}
  13. constructor TStringsEnumerator.Create(AStrings: TStrings);
  14. begin
  15. inherited Create;
  16. FStrings := AStrings;
  17. FPosition := -1;
  18. end;
  19. function TStringsEnumerator.GetCurrent: String;
  20. begin
  21. Result := FStrings[FPosition];
  22. end;
  23. function TStringsEnumerator.MoveNext: Boolean;
  24. begin
  25. Inc(FPosition);
  26. Result := FPosition < FStrings.Count;
  27. end;
  28. {****************************************************************************}
  29. {* TStrings *}
  30. {****************************************************************************}
  31. // Function to quote text. Should move maybe to sysutils !!
  32. // Also, it is not clear at this point what exactly should be done.
  33. { //!! is used to mark unsupported things. }
  34. Function QuoteString (Const S : String; Const Quote : String) : String;
  35. Var
  36. I,J : Integer;
  37. begin
  38. J:=0;
  39. Result:=S;
  40. for i:=1 to length(s) do
  41. begin
  42. inc(j);
  43. if S[i]=Quote then
  44. begin
  45. System.Insert(Quote,Result,J);
  46. inc(j);
  47. end;
  48. end;
  49. Result:=Quote+Result+Quote;
  50. end;
  51. {
  52. For compatibility we can't add a Constructor to TSTrings to initialize
  53. the special characters. Therefore we add a routine which is called whenever
  54. the special chars are needed.
  55. }
  56. Procedure Tstrings.CheckSpecialChars;
  57. begin
  58. If Not FSpecialCharsInited then
  59. begin
  60. FQuoteChar:='"';
  61. FDelimiter:=',';
  62. FNameValueSeparator:='=';
  63. FLBS:=DefaultTextLineBreakStyle;
  64. FSpecialCharsInited:=true;
  65. FLineBreak:=sLineBreak;
  66. end;
  67. end;
  68. Function TStrings.GetLBS : TTextLineBreakStyle;
  69. begin
  70. CheckSpecialChars;
  71. Result:=FLBS;
  72. end;
  73. Procedure TStrings.SetLBS (AValue : TTextLineBreakStyle);
  74. begin
  75. CheckSpecialChars;
  76. FLBS:=AValue;
  77. end;
  78. procedure TStrings.SetDelimiter(c:Char);
  79. begin
  80. CheckSpecialChars;
  81. FDelimiter:=c;
  82. end;
  83. Function TStrings.GetDelimiter : Char;
  84. begin
  85. CheckSpecialChars;
  86. Result:=FDelimiter;
  87. end;
  88. procedure TStrings.SetLineBreak(Const S : String);
  89. begin
  90. CheckSpecialChars;
  91. FLineBreak:=S;
  92. end;
  93. Function TStrings.GetLineBreak : String;
  94. begin
  95. CheckSpecialChars;
  96. Result:=FLineBreak;
  97. end;
  98. procedure TStrings.SetQuoteChar(c:Char);
  99. begin
  100. CheckSpecialChars;
  101. FQuoteChar:=c;
  102. end;
  103. Function TStrings.GetQuoteChar :Char;
  104. begin
  105. CheckSpecialChars;
  106. Result:=FQuoteChar;
  107. end;
  108. procedure TStrings.SetNameValueSeparator(c:Char);
  109. begin
  110. CheckSpecialChars;
  111. FNameValueSeparator:=c;
  112. end;
  113. Function TStrings.GetNameValueSeparator :Char;
  114. begin
  115. CheckSpecialChars;
  116. Result:=FNameValueSeparator;
  117. end;
  118. function TStrings.GetCommaText: string;
  119. Var
  120. C1,C2 : Char;
  121. FSD : Boolean;
  122. begin
  123. CheckSpecialChars;
  124. FSD:=StrictDelimiter;
  125. C1:=Delimiter;
  126. C2:=QuoteChar;
  127. Delimiter:=',';
  128. QuoteChar:='"';
  129. StrictDelimiter:=False;
  130. Try
  131. Result:=GetDelimitedText;
  132. Finally
  133. Delimiter:=C1;
  134. QuoteChar:=C2;
  135. StrictDelimiter:=FSD;
  136. end;
  137. end;
  138. Function TStrings.GetDelimitedText: string;
  139. Var
  140. I : integer;
  141. p : pchar;
  142. BreakChars : set of char;
  143. S : String;
  144. begin
  145. CheckSpecialChars;
  146. result:='';
  147. if StrictDelimiter then
  148. BreakChars:=[#0,QuoteChar,Delimiter]
  149. else
  150. BreakChars:=[#0..' ',QuoteChar,Delimiter];
  151. // Check for break characters and quote if required.
  152. For i:=0 to count-1 do
  153. begin
  154. S:=Strings[i];
  155. p:=pchar(S);
  156. //Quote strings that include BreakChars:
  157. while not(p^ in BreakChars) do
  158. inc(p);
  159. if (p<>pchar(S)+length(S)) then
  160. Result:=Result+QuoteString(S,QuoteChar)
  161. else
  162. Result:=Result+S;
  163. if I<Count-1 then
  164. Result:=Result+Delimiter;
  165. end;
  166. // Quote empty string:
  167. If (Length(Result)=0) and (Count=1) then
  168. Result:=QuoteChar+QuoteChar;
  169. end;
  170. procedure TStrings.GetNameValue(Index : Integer; Out AName,AValue : String);
  171. Var L : longint;
  172. begin
  173. CheckSpecialChars;
  174. AValue:=Strings[Index];
  175. L:=Pos(FNameValueSeparator,AValue);
  176. If L<>0 then
  177. begin
  178. AName:=Copy(AValue,1,L-1);
  179. System.Delete(AValue,1,L);
  180. end
  181. else
  182. AName:='';
  183. end;
  184. function TStrings.ExtractName(const s:String):String;
  185. var
  186. L: Longint;
  187. begin
  188. CheckSpecialChars;
  189. L:=Pos(FNameValueSeparator,S);
  190. If L<>0 then
  191. Result:=Copy(S,1,L-1)
  192. else
  193. Result:='';
  194. end;
  195. function TStrings.GetName(Index: Integer): string;
  196. Var
  197. V : String;
  198. begin
  199. GetNameValue(Index,Result,V);
  200. end;
  201. Function TStrings.GetValue(const Name: string): string;
  202. Var
  203. L : longint;
  204. N : String;
  205. begin
  206. Result:='';
  207. L:=IndexOfName(Name);
  208. If L<>-1 then
  209. GetNameValue(L,N,Result);
  210. end;
  211. Function TStrings.GetValueFromIndex(Index: Integer): string;
  212. Var
  213. N : String;
  214. begin
  215. GetNameValue(Index,N,Result);
  216. end;
  217. Procedure TStrings.SetValueFromIndex(Index: Integer; const Value: string);
  218. begin
  219. If (Value='') then
  220. Delete(Index)
  221. else
  222. begin
  223. If (Index<0) then
  224. Index:=Add('');
  225. CheckSpecialChars;
  226. Strings[Index]:=GetName(Index)+FNameValueSeparator+Value;
  227. end;
  228. end;
  229. procedure TStrings.ReadData(Reader: TReader);
  230. begin
  231. Reader.ReadListBegin;
  232. BeginUpdate;
  233. try
  234. Clear;
  235. while not Reader.EndOfList do
  236. Add(Reader.ReadString);
  237. finally
  238. EndUpdate;
  239. end;
  240. Reader.ReadListEnd;
  241. end;
  242. Procedure TStrings.SetDelimitedText(const AValue: string);
  243. var i,j:integer;
  244. aNotFirst:boolean;
  245. begin
  246. CheckSpecialChars;
  247. BeginUpdate;
  248. i:=1;
  249. j:=1;
  250. aNotFirst:=false;
  251. { Paraphrased from Delphi XE2 help:
  252. Strings must be separated by Delimiter characters or spaces.
  253. They may be enclosed in QuoteChars.
  254. QuoteChars in the string must be repeated to distinguish them from the QuoteChars enclosing the string.
  255. }
  256. try
  257. Clear;
  258. If StrictDelimiter then
  259. begin
  260. while i<=length(AValue) do begin
  261. // skip delimiter
  262. if aNotFirst and (i<=length(AValue)) and (AValue[i]=FDelimiter) then inc(i);
  263. // read next string
  264. if i<=length(AValue) then begin
  265. if AValue[i]=FQuoteChar then begin
  266. // next string is quoted
  267. j:=i+1;
  268. while (j<=length(AValue)) and
  269. ( (AValue[j]<>FQuoteChar) or
  270. ( (j+1<=length(AValue)) and (AValue[j+1]=FQuoteChar) ) ) do begin
  271. if (j<=length(AValue)) and (AValue[j]=FQuoteChar) then inc(j,2)
  272. else inc(j);
  273. end;
  274. // j is position of closing quote
  275. Add( StringReplace (Copy(AValue,i+1,j-i-1),
  276. FQuoteChar+FQuoteChar,FQuoteChar, [rfReplaceAll]));
  277. i:=j+1;
  278. end else begin
  279. // next string is not quoted; read until delimiter
  280. j:=i;
  281. while (j<=length(AValue)) and
  282. (AValue[j]<>FDelimiter) do inc(j);
  283. Add( Copy(AValue,i,j-i));
  284. i:=j;
  285. end;
  286. end else begin
  287. if aNotFirst then Add('');
  288. end;
  289. aNotFirst:=true;
  290. end;
  291. end
  292. else
  293. begin
  294. while i<=length(AValue) do begin
  295. // skip delimiter
  296. if aNotFirst and (i<=length(AValue)) and (AValue[i]=FDelimiter) then inc(i);
  297. // skip spaces
  298. while (i<=length(AValue)) and (Ord(AValue[i])<=Ord(' ')) do inc(i);
  299. // read next string
  300. if i<=length(AValue) then begin
  301. if AValue[i]=FQuoteChar then begin
  302. // next string is quoted
  303. j:=i+1;
  304. while (j<=length(AValue)) and
  305. ( (AValue[j]<>FQuoteChar) or
  306. ( (j+1<=length(AValue)) and (AValue[j+1]=FQuoteChar) ) ) do begin
  307. if (j<=length(AValue)) and (AValue[j]=FQuoteChar) then inc(j,2)
  308. else inc(j);
  309. end;
  310. // j is position of closing quote
  311. Add( StringReplace (Copy(AValue,i+1,j-i-1),
  312. FQuoteChar+FQuoteChar,FQuoteChar, [rfReplaceAll]));
  313. i:=j+1;
  314. end else begin
  315. // next string is not quoted; read until control character/space/delimiter
  316. j:=i;
  317. while (j<=length(AValue)) and
  318. (Ord(AValue[j])>Ord(' ')) and
  319. (AValue[j]<>FDelimiter) do inc(j);
  320. Add( Copy(AValue,i,j-i));
  321. i:=j;
  322. end;
  323. end else begin
  324. if aNotFirst then Add('');
  325. end;
  326. // skip spaces
  327. while (i<=length(AValue)) and (Ord(AValue[i])<=Ord(' ')) do inc(i);
  328. aNotFirst:=true;
  329. end;
  330. end;
  331. finally
  332. EndUpdate;
  333. end;
  334. end;
  335. Procedure TStrings.SetCommaText(const Value: string);
  336. Var
  337. C1,C2 : Char;
  338. begin
  339. CheckSpecialChars;
  340. C1:=Delimiter;
  341. C2:=QuoteChar;
  342. Delimiter:=',';
  343. QuoteChar:='"';
  344. Try
  345. SetDelimitedText(Value);
  346. Finally
  347. Delimiter:=C1;
  348. QuoteChar:=C2;
  349. end;
  350. end;
  351. Procedure TStrings.SetStringsAdapter(const Value: IStringsAdapter);
  352. begin
  353. end;
  354. Procedure TStrings.SetValue(const Name, Value: string);
  355. Var L : longint;
  356. begin
  357. CheckSpecialChars;
  358. L:=IndexOfName(Name);
  359. if L=-1 then
  360. Add (Name+FNameValueSeparator+Value)
  361. else
  362. Strings[L]:=Name+FNameValueSeparator+value;
  363. end;
  364. procedure TStrings.WriteData(Writer: TWriter);
  365. var
  366. i: Integer;
  367. begin
  368. Writer.WriteListBegin;
  369. for i := 0 to Count - 1 do
  370. Writer.WriteString(Strings[i]);
  371. Writer.WriteListEnd;
  372. end;
  373. procedure TStrings.DefineProperties(Filer: TFiler);
  374. var
  375. HasData: Boolean;
  376. begin
  377. if Assigned(Filer.Ancestor) then
  378. // Only serialize if string list is different from ancestor
  379. if Filer.Ancestor.InheritsFrom(TStrings) then
  380. HasData := not Equals(TStrings(Filer.Ancestor))
  381. else
  382. HasData := True
  383. else
  384. HasData := Count > 0;
  385. Filer.DefineProperty('Strings', @ReadData, @WriteData, HasData);
  386. end;
  387. Procedure TStrings.Error(const Msg: string; Data: Integer);
  388. begin
  389. Raise EStringListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  390. end;
  391. Procedure TStrings.Error(const Msg: pstring; Data: Integer);
  392. begin
  393. Raise EStringListError.CreateFmt(Msg^,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  394. end;
  395. Function TStrings.GetCapacity: Integer;
  396. begin
  397. Result:=Count;
  398. end;
  399. Function TStrings.GetObject(Index: Integer): TObject;
  400. begin
  401. Result:=Nil;
  402. end;
  403. Function TStrings.GetTextStr: string;
  404. Var P : Pchar;
  405. I,L,NLS : Longint;
  406. S,NL : String;
  407. begin
  408. CheckSpecialChars;
  409. // Determine needed place
  410. if FLineBreak<>sLineBreak then
  411. NL:=FLineBreak
  412. else
  413. Case FLBS of
  414. tlbsLF : NL:=#10;
  415. tlbsCRLF : NL:=#13#10;
  416. tlbsCR : NL:=#13;
  417. end;
  418. L:=0;
  419. NLS:=Length(NL);
  420. For I:=0 to count-1 do
  421. L:=L+Length(Strings[I])+NLS;
  422. Setlength(Result,L);
  423. P:=Pointer(Result);
  424. For i:=0 To count-1 do
  425. begin
  426. S:=Strings[I];
  427. L:=Length(S);
  428. if L<>0 then
  429. System.Move(Pointer(S)^,P^,L);
  430. P:=P+L;
  431. For L:=1 to NLS do
  432. begin
  433. P^:=NL[L];
  434. inc(P);
  435. end;
  436. end;
  437. end;
  438. Procedure TStrings.Put(Index: Integer; const S: string);
  439. Var Obj : TObject;
  440. begin
  441. Obj:=Objects[Index];
  442. Delete(Index);
  443. InsertObject(Index,S,Obj);
  444. end;
  445. Procedure TStrings.PutObject(Index: Integer; AObject: TObject);
  446. begin
  447. // Empty.
  448. end;
  449. Procedure TStrings.SetCapacity(NewCapacity: Integer);
  450. begin
  451. // Empty.
  452. end;
  453. Class Function TStrings.GetNextLine (Const Value : String; Var S : String; Var P : Integer) : Boolean;
  454. Var
  455. PS : PChar;
  456. IP,L : Integer;
  457. begin
  458. L:=Length(Value);
  459. S:='';
  460. Result:=False;
  461. If ((L-P)<0) then
  462. exit;
  463. if ((L-P)=0) and (not (value[P] in [#10,#13])) Then
  464. Begin
  465. s:=value[P];
  466. inc(P);
  467. Exit(True);
  468. End;
  469. PS:=PChar(Value)+P-1;
  470. IP:=P;
  471. While ((L-P)>=0) and (not (PS^ in [#10,#13])) do
  472. begin
  473. P:=P+1;
  474. Inc(PS);
  475. end;
  476. SetLength (S,P-IP);
  477. System.Move (Value[IP],Pointer(S)^,P-IP);
  478. If (P<=L) and (Value[P]=#13) then
  479. Inc(P);
  480. If (P<=L) and (Value[P]=#10) then
  481. Inc(P); // Point to character after #10(#13)
  482. Result:=True;
  483. end;
  484. Function TStrings.GetNextLineBreak (Const Value : String; Var S : String; Var P : Integer) : Boolean;
  485. Var
  486. PS,PC,PP : PChar;
  487. IP,L : Integer;
  488. begin
  489. S:='';
  490. Result:=False;
  491. If ((Length(Value)-P)<=0) then
  492. exit;
  493. PS:=@Value[P];
  494. PC:=PS;
  495. PP:=AnsiStrPos(PS,PChar(FLineBreak));
  496. // Stop on #0.
  497. While (PC^<>#0) and (PC<>PP) do
  498. Inc(PC);
  499. P:=P+(PC-PS)+Length(FLineBreak);
  500. SetString(S,PS,PC-PS);
  501. Result:=True;
  502. end;
  503. Procedure TStrings.DoSetTextStr(const Value: string; DoClear : Boolean);
  504. Var
  505. S : String;
  506. P : Integer;
  507. begin
  508. Try
  509. beginUpdate;
  510. if DoClear then
  511. Clear;
  512. P:=1;
  513. if FLineBreak=sLineBreak then
  514. begin
  515. While GetNextLine (Value,S,P) do
  516. Add(S)
  517. end
  518. else
  519. While GetNextLineBreak (Value,S,P) do
  520. Add(S);
  521. finally
  522. EndUpdate;
  523. end;
  524. end;
  525. Procedure TStrings.SetTextStr(const Value: string);
  526. begin
  527. CheckSpecialChars;
  528. DoSetTextStr(Value,True);
  529. end;
  530. Procedure TStrings.AddText(const S: string);
  531. begin
  532. CheckSpecialChars;
  533. DoSetTextStr(S,False);
  534. end;
  535. Procedure TStrings.SetUpdateState(Updating: Boolean);
  536. begin
  537. FPONotifyObservers(Self,ooChange,Nil);
  538. end;
  539. destructor TSTrings.Destroy;
  540. begin
  541. inherited destroy;
  542. end;
  543. Function TStrings.Add(const S: string): Integer;
  544. begin
  545. Result:=Count;
  546. Insert (Count,S);
  547. end;
  548. function TStrings.Add(const Fmt : string; const Args : Array of const): Integer;
  549. begin
  550. Result:=Add(Format(Fmt,Args));
  551. end;
  552. Function TStrings.AddObject(const S: string; AObject: TObject): Integer;
  553. begin
  554. Result:=Add(S);
  555. Objects[result]:=AObject;
  556. end;
  557. function TStrings.AddObject(const Fmt: string; Args : Array of const; AObject: TObject): Integer;
  558. begin
  559. Result:=AddObject(Format(Fmt,Args),AObject);
  560. end;
  561. Procedure TStrings.Append(const S: string);
  562. begin
  563. Add (S);
  564. end;
  565. Procedure TStrings.AddStrings(TheStrings: TStrings);
  566. Var Runner : longint;
  567. begin
  568. beginupdate;
  569. try
  570. For Runner:=0 to TheStrings.Count-1 do
  571. self.AddObject (Thestrings[Runner],TheStrings.Objects[Runner]);
  572. finally
  573. EndUpdate;
  574. end;
  575. end;
  576. Procedure TStrings.AddStrings(const TheStrings: array of string);
  577. Var Runner : longint;
  578. begin
  579. try
  580. beginupdate;
  581. if Count + High(TheStrings)+1 > Capacity then
  582. Capacity := Count + High(TheStrings)+1;
  583. For Runner:=Low(TheStrings) to High(TheStrings) do
  584. self.Add(Thestrings[Runner]);
  585. finally
  586. EndUpdate;
  587. end;
  588. end;
  589. Procedure TStrings.Assign(Source: TPersistent);
  590. Var
  591. S : TStrings;
  592. begin
  593. If Source is TStrings then
  594. begin
  595. S:=TStrings(Source);
  596. BeginUpdate;
  597. Try
  598. clear;
  599. FSpecialCharsInited:=S.FSpecialCharsInited;
  600. FQuoteChar:=S.FQuoteChar;
  601. FDelimiter:=S.FDelimiter;
  602. FNameValueSeparator:=S.FNameValueSeparator;
  603. FLBS:=S.FLBS;
  604. FLineBreak:=S.FLineBreak;
  605. AddStrings(S);
  606. finally
  607. EndUpdate;
  608. end;
  609. end
  610. else
  611. Inherited Assign(Source);
  612. end;
  613. Procedure TStrings.BeginUpdate;
  614. begin
  615. if FUpdateCount = 0 then SetUpdateState(true);
  616. inc(FUpdateCount);
  617. end;
  618. Procedure TStrings.EndUpdate;
  619. begin
  620. If FUpdateCount>0 then
  621. Dec(FUpdateCount);
  622. if FUpdateCount=0 then
  623. SetUpdateState(False);
  624. end;
  625. Function TStrings.Equals(Obj: TObject): Boolean;
  626. begin
  627. if Obj is TStrings then
  628. Result := Equals(TStrings(Obj))
  629. else
  630. Result := inherited Equals(Obj);
  631. end;
  632. Function TStrings.Equals(TheStrings: TStrings): Boolean;
  633. Var Runner,Nr : Longint;
  634. begin
  635. Result:=False;
  636. Nr:=Self.Count;
  637. if Nr<>TheStrings.Count then exit;
  638. For Runner:=0 to Nr-1 do
  639. If Strings[Runner]<>TheStrings[Runner] then exit;
  640. Result:=True;
  641. end;
  642. Procedure TStrings.Exchange(Index1, Index2: Integer);
  643. Var
  644. Obj : TObject;
  645. Str : String;
  646. begin
  647. beginUpdate;
  648. Try
  649. Obj:=Objects[Index1];
  650. Str:=Strings[Index1];
  651. Objects[Index1]:=Objects[Index2];
  652. Strings[Index1]:=Strings[Index2];
  653. Objects[Index2]:=Obj;
  654. Strings[Index2]:=Str;
  655. finally
  656. EndUpdate;
  657. end;
  658. end;
  659. function TStrings.GetEnumerator: TStringsEnumerator;
  660. begin
  661. Result:=TStringsEnumerator.Create(Self);
  662. end;
  663. Function TStrings.GetText: PChar;
  664. begin
  665. Result:=StrNew(Pchar(Self.Text));
  666. end;
  667. Function TStrings.DoCompareText(const s1,s2 : string) : PtrInt;
  668. begin
  669. result:=CompareText(s1,s2);
  670. end;
  671. Function TStrings.IndexOf(const S: string): Integer;
  672. begin
  673. Result:=0;
  674. While (Result<Count) and (DoCompareText(Strings[Result],S)<>0) do Result:=Result+1;
  675. if Result=Count then Result:=-1;
  676. end;
  677. Function TStrings.IndexOfName(const Name: string): Integer;
  678. Var
  679. len : longint;
  680. S : String;
  681. begin
  682. CheckSpecialChars;
  683. Result:=0;
  684. while (Result<Count) do
  685. begin
  686. S:=Strings[Result];
  687. len:=pos(FNameValueSeparator,S)-1;
  688. if (len>=0) and (DoCompareText(Name,Copy(S,1,Len))=0) then
  689. exit;
  690. inc(result);
  691. end;
  692. result:=-1;
  693. end;
  694. Function TStrings.IndexOfObject(AObject: TObject): Integer;
  695. begin
  696. Result:=0;
  697. While (Result<count) and (Objects[Result]<>AObject) do Result:=Result+1;
  698. If Result=Count then Result:=-1;
  699. end;
  700. Procedure TStrings.InsertObject(Index: Integer; const S: string;
  701. AObject: TObject);
  702. begin
  703. Insert (Index,S);
  704. Objects[Index]:=AObject;
  705. end;
  706. Procedure TStrings.LoadFromFile(const FileName: string);
  707. Var
  708. TheStream : TFileStream;
  709. begin
  710. TheStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
  711. try
  712. LoadFromStream(TheStream);
  713. finally
  714. TheStream.Free;
  715. end;
  716. end;
  717. Procedure TStrings.LoadFromStream(Stream: TStream);
  718. {
  719. Borlands method is no good, since a pipe for
  720. instance doesn't have a size.
  721. So we must do it the hard way.
  722. }
  723. Const
  724. BufSize = 1024;
  725. MaxGrow = 1 shl 29;
  726. Var
  727. Buffer : AnsiString;
  728. BytesRead,
  729. BufLen,
  730. I,BufDelta : Longint;
  731. begin
  732. // reread into a buffer
  733. beginupdate;
  734. try
  735. Buffer:='';
  736. BufLen:=0;
  737. I:=1;
  738. Repeat
  739. BufDelta:=BufSize*I;
  740. SetLength(Buffer,BufLen+BufDelta);
  741. BytesRead:=Stream.Read(Buffer[BufLen+1],BufDelta);
  742. inc(BufLen,BufDelta);
  743. If I<MaxGrow then
  744. I:=I shl 1;
  745. Until BytesRead<>BufDelta;
  746. SetLength(Buffer, BufLen-BufDelta+BytesRead);
  747. SetTextStr(Buffer);
  748. SetLength(Buffer,0);
  749. finally
  750. EndUpdate;
  751. end;
  752. end;
  753. Procedure TStrings.Move(CurIndex, NewIndex: Integer);
  754. Var
  755. Obj : TObject;
  756. Str : String;
  757. begin
  758. BeginUpdate;
  759. Try
  760. Obj:=Objects[CurIndex];
  761. Str:=Strings[CurIndex];
  762. Objects[CurIndex]:=Nil; // Prevent Delete from freeing.
  763. Delete(Curindex);
  764. InsertObject(NewIndex,Str,Obj);
  765. finally
  766. EndUpdate;
  767. end;
  768. end;
  769. Procedure TStrings.SaveToFile(const FileName: string);
  770. Var TheStream : TFileStream;
  771. begin
  772. TheStream:=TFileStream.Create(FileName,fmCreate);
  773. try
  774. SaveToStream(TheStream);
  775. finally
  776. TheStream.Free;
  777. end;
  778. end;
  779. Procedure TStrings.SaveToStream(Stream: TStream);
  780. Var
  781. S : String;
  782. begin
  783. S:=Text;
  784. if S = '' then Exit;
  785. Stream.WriteBuffer(Pointer(S)^,Length(S));
  786. end;
  787. Procedure TStrings.SetText(TheText: PChar);
  788. Var S : String;
  789. begin
  790. If TheText<>Nil then
  791. S:=StrPas(TheText)
  792. else
  793. S:='';
  794. SetTextStr(S);
  795. end;
  796. {****************************************************************************}
  797. {* TStringList *}
  798. {****************************************************************************}
  799. {$if not defined(FPC_TESTGENERICS)}
  800. Procedure TStringList.ExchangeItemsInt(Index1, Index2: Integer);
  801. Var P1,P2 : Pointer;
  802. begin
  803. P1:=Pointer(Flist^[Index1].FString);
  804. P2:=Pointer(Flist^[Index1].FObject);
  805. Pointer(Flist^[Index1].Fstring):=Pointer(Flist^[Index2].Fstring);
  806. Pointer(Flist^[Index1].FObject):=Pointer(Flist^[Index2].FObject);
  807. Pointer(Flist^[Index2].Fstring):=P1;
  808. Pointer(Flist^[Index2].FObject):=P2;
  809. end;
  810. Procedure TStringList.ExchangeItems(Index1, Index2: Integer);
  811. begin
  812. ExchangeItemsInt(Index1, Index2);
  813. end;
  814. Procedure TStringList.Grow;
  815. Var
  816. NC : Integer;
  817. begin
  818. NC:=FCapacity;
  819. If NC>=256 then
  820. NC:=NC+(NC Div 4)
  821. else if NC=0 then
  822. NC:=4
  823. else
  824. NC:=NC*4;
  825. SetCapacity(NC);
  826. end;
  827. Procedure TStringList.InternalClear(FromIndex : Integer = 0; ClearOnly : Boolean = False);
  828. Var
  829. I: Integer;
  830. begin
  831. if FromIndex < FCount then
  832. begin
  833. if FOwnsObjects then
  834. begin
  835. For I:=FromIndex to FCount-1 do
  836. begin
  837. Flist^[I].FString:='';
  838. freeandnil(Flist^[i].FObject);
  839. end;
  840. end
  841. else
  842. begin
  843. For I:=FromIndex to FCount-1 do
  844. Flist^[I].FString:='';
  845. end;
  846. FCount:=FromIndex;
  847. end;
  848. if Not ClearOnly then
  849. SetCapacity(0);
  850. end;
  851. Procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  852. var
  853. Pivot, vL, vR: Integer;
  854. ExchangeProc: procedure(Left, Right: Integer) of object;
  855. begin
  856. //if ExchangeItems is override call that, else call (faster) ExchangeItemsInt
  857. if TMethod(@Self.ExchangeItems).Code = CodePointer(@TStringList.ExchangeItems) then
  858. ExchangeProc := @ExchangeItemsInt
  859. else
  860. ExchangeProc := @ExchangeItems;
  861. if R - L <= 1 then begin // a little bit of time saver
  862. if L < R then
  863. if CompareFn(Self, L, R) > 0 then
  864. ExchangeProc(L, R);
  865. Exit;
  866. end;
  867. vL := L;
  868. vR := R;
  869. Pivot := L + Random(R - L); // they say random is best
  870. while vL < vR do begin
  871. while (vL < Pivot) and (CompareFn(Self, vL, Pivot) <= 0) do
  872. Inc(vL);
  873. while (vR > Pivot) and (CompareFn(Self, vR, Pivot) > 0) do
  874. Dec(vR);
  875. ExchangeProc(vL, vR);
  876. if Pivot = vL then // swap pivot if we just hit it from one side
  877. Pivot := vR
  878. else if Pivot = vR then
  879. Pivot := vL;
  880. end;
  881. if Pivot - 1 >= L then
  882. QuickSort(L, Pivot - 1, CompareFn);
  883. if Pivot + 1 <= R then
  884. QuickSort(Pivot + 1, R, CompareFn);
  885. end;
  886. Procedure TStringList.InsertItem(Index: Integer; const S: string);
  887. begin
  888. InsertItem(Index, S, nil);
  889. end;
  890. Procedure TStringList.InsertItem(Index: Integer; const S: string; O: TObject);
  891. begin
  892. Changing;
  893. If FCount=Fcapacity then Grow;
  894. If Index<FCount then
  895. System.Move (FList^[Index],FList^[Index+1],
  896. (FCount-Index)*SizeOf(TStringItem));
  897. Pointer(Flist^[Index].Fstring):=Nil; // Needed to initialize...
  898. Flist^[Index].FString:=S;
  899. Flist^[Index].FObject:=O;
  900. Inc(FCount);
  901. Changed;
  902. end;
  903. Procedure TStringList.SetSorted(Value: Boolean);
  904. begin
  905. If FSorted<>Value then
  906. begin
  907. If Value then sort;
  908. FSorted:=VAlue
  909. end;
  910. end;
  911. Procedure TStringList.Changed;
  912. begin
  913. If (FUpdateCount=0) Then
  914. begin
  915. If Assigned(FOnChange) then
  916. FOnchange(Self);
  917. FPONotifyObservers(Self,ooChange,Nil);
  918. end;
  919. end;
  920. Procedure TStringList.Changing;
  921. begin
  922. If FUpdateCount=0 then
  923. if Assigned(FOnChanging) then
  924. FOnchanging(Self);
  925. end;
  926. Function TStringList.Get(Index: Integer): string;
  927. begin
  928. If (Index<0) or (INdex>=Fcount) then
  929. Error (SListIndexError,Index);
  930. Result:=Flist^[Index].FString;
  931. end;
  932. Function TStringList.GetCapacity: Integer;
  933. begin
  934. Result:=FCapacity;
  935. end;
  936. Function TStringList.GetCount: Integer;
  937. begin
  938. Result:=FCount;
  939. end;
  940. Function TStringList.GetObject(Index: Integer): TObject;
  941. begin
  942. If (Index<0) or (INdex>=Fcount) then
  943. Error (SListIndexError,Index);
  944. Result:=Flist^[Index].FObject;
  945. end;
  946. Procedure TStringList.Put(Index: Integer; const S: string);
  947. begin
  948. If Sorted then
  949. Error(SSortedListError,0);
  950. If (Index<0) or (INdex>=Fcount) then
  951. Error (SListIndexError,Index);
  952. Changing;
  953. Flist^[Index].FString:=S;
  954. Changed;
  955. end;
  956. Procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  957. begin
  958. If (Index<0) or (INdex>=Fcount) then
  959. Error (SListIndexError,Index);
  960. Changing;
  961. Flist^[Index].FObject:=AObject;
  962. Changed;
  963. end;
  964. Procedure TStringList.SetCapacity(NewCapacity: Integer);
  965. Var NewList : Pointer;
  966. I,MSize : Longint;
  967. begin
  968. If (NewCapacity<0) then
  969. Error (SListCapacityError,NewCapacity);
  970. If NewCapacity>FCapacity then
  971. begin
  972. GetMem (NewList,NewCapacity*SizeOf(TStringItem));
  973. If NewList=Nil then
  974. Error (SListCapacityError,NewCapacity);
  975. If Assigned(FList) then
  976. begin
  977. MSize:=FCapacity*Sizeof(TStringItem);
  978. System.Move (FList^,NewList^,MSize);
  979. FillWord (Pchar(NewList)[MSize],(NewCapacity-FCapacity)*WordRatio, 0);
  980. FreeMem (Flist,MSize);
  981. end;
  982. Flist:=NewList;
  983. FCapacity:=NewCapacity;
  984. end
  985. else if NewCapacity<FCapacity then
  986. begin
  987. if NewCapacity = 0 then
  988. begin
  989. if FCount > 0 then
  990. InternalClear(0,True);
  991. FreeMem(FList);
  992. FList := nil;
  993. end else
  994. begin
  995. InternalClear(NewCapacity,True);
  996. GetMem(NewList, NewCapacity * SizeOf(TStringItem));
  997. System.Move(FList^, NewList^, NewCapacity * SizeOf(TStringItem));
  998. FreeMem(FList);
  999. FList := NewList;
  1000. end;
  1001. FCapacity:=NewCapacity;
  1002. end;
  1003. end;
  1004. Procedure TStringList.SetUpdateState(Updating: Boolean);
  1005. begin
  1006. If Updating then
  1007. Changing
  1008. else
  1009. Changed
  1010. end;
  1011. destructor TStringList.Destroy;
  1012. begin
  1013. InternalClear;
  1014. Inherited destroy;
  1015. end;
  1016. Function TStringList.Add(const S: string): Integer;
  1017. begin
  1018. If Not Sorted then
  1019. Result:=FCount
  1020. else
  1021. If Find (S,Result) then
  1022. Case DUplicates of
  1023. DupIgnore : Exit;
  1024. DupError : Error(SDuplicateString,0)
  1025. end;
  1026. InsertItem (Result,S);
  1027. end;
  1028. Procedure TStringList.Clear;
  1029. begin
  1030. if FCount = 0 then Exit;
  1031. Changing;
  1032. InternalClear;
  1033. Changed;
  1034. end;
  1035. Procedure TStringList.Delete(Index: Integer);
  1036. begin
  1037. If (Index<0) or (Index>=FCount) then
  1038. Error(SlistINdexError,Index);
  1039. Changing;
  1040. Flist^[Index].FString:='';
  1041. if FOwnsObjects then
  1042. FreeAndNil(Flist^[Index].FObject);
  1043. Dec(FCount);
  1044. If Index<FCount then
  1045. System.Move(Flist^[Index+1],
  1046. Flist^[Index],
  1047. (Fcount-Index)*SizeOf(TStringItem));
  1048. Changed;
  1049. end;
  1050. Procedure TStringList.Exchange(Index1, Index2: Integer);
  1051. begin
  1052. If (Index1<0) or (Index1>=FCount) then
  1053. Error(SListIndexError,Index1);
  1054. If (Index2<0) or (Index2>=FCount) then
  1055. Error(SListIndexError,Index2);
  1056. Changing;
  1057. ExchangeItemsInt(Index1,Index2);
  1058. changed;
  1059. end;
  1060. procedure TStringList.SetCaseSensitive(b : boolean);
  1061. begin
  1062. if b=FCaseSensitive then
  1063. Exit;
  1064. FCaseSensitive:=b;
  1065. if FSorted then
  1066. begin
  1067. FForceSort:=True;
  1068. sort;
  1069. FForceSort:=False;
  1070. end;
  1071. end;
  1072. Function TStringList.DoCompareText(const s1,s2 : string) : PtrInt;
  1073. begin
  1074. if FCaseSensitive then
  1075. result:=AnsiCompareStr(s1,s2)
  1076. else
  1077. result:=AnsiCompareText(s1,s2);
  1078. end;
  1079. function TStringList.CompareStrings(const s1,s2 : string) : Integer;
  1080. begin
  1081. Result := DoCompareText(s1, s2);
  1082. end;
  1083. Function TStringList.Find(const S: string; Out Index: Integer): Boolean;
  1084. var
  1085. L, R, I: Integer;
  1086. CompareRes: PtrInt;
  1087. begin
  1088. Result := false;
  1089. if Not Sorted then
  1090. exit;
  1091. // Use binary search.
  1092. L := 0;
  1093. R := Count - 1;
  1094. while (L<=R) do
  1095. begin
  1096. I := L + (R - L) div 2;
  1097. CompareRes := DoCompareText(S, Flist^[I].FString);
  1098. if (CompareRes>0) then
  1099. L := I+1
  1100. else begin
  1101. R := I-1;
  1102. if (CompareRes=0) then begin
  1103. Result := true;
  1104. if (Duplicates<>dupAccept) then
  1105. L := I; // forces end of while loop
  1106. end;
  1107. end;
  1108. end;
  1109. Index := L;
  1110. end;
  1111. Function TStringList.IndexOf(const S: string): Integer;
  1112. begin
  1113. If Not Sorted then
  1114. Result:=Inherited indexOf(S)
  1115. else
  1116. // faster using binary search...
  1117. If Not Find (S,Result) then
  1118. Result:=-1;
  1119. end;
  1120. Procedure TStringList.Insert(Index: Integer; const S: string);
  1121. begin
  1122. If Sorted then
  1123. Error (SSortedListError,0)
  1124. else
  1125. If (Index<0) or (Index>FCount) then
  1126. Error (SListIndexError,Index)
  1127. else
  1128. InsertItem (Index,S);
  1129. end;
  1130. Procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1131. begin
  1132. If (FForceSort or (Not Sorted)) and (FCount>1) then
  1133. begin
  1134. Changing;
  1135. QuickSort(0,FCount-1, CompareFn);
  1136. Changed;
  1137. end;
  1138. end;
  1139. function StringListAnsiCompare(List: TStringList; Index1, Index: Integer): Integer;
  1140. begin
  1141. Result := List.DoCompareText(List.FList^[Index1].FString,
  1142. List.FList^[Index].FString);
  1143. end;
  1144. Procedure TStringList.Sort;
  1145. begin
  1146. CustomSort(@StringListAnsiCompare);
  1147. end;
  1148. {$else}
  1149. { generics based implementation of TStringList follows }
  1150. function StringListAnsiCompare(List: TStringList; Index1, Index2: Integer): Integer;
  1151. begin
  1152. Result := List.DoCompareText(List.Strings[Index1], List.Strings[Index2]);
  1153. end;
  1154. constructor TStringList.Create;
  1155. begin
  1156. inherited;
  1157. FOwnsObjects:=false;
  1158. FMap := TFPStrObjMap.Create;
  1159. FMap.OnPtrCompare := @MapPtrCompare;
  1160. FOnCompareText := @DefaultCompareText;
  1161. NameValueSeparator:='=';
  1162. CheckSpecialChars;
  1163. end;
  1164. destructor TStringList.Destroy;
  1165. begin
  1166. FMap.Free;
  1167. inherited;
  1168. end;
  1169. function TStringList.GetDuplicates: TDuplicates;
  1170. begin
  1171. Result := FMap.Duplicates;
  1172. end;
  1173. function TStringList.GetSorted: boolean;
  1174. begin
  1175. Result := FMap.Sorted;
  1176. end;
  1177. procedure TStringList.SetDuplicates(NewDuplicates: TDuplicates);
  1178. begin
  1179. FMap.Duplicates := NewDuplicates;
  1180. end;
  1181. procedure TStringList.SetSorted(NewSorted: Boolean);
  1182. begin
  1183. FMap.Sorted := NewSorted;
  1184. end;
  1185. procedure TStringList.Changed;
  1186. begin
  1187. if FUpdateCount = 0 then
  1188. if Assigned(FOnChange) then
  1189. FOnChange(Self);
  1190. end;
  1191. procedure TStringList.Changing;
  1192. begin
  1193. if FUpdateCount = 0 then
  1194. if Assigned(FOnChanging) then
  1195. FOnChanging(Self);
  1196. end;
  1197. function TStringList.Get(Index: Integer): string;
  1198. begin
  1199. Result := FMap.Keys[Index];
  1200. end;
  1201. function TStringList.GetCapacity: Integer;
  1202. begin
  1203. Result := FMap.Capacity;
  1204. end;
  1205. function TStringList.GetCount: Integer;
  1206. begin
  1207. Result := FMap.Count;
  1208. end;
  1209. function TStringList.GetObject(Index: Integer): TObject;
  1210. begin
  1211. Result := FMap.Data[Index];
  1212. end;
  1213. procedure TStringList.Put(Index: Integer; const S: string);
  1214. begin
  1215. Changing;
  1216. FMap.Keys[Index] := S;
  1217. Changed;
  1218. end;
  1219. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1220. begin
  1221. Changing;
  1222. FMap.Data[Index] := AObject;
  1223. Changed;
  1224. end;
  1225. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1226. begin
  1227. FMap.Capacity := NewCapacity;
  1228. end;
  1229. procedure TStringList.SetUpdateState(Updating: Boolean);
  1230. begin
  1231. if Updating then
  1232. Changing
  1233. else
  1234. Changed
  1235. end;
  1236. function TStringList.Add(const S: string): Integer;
  1237. begin
  1238. Result := FMap.Add(S);
  1239. end;
  1240. procedure TStringList.Clear;
  1241. begin
  1242. if FMap.Count = 0 then exit;
  1243. Changing;
  1244. FMap.Clear;
  1245. Changed;
  1246. end;
  1247. procedure TStringList.Delete(Index: Integer);
  1248. begin
  1249. if (Index < 0) or (Index >= FMap.Count) then
  1250. Error(SListIndexError, Index);
  1251. Changing;
  1252. FMap.Delete(Index);
  1253. Changed;
  1254. end;
  1255. procedure TStringList.Exchange(Index1, Index2: Integer);
  1256. begin
  1257. if (Index1 < 0) or (Index1 >= FMap.Count) then
  1258. Error(SListIndexError, Index1);
  1259. if (Index2 < 0) or (Index2 >= FMap.Count) then
  1260. Error(SListIndexError, Index2);
  1261. Changing;
  1262. FMap.InternalExchange(Index1, Index2);
  1263. Changed;
  1264. end;
  1265. procedure TStringList.SetCaseSensitive(NewSensitive: Boolean);
  1266. begin
  1267. if NewSensitive <> FCaseSensitive then
  1268. begin
  1269. FCaseSensitive := NewSensitive;
  1270. if Sorted then
  1271. Sort;
  1272. end;
  1273. end;
  1274. function TStringList.MapPtrCompare(Key1, Key2: Pointer): Integer;
  1275. begin
  1276. Result := FOnCompareText(string(Key1^), string(Key2^));
  1277. end;
  1278. function TStringList.DefaultCompareText(const s1, s2: string): PtrInt;
  1279. begin
  1280. if FCaseSensitive then
  1281. Result := AnsiCompareStr(s1, s2)
  1282. else
  1283. Result := AnsiCompareText(s1, s2);
  1284. end;
  1285. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1286. begin
  1287. Result := FOnCompareText(s1, s2);
  1288. end;
  1289. function TStringList.Find(const S: string; var Index: Integer): Boolean;
  1290. begin
  1291. Result := FMap.Find(S, Index);
  1292. end;
  1293. function TStringList.IndexOf(const S: string): Integer;
  1294. begin
  1295. Result := FMap.IndexOf(S);
  1296. end;
  1297. procedure TStringList.Insert(Index: Integer; const S: string);
  1298. begin
  1299. if not Sorted and (0 <= Index) and (Index < FMap.Count) then
  1300. Changing;
  1301. FMap.InsertKey(Index, S);
  1302. Changed;
  1303. end;
  1304. procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  1305. var
  1306. I, J, Pivot: Integer;
  1307. begin
  1308. repeat
  1309. I := L;
  1310. J := R;
  1311. Pivot := (L + R) div 2;
  1312. repeat
  1313. while CompareFn(Self, I, Pivot) < 0 do Inc(I);
  1314. while CompareFn(Self, J, Pivot) > 0 do Dec(J);
  1315. if I <= J then
  1316. begin
  1317. FMap.InternalExchange(I, J); // No check, indices are correct.
  1318. if Pivot = I then
  1319. Pivot := J
  1320. else if Pivot = J then
  1321. Pivot := I;
  1322. Inc(I);
  1323. Dec(j);
  1324. end;
  1325. until I > J;
  1326. if L < J then
  1327. QuickSort(L,J, CompareFn);
  1328. L := I;
  1329. until I >= R;
  1330. end;
  1331. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1332. begin
  1333. if not Sorted and (FMap.Count > 1) then
  1334. begin
  1335. Changing;
  1336. QuickSort(0, FMap.Count-1, CompareFn);
  1337. Changed;
  1338. end;
  1339. end;
  1340. procedure TStringList.Sort;
  1341. begin
  1342. if not Sorted and (FMap.Count > 1) then
  1343. begin
  1344. Changing;
  1345. FMap.Sort;
  1346. Changed;
  1347. end;
  1348. end;
  1349. {$endif}