stringl.inc 33 KB

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