stringl.inc 32 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702
  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. try
  569. beginupdate;
  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. Try
  648. beginUpdate;
  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. try
  734. beginupdate;
  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. Obj:=Objects[CurIndex];
  760. Str:=Strings[CurIndex];
  761. Objects[CurIndex]:=Nil; // Prevent Delete from freeing.
  762. Delete(Curindex);
  763. InsertObject(NewIndex,Str,Obj);
  764. EndUpdate;
  765. end;
  766. Procedure TStrings.SaveToFile(const FileName: string);
  767. Var TheStream : TFileStream;
  768. begin
  769. TheStream:=TFileStream.Create(FileName,fmCreate);
  770. try
  771. SaveToStream(TheStream);
  772. finally
  773. TheStream.Free;
  774. end;
  775. end;
  776. Procedure TStrings.SaveToStream(Stream: TStream);
  777. Var
  778. S : String;
  779. begin
  780. S:=Text;
  781. if S = '' then Exit;
  782. Stream.WriteBuffer(Pointer(S)^,Length(S));
  783. end;
  784. Procedure TStrings.SetText(TheText: PChar);
  785. Var S : String;
  786. begin
  787. If TheText<>Nil then
  788. S:=StrPas(TheText)
  789. else
  790. S:='';
  791. SetTextStr(S);
  792. end;
  793. {****************************************************************************}
  794. {* TStringList *}
  795. {****************************************************************************}
  796. {$if not defined(FPC_TESTGENERICS)}
  797. Procedure TStringList.ExchangeItemsInt(Index1, Index2: Integer);
  798. Var P1,P2 : Pointer;
  799. begin
  800. P1:=Pointer(Flist^[Index1].FString);
  801. P2:=Pointer(Flist^[Index1].FObject);
  802. Pointer(Flist^[Index1].Fstring):=Pointer(Flist^[Index2].Fstring);
  803. Pointer(Flist^[Index1].FObject):=Pointer(Flist^[Index2].FObject);
  804. Pointer(Flist^[Index2].Fstring):=P1;
  805. Pointer(Flist^[Index2].FObject):=P2;
  806. end;
  807. Procedure TStringList.ExchangeItems(Index1, Index2: Integer);
  808. begin
  809. ExchangeItemsInt(Index1, Index2);
  810. end;
  811. Procedure TStringList.Grow;
  812. Var
  813. NC : Integer;
  814. begin
  815. NC:=FCapacity;
  816. If NC>=256 then
  817. NC:=NC+(NC Div 4)
  818. else if NC=0 then
  819. NC:=4
  820. else
  821. NC:=NC*4;
  822. SetCapacity(NC);
  823. end;
  824. Procedure TStringList.InternalClear(FromIndex : Integer = 0; ClearOnly : Boolean = False);
  825. Var
  826. I: Integer;
  827. begin
  828. if FromIndex < FCount then
  829. begin
  830. if FOwnsObjects then
  831. begin
  832. For I:=FromIndex to FCount-1 do
  833. begin
  834. Flist^[I].FString:='';
  835. freeandnil(Flist^[i].FObject);
  836. end;
  837. end
  838. else
  839. begin
  840. For I:=FromIndex to FCount-1 do
  841. Flist^[I].FString:='';
  842. end;
  843. FCount:=FromIndex;
  844. end;
  845. if Not ClearOnly then
  846. SetCapacity(0);
  847. end;
  848. Procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  849. var
  850. Pivot, vL, vR: Integer;
  851. ExchangeProc: procedure(Left, Right: Integer) of object;
  852. begin
  853. //if ExchangeItems is override call that, else call (faster) ExchangeItemsInt
  854. if TMethod(@Self.ExchangeItems).Code = CodePointer(@TStringList.ExchangeItems) then
  855. ExchangeProc := @ExchangeItemsInt
  856. else
  857. ExchangeProc := @ExchangeItems;
  858. if R - L <= 1 then begin // a little bit of time saver
  859. if L < R then
  860. if CompareFn(Self, L, R) > 0 then
  861. ExchangeProc(L, R);
  862. Exit;
  863. end;
  864. vL := L;
  865. vR := R;
  866. Pivot := L + Random(R - L); // they say random is best
  867. while vL < vR do begin
  868. while (vL < Pivot) and (CompareFn(Self, vL, Pivot) <= 0) do
  869. Inc(vL);
  870. while (vR > Pivot) and (CompareFn(Self, vR, Pivot) > 0) do
  871. Dec(vR);
  872. ExchangeProc(vL, vR);
  873. if Pivot = vL then // swap pivot if we just hit it from one side
  874. Pivot := vR
  875. else if Pivot = vR then
  876. Pivot := vL;
  877. end;
  878. if Pivot - 1 >= L then
  879. QuickSort(L, Pivot - 1, CompareFn);
  880. if Pivot + 1 <= R then
  881. QuickSort(Pivot + 1, R, CompareFn);
  882. end;
  883. Procedure TStringList.InsertItem(Index: Integer; const S: string);
  884. begin
  885. InsertItem(Index, S, nil);
  886. end;
  887. Procedure TStringList.InsertItem(Index: Integer; const S: string; O: TObject);
  888. begin
  889. Changing;
  890. If FCount=Fcapacity then Grow;
  891. If Index<FCount then
  892. System.Move (FList^[Index],FList^[Index+1],
  893. (FCount-Index)*SizeOf(TStringItem));
  894. Pointer(Flist^[Index].Fstring):=Nil; // Needed to initialize...
  895. Flist^[Index].FString:=S;
  896. Flist^[Index].FObject:=O;
  897. Inc(FCount);
  898. Changed;
  899. end;
  900. Procedure TStringList.SetSorted(Value: Boolean);
  901. begin
  902. If FSorted<>Value then
  903. begin
  904. If Value then sort;
  905. FSorted:=VAlue
  906. end;
  907. end;
  908. Procedure TStringList.Changed;
  909. begin
  910. If (FUpdateCount=0) Then
  911. begin
  912. If Assigned(FOnChange) then
  913. FOnchange(Self);
  914. FPONotifyObservers(Self,ooChange,Nil);
  915. end;
  916. end;
  917. Procedure TStringList.Changing;
  918. begin
  919. If FUpdateCount=0 then
  920. if Assigned(FOnChanging) then
  921. FOnchanging(Self);
  922. end;
  923. Function TStringList.Get(Index: Integer): string;
  924. begin
  925. If (Index<0) or (INdex>=Fcount) then
  926. Error (SListIndexError,Index);
  927. Result:=Flist^[Index].FString;
  928. end;
  929. Function TStringList.GetCapacity: Integer;
  930. begin
  931. Result:=FCapacity;
  932. end;
  933. Function TStringList.GetCount: Integer;
  934. begin
  935. Result:=FCount;
  936. end;
  937. Function TStringList.GetObject(Index: Integer): TObject;
  938. begin
  939. If (Index<0) or (INdex>=Fcount) then
  940. Error (SListIndexError,Index);
  941. Result:=Flist^[Index].FObject;
  942. end;
  943. Procedure TStringList.Put(Index: Integer; const S: string);
  944. begin
  945. If Sorted then
  946. Error(SSortedListError,0);
  947. If (Index<0) or (INdex>=Fcount) then
  948. Error (SListIndexError,Index);
  949. Changing;
  950. Flist^[Index].FString:=S;
  951. Changed;
  952. end;
  953. Procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  954. begin
  955. If (Index<0) or (INdex>=Fcount) then
  956. Error (SListIndexError,Index);
  957. Changing;
  958. Flist^[Index].FObject:=AObject;
  959. Changed;
  960. end;
  961. Procedure TStringList.SetCapacity(NewCapacity: Integer);
  962. Var NewList : Pointer;
  963. I,MSize : Longint;
  964. begin
  965. If (NewCapacity<0) then
  966. Error (SListCapacityError,NewCapacity);
  967. If NewCapacity>FCapacity then
  968. begin
  969. GetMem (NewList,NewCapacity*SizeOf(TStringItem));
  970. If NewList=Nil then
  971. Error (SListCapacityError,NewCapacity);
  972. If Assigned(FList) then
  973. begin
  974. MSize:=FCapacity*Sizeof(TStringItem);
  975. System.Move (FList^,NewList^,MSize);
  976. FillWord (Pchar(NewList)[MSize],(NewCapacity-FCapacity)*WordRatio, 0);
  977. FreeMem (Flist,MSize);
  978. end;
  979. Flist:=NewList;
  980. FCapacity:=NewCapacity;
  981. end
  982. else if NewCapacity<FCapacity then
  983. begin
  984. if NewCapacity = 0 then
  985. begin
  986. if FCount > 0 then
  987. InternalClear(0,True);
  988. FreeMem(FList);
  989. FList := nil;
  990. end else
  991. begin
  992. InternalClear(NewCapacity,True);
  993. GetMem(NewList, NewCapacity * SizeOf(TStringItem));
  994. System.Move(FList^, NewList^, NewCapacity * SizeOf(TStringItem));
  995. FreeMem(FList);
  996. FList := NewList;
  997. end;
  998. FCapacity:=NewCapacity;
  999. end;
  1000. end;
  1001. Procedure TStringList.SetUpdateState(Updating: Boolean);
  1002. begin
  1003. If Updating then
  1004. Changing
  1005. else
  1006. Changed
  1007. end;
  1008. destructor TStringList.Destroy;
  1009. begin
  1010. InternalClear;
  1011. Inherited destroy;
  1012. end;
  1013. Function TStringList.Add(const S: string): Integer;
  1014. begin
  1015. If Not Sorted then
  1016. Result:=FCount
  1017. else
  1018. If Find (S,Result) then
  1019. Case DUplicates of
  1020. DupIgnore : Exit;
  1021. DupError : Error(SDuplicateString,0)
  1022. end;
  1023. InsertItem (Result,S);
  1024. end;
  1025. Procedure TStringList.Clear;
  1026. begin
  1027. if FCount = 0 then Exit;
  1028. Changing;
  1029. InternalClear;
  1030. Changed;
  1031. end;
  1032. Procedure TStringList.Delete(Index: Integer);
  1033. begin
  1034. If (Index<0) or (Index>=FCount) then
  1035. Error(SlistINdexError,Index);
  1036. Changing;
  1037. Flist^[Index].FString:='';
  1038. if FOwnsObjects then
  1039. FreeAndNil(Flist^[Index].FObject);
  1040. Dec(FCount);
  1041. If Index<FCount then
  1042. System.Move(Flist^[Index+1],
  1043. Flist^[Index],
  1044. (Fcount-Index)*SizeOf(TStringItem));
  1045. Changed;
  1046. end;
  1047. Procedure TStringList.Exchange(Index1, Index2: Integer);
  1048. begin
  1049. If (Index1<0) or (Index1>=FCount) then
  1050. Error(SListIndexError,Index1);
  1051. If (Index2<0) or (Index2>=FCount) then
  1052. Error(SListIndexError,Index2);
  1053. Changing;
  1054. ExchangeItemsInt(Index1,Index2);
  1055. changed;
  1056. end;
  1057. procedure TStringList.SetCaseSensitive(b : boolean);
  1058. begin
  1059. if b=FCaseSensitive then
  1060. Exit;
  1061. FCaseSensitive:=b;
  1062. if FSorted then
  1063. begin
  1064. FForceSort:=True;
  1065. sort;
  1066. FForceSort:=False;
  1067. end;
  1068. end;
  1069. Function TStringList.DoCompareText(const s1,s2 : string) : PtrInt;
  1070. begin
  1071. if FCaseSensitive then
  1072. result:=AnsiCompareStr(s1,s2)
  1073. else
  1074. result:=AnsiCompareText(s1,s2);
  1075. end;
  1076. function TStringList.CompareStrings(const s1,s2 : string) : Integer;
  1077. begin
  1078. Result := DoCompareText(s1, s2);
  1079. end;
  1080. Function TStringList.Find(const S: string; Out Index: Integer): Boolean;
  1081. var
  1082. L, R, I: Integer;
  1083. CompareRes: PtrInt;
  1084. begin
  1085. Result := false;
  1086. // Use binary search.
  1087. L := 0;
  1088. R := Count - 1;
  1089. while (L<=R) do
  1090. begin
  1091. I := L + (R - L) div 2;
  1092. CompareRes := DoCompareText(S, Flist^[I].FString);
  1093. if (CompareRes>0) then
  1094. L := I+1
  1095. else begin
  1096. R := I-1;
  1097. if (CompareRes=0) then begin
  1098. Result := true;
  1099. if (Duplicates<>dupAccept) then
  1100. L := I; // forces end of while loop
  1101. end;
  1102. end;
  1103. end;
  1104. Index := L;
  1105. end;
  1106. Function TStringList.IndexOf(const S: string): Integer;
  1107. begin
  1108. If Not Sorted then
  1109. Result:=Inherited indexOf(S)
  1110. else
  1111. // faster using binary search...
  1112. If Not Find (S,Result) then
  1113. Result:=-1;
  1114. end;
  1115. Procedure TStringList.Insert(Index: Integer; const S: string);
  1116. begin
  1117. If Sorted then
  1118. Error (SSortedListError,0)
  1119. else
  1120. If (Index<0) or (Index>FCount) then
  1121. Error (SListIndexError,Index)
  1122. else
  1123. InsertItem (Index,S);
  1124. end;
  1125. Procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1126. begin
  1127. If (FForceSort or (Not Sorted)) and (FCount>1) then
  1128. begin
  1129. Changing;
  1130. QuickSort(0,FCount-1, CompareFn);
  1131. Changed;
  1132. end;
  1133. end;
  1134. function StringListAnsiCompare(List: TStringList; Index1, Index: Integer): Integer;
  1135. begin
  1136. Result := List.DoCompareText(List.FList^[Index1].FString,
  1137. List.FList^[Index].FString);
  1138. end;
  1139. Procedure TStringList.Sort;
  1140. begin
  1141. CustomSort(@StringListAnsiCompare);
  1142. end;
  1143. {$else}
  1144. { generics based implementation of TStringList follows }
  1145. function StringListAnsiCompare(List: TStringList; Index1, Index2: Integer): Integer;
  1146. begin
  1147. Result := List.DoCompareText(List.Strings[Index1], List.Strings[Index2]);
  1148. end;
  1149. constructor TStringList.Create;
  1150. begin
  1151. inherited;
  1152. FOwnsObjects:=false;
  1153. FMap := TFPStrObjMap.Create;
  1154. FMap.OnPtrCompare := @MapPtrCompare;
  1155. FOnCompareText := @DefaultCompareText;
  1156. NameValueSeparator:='=';
  1157. CheckSpecialChars;
  1158. end;
  1159. destructor TStringList.Destroy;
  1160. begin
  1161. FMap.Free;
  1162. inherited;
  1163. end;
  1164. function TStringList.GetDuplicates: TDuplicates;
  1165. begin
  1166. Result := FMap.Duplicates;
  1167. end;
  1168. function TStringList.GetSorted: boolean;
  1169. begin
  1170. Result := FMap.Sorted;
  1171. end;
  1172. procedure TStringList.SetDuplicates(NewDuplicates: TDuplicates);
  1173. begin
  1174. FMap.Duplicates := NewDuplicates;
  1175. end;
  1176. procedure TStringList.SetSorted(NewSorted: Boolean);
  1177. begin
  1178. FMap.Sorted := NewSorted;
  1179. end;
  1180. procedure TStringList.Changed;
  1181. begin
  1182. if FUpdateCount = 0 then
  1183. if Assigned(FOnChange) then
  1184. FOnChange(Self);
  1185. end;
  1186. procedure TStringList.Changing;
  1187. begin
  1188. if FUpdateCount = 0 then
  1189. if Assigned(FOnChanging) then
  1190. FOnChanging(Self);
  1191. end;
  1192. function TStringList.Get(Index: Integer): string;
  1193. begin
  1194. Result := FMap.Keys[Index];
  1195. end;
  1196. function TStringList.GetCapacity: Integer;
  1197. begin
  1198. Result := FMap.Capacity;
  1199. end;
  1200. function TStringList.GetCount: Integer;
  1201. begin
  1202. Result := FMap.Count;
  1203. end;
  1204. function TStringList.GetObject(Index: Integer): TObject;
  1205. begin
  1206. Result := FMap.Data[Index];
  1207. end;
  1208. procedure TStringList.Put(Index: Integer; const S: string);
  1209. begin
  1210. Changing;
  1211. FMap.Keys[Index] := S;
  1212. Changed;
  1213. end;
  1214. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1215. begin
  1216. Changing;
  1217. FMap.Data[Index] := AObject;
  1218. Changed;
  1219. end;
  1220. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1221. begin
  1222. FMap.Capacity := NewCapacity;
  1223. end;
  1224. procedure TStringList.SetUpdateState(Updating: Boolean);
  1225. begin
  1226. if Updating then
  1227. Changing
  1228. else
  1229. Changed
  1230. end;
  1231. function TStringList.Add(const S: string): Integer;
  1232. begin
  1233. Result := FMap.Add(S);
  1234. end;
  1235. procedure TStringList.Clear;
  1236. begin
  1237. if FMap.Count = 0 then exit;
  1238. Changing;
  1239. FMap.Clear;
  1240. Changed;
  1241. end;
  1242. procedure TStringList.Delete(Index: Integer);
  1243. begin
  1244. if (Index < 0) or (Index >= FMap.Count) then
  1245. Error(SListIndexError, Index);
  1246. Changing;
  1247. FMap.Delete(Index);
  1248. Changed;
  1249. end;
  1250. procedure TStringList.Exchange(Index1, Index2: Integer);
  1251. begin
  1252. if (Index1 < 0) or (Index1 >= FMap.Count) then
  1253. Error(SListIndexError, Index1);
  1254. if (Index2 < 0) or (Index2 >= FMap.Count) then
  1255. Error(SListIndexError, Index2);
  1256. Changing;
  1257. FMap.InternalExchange(Index1, Index2);
  1258. Changed;
  1259. end;
  1260. procedure TStringList.SetCaseSensitive(NewSensitive: Boolean);
  1261. begin
  1262. if NewSensitive <> FCaseSensitive then
  1263. begin
  1264. FCaseSensitive := NewSensitive;
  1265. if Sorted then
  1266. Sort;
  1267. end;
  1268. end;
  1269. function TStringList.MapPtrCompare(Key1, Key2: Pointer): Integer;
  1270. begin
  1271. Result := FOnCompareText(string(Key1^), string(Key2^));
  1272. end;
  1273. function TStringList.DefaultCompareText(const s1, s2: string): PtrInt;
  1274. begin
  1275. if FCaseSensitive then
  1276. Result := AnsiCompareStr(s1, s2)
  1277. else
  1278. Result := AnsiCompareText(s1, s2);
  1279. end;
  1280. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1281. begin
  1282. Result := FOnCompareText(s1, s2);
  1283. end;
  1284. function TStringList.Find(const S: string; var Index: Integer): Boolean;
  1285. begin
  1286. Result := FMap.Find(S, Index);
  1287. end;
  1288. function TStringList.IndexOf(const S: string): Integer;
  1289. begin
  1290. Result := FMap.IndexOf(S);
  1291. end;
  1292. procedure TStringList.Insert(Index: Integer; const S: string);
  1293. begin
  1294. if not Sorted and (0 <= Index) and (Index < FMap.Count) then
  1295. Changing;
  1296. FMap.InsertKey(Index, S);
  1297. Changed;
  1298. end;
  1299. procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  1300. var
  1301. I, J, Pivot: Integer;
  1302. begin
  1303. repeat
  1304. I := L;
  1305. J := R;
  1306. Pivot := (L + R) div 2;
  1307. repeat
  1308. while CompareFn(Self, I, Pivot) < 0 do Inc(I);
  1309. while CompareFn(Self, J, Pivot) > 0 do Dec(J);
  1310. if I <= J then
  1311. begin
  1312. FMap.InternalExchange(I, J); // No check, indices are correct.
  1313. if Pivot = I then
  1314. Pivot := J
  1315. else if Pivot = J then
  1316. Pivot := I;
  1317. Inc(I);
  1318. Dec(j);
  1319. end;
  1320. until I > J;
  1321. if L < J then
  1322. QuickSort(L,J, CompareFn);
  1323. L := I;
  1324. until I >= R;
  1325. end;
  1326. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1327. begin
  1328. if not Sorted and (FMap.Count > 1) then
  1329. begin
  1330. Changing;
  1331. QuickSort(0, FMap.Count-1, CompareFn);
  1332. Changed;
  1333. end;
  1334. end;
  1335. procedure TStringList.Sort;
  1336. begin
  1337. if not Sorted and (FMap.Count > 1) then
  1338. begin
  1339. Changing;
  1340. FMap.Sort;
  1341. Changed;
  1342. end;
  1343. end;
  1344. {$endif}