stringl.inc 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706
  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. begin
  488. S:='';
  489. Result:=False;
  490. If ((Length(Value)-P)<=0) then
  491. exit;
  492. PS:=@Value[P];
  493. PC:=PS;
  494. PP:=AnsiStrPos(PS,PChar(FLineBreak));
  495. // Stop on #0.
  496. While (PC^<>#0) and (PC<>PP) do
  497. Inc(PC);
  498. P:=P+(PC-PS)+Length(FLineBreak);
  499. SetString(S,PS,PC-PS);
  500. Result:=True;
  501. end;
  502. Procedure TStrings.DoSetTextStr(const Value: string; DoClear : Boolean);
  503. Var
  504. S : String;
  505. P : Integer;
  506. begin
  507. Try
  508. beginUpdate;
  509. if DoClear then
  510. Clear;
  511. P:=1;
  512. if FLineBreak=sLineBreak then
  513. begin
  514. While GetNextLine (Value,S,P) do
  515. Add(S)
  516. end
  517. else
  518. While GetNextLineBreak (Value,S,P) do
  519. Add(S);
  520. finally
  521. EndUpdate;
  522. end;
  523. end;
  524. Procedure TStrings.SetTextStr(const Value: string);
  525. begin
  526. CheckSpecialChars;
  527. DoSetTextStr(Value,True);
  528. end;
  529. Procedure TStrings.AddText(const S: string);
  530. begin
  531. CheckSpecialChars;
  532. DoSetTextStr(S,False);
  533. end;
  534. Procedure TStrings.SetUpdateState(Updating: Boolean);
  535. begin
  536. FPONotifyObservers(Self,ooChange,Nil);
  537. end;
  538. destructor TSTrings.Destroy;
  539. begin
  540. inherited destroy;
  541. end;
  542. Function TStrings.Add(const S: string): Integer;
  543. begin
  544. Result:=Count;
  545. Insert (Count,S);
  546. end;
  547. function TStrings.Add(const Fmt : string; const Args : Array of const): Integer;
  548. begin
  549. Result:=Add(Format(Fmt,Args));
  550. end;
  551. Function TStrings.AddObject(const S: string; AObject: TObject): Integer;
  552. begin
  553. Result:=Add(S);
  554. Objects[result]:=AObject;
  555. end;
  556. function TStrings.AddObject(const Fmt: string; Args : Array of const; AObject: TObject): Integer;
  557. begin
  558. Result:=AddObject(Format(Fmt,Args),AObject);
  559. end;
  560. Procedure TStrings.Append(const S: string);
  561. begin
  562. Add (S);
  563. end;
  564. Procedure TStrings.AddStrings(TheStrings: TStrings);
  565. Var Runner : longint;
  566. begin
  567. try
  568. beginupdate;
  569. For Runner:=0 to TheStrings.Count-1 do
  570. self.AddObject (Thestrings[Runner],TheStrings.Objects[Runner]);
  571. finally
  572. EndUpdate;
  573. end;
  574. end;
  575. Procedure TStrings.AddStrings(const TheStrings: array of string);
  576. Var Runner : longint;
  577. begin
  578. try
  579. beginupdate;
  580. if Count + High(TheStrings)+1 > Capacity then
  581. Capacity := Count + High(TheStrings)+1;
  582. For Runner:=Low(TheStrings) to High(TheStrings) do
  583. self.Add(Thestrings[Runner]);
  584. finally
  585. EndUpdate;
  586. end;
  587. end;
  588. Procedure TStrings.Assign(Source: TPersistent);
  589. Var
  590. S : TStrings;
  591. begin
  592. If Source is TStrings then
  593. begin
  594. S:=TStrings(Source);
  595. BeginUpdate;
  596. Try
  597. clear;
  598. FSpecialCharsInited:=S.FSpecialCharsInited;
  599. FQuoteChar:=S.FQuoteChar;
  600. FDelimiter:=S.FDelimiter;
  601. FNameValueSeparator:=S.FNameValueSeparator;
  602. FLBS:=S.FLBS;
  603. FLineBreak:=S.FLineBreak;
  604. AddStrings(S);
  605. finally
  606. EndUpdate;
  607. end;
  608. end
  609. else
  610. Inherited Assign(Source);
  611. end;
  612. Procedure TStrings.BeginUpdate;
  613. begin
  614. if FUpdateCount = 0 then SetUpdateState(true);
  615. inc(FUpdateCount);
  616. end;
  617. Procedure TStrings.EndUpdate;
  618. begin
  619. If FUpdateCount>0 then
  620. Dec(FUpdateCount);
  621. if FUpdateCount=0 then
  622. SetUpdateState(False);
  623. end;
  624. Function TStrings.Equals(Obj: TObject): Boolean;
  625. begin
  626. if Obj is TStrings then
  627. Result := Equals(TStrings(Obj))
  628. else
  629. Result := inherited Equals(Obj);
  630. end;
  631. Function TStrings.Equals(TheStrings: TStrings): Boolean;
  632. Var Runner,Nr : Longint;
  633. begin
  634. Result:=False;
  635. Nr:=Self.Count;
  636. if Nr<>TheStrings.Count then exit;
  637. For Runner:=0 to Nr-1 do
  638. If Strings[Runner]<>TheStrings[Runner] then exit;
  639. Result:=True;
  640. end;
  641. Procedure TStrings.Exchange(Index1, Index2: Integer);
  642. Var
  643. Obj : TObject;
  644. Str : String;
  645. begin
  646. Try
  647. beginUpdate;
  648. Obj:=Objects[Index1];
  649. Str:=Strings[Index1];
  650. Objects[Index1]:=Objects[Index2];
  651. Strings[Index1]:=Strings[Index2];
  652. Objects[Index2]:=Obj;
  653. Strings[Index2]:=Str;
  654. finally
  655. EndUpdate;
  656. end;
  657. end;
  658. function TStrings.GetEnumerator: TStringsEnumerator;
  659. begin
  660. Result:=TStringsEnumerator.Create(Self);
  661. end;
  662. Function TStrings.GetText: PChar;
  663. begin
  664. Result:=StrNew(Pchar(Self.Text));
  665. end;
  666. Function TStrings.DoCompareText(const s1,s2 : string) : PtrInt;
  667. begin
  668. result:=CompareText(s1,s2);
  669. end;
  670. Function TStrings.IndexOf(const S: string): Integer;
  671. begin
  672. Result:=0;
  673. While (Result<Count) and (DoCompareText(Strings[Result],S)<>0) do Result:=Result+1;
  674. if Result=Count then Result:=-1;
  675. end;
  676. Function TStrings.IndexOfName(const Name: string): Integer;
  677. Var
  678. len : longint;
  679. S : String;
  680. begin
  681. CheckSpecialChars;
  682. Result:=0;
  683. while (Result<Count) do
  684. begin
  685. S:=Strings[Result];
  686. len:=pos(FNameValueSeparator,S)-1;
  687. if (len>=0) and (DoCompareText(Name,Copy(S,1,Len))=0) then
  688. exit;
  689. inc(result);
  690. end;
  691. result:=-1;
  692. end;
  693. Function TStrings.IndexOfObject(AObject: TObject): Integer;
  694. begin
  695. Result:=0;
  696. While (Result<count) and (Objects[Result]<>AObject) do Result:=Result+1;
  697. If Result=Count then Result:=-1;
  698. end;
  699. Procedure TStrings.InsertObject(Index: Integer; const S: string;
  700. AObject: TObject);
  701. begin
  702. Insert (Index,S);
  703. Objects[Index]:=AObject;
  704. end;
  705. Procedure TStrings.LoadFromFile(const FileName: string);
  706. Var
  707. TheStream : TFileStream;
  708. begin
  709. TheStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
  710. try
  711. LoadFromStream(TheStream);
  712. finally
  713. TheStream.Free;
  714. end;
  715. end;
  716. Procedure TStrings.LoadFromStream(Stream: TStream);
  717. {
  718. Borlands method is no good, since a pipe for
  719. instance doesn't have a size.
  720. So we must do it the hard way.
  721. }
  722. Const
  723. BufSize = 1024;
  724. MaxGrow = 1 shl 29;
  725. Var
  726. Buffer : AnsiString;
  727. BytesRead,
  728. BufLen,
  729. I,BufDelta : Longint;
  730. begin
  731. // reread into a buffer
  732. try
  733. beginupdate;
  734. Buffer:='';
  735. BufLen:=0;
  736. I:=1;
  737. Repeat
  738. BufDelta:=BufSize*I;
  739. SetLength(Buffer,BufLen+BufDelta);
  740. BytesRead:=Stream.Read(Buffer[BufLen+1],BufDelta);
  741. inc(BufLen,BufDelta);
  742. If I<MaxGrow then
  743. I:=I shl 1;
  744. Until BytesRead<>BufDelta;
  745. SetLength(Buffer, BufLen-BufDelta+BytesRead);
  746. SetTextStr(Buffer);
  747. SetLength(Buffer,0);
  748. finally
  749. EndUpdate;
  750. end;
  751. end;
  752. Procedure TStrings.Move(CurIndex, NewIndex: Integer);
  753. Var
  754. Obj : TObject;
  755. Str : String;
  756. begin
  757. BeginUpdate;
  758. Try
  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. finally
  765. EndUpdate;
  766. end;
  767. end;
  768. Procedure TStrings.SaveToFile(const FileName: string);
  769. Var TheStream : TFileStream;
  770. begin
  771. TheStream:=TFileStream.Create(FileName,fmCreate);
  772. try
  773. SaveToStream(TheStream);
  774. finally
  775. TheStream.Free;
  776. end;
  777. end;
  778. Procedure TStrings.SaveToStream(Stream: TStream);
  779. Var
  780. S : String;
  781. begin
  782. S:=Text;
  783. if S = '' then Exit;
  784. Stream.WriteBuffer(Pointer(S)^,Length(S));
  785. end;
  786. Procedure TStrings.SetText(TheText: PChar);
  787. Var S : String;
  788. begin
  789. If TheText<>Nil then
  790. S:=StrPas(TheText)
  791. else
  792. S:='';
  793. SetTextStr(S);
  794. end;
  795. {****************************************************************************}
  796. {* TStringList *}
  797. {****************************************************************************}
  798. {$if not defined(FPC_TESTGENERICS)}
  799. Procedure TStringList.ExchangeItemsInt(Index1, Index2: Integer);
  800. Var P1,P2 : Pointer;
  801. begin
  802. P1:=Pointer(Flist^[Index1].FString);
  803. P2:=Pointer(Flist^[Index1].FObject);
  804. Pointer(Flist^[Index1].Fstring):=Pointer(Flist^[Index2].Fstring);
  805. Pointer(Flist^[Index1].FObject):=Pointer(Flist^[Index2].FObject);
  806. Pointer(Flist^[Index2].Fstring):=P1;
  807. Pointer(Flist^[Index2].FObject):=P2;
  808. end;
  809. Procedure TStringList.ExchangeItems(Index1, Index2: Integer);
  810. begin
  811. ExchangeItemsInt(Index1, Index2);
  812. end;
  813. Procedure TStringList.Grow;
  814. Var
  815. NC : Integer;
  816. begin
  817. NC:=FCapacity;
  818. If NC>=256 then
  819. NC:=NC+(NC Div 4)
  820. else if NC=0 then
  821. NC:=4
  822. else
  823. NC:=NC*4;
  824. SetCapacity(NC);
  825. end;
  826. Procedure TStringList.InternalClear(FromIndex : Integer = 0; ClearOnly : Boolean = False);
  827. Var
  828. I: Integer;
  829. begin
  830. if FromIndex < FCount then
  831. begin
  832. if FOwnsObjects then
  833. begin
  834. For I:=FromIndex to FCount-1 do
  835. begin
  836. Flist^[I].FString:='';
  837. freeandnil(Flist^[i].FObject);
  838. end;
  839. end
  840. else
  841. begin
  842. For I:=FromIndex to FCount-1 do
  843. Flist^[I].FString:='';
  844. end;
  845. FCount:=FromIndex;
  846. end;
  847. if Not ClearOnly then
  848. SetCapacity(0);
  849. end;
  850. Procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  851. var
  852. Pivot, vL, vR: Integer;
  853. ExchangeProc: procedure(Left, Right: Integer) of object;
  854. begin
  855. //if ExchangeItems is override call that, else call (faster) ExchangeItemsInt
  856. if TMethod(@Self.ExchangeItems).Code = CodePointer(@TStringList.ExchangeItems) then
  857. ExchangeProc := @ExchangeItemsInt
  858. else
  859. ExchangeProc := @ExchangeItems;
  860. if R - L <= 1 then begin // a little bit of time saver
  861. if L < R then
  862. if CompareFn(Self, L, R) > 0 then
  863. ExchangeProc(L, R);
  864. Exit;
  865. end;
  866. vL := L;
  867. vR := R;
  868. Pivot := L + Random(R - L); // they say random is best
  869. while vL < vR do begin
  870. while (vL < Pivot) and (CompareFn(Self, vL, Pivot) <= 0) do
  871. Inc(vL);
  872. while (vR > Pivot) and (CompareFn(Self, vR, Pivot) > 0) do
  873. Dec(vR);
  874. ExchangeProc(vL, vR);
  875. if Pivot = vL then // swap pivot if we just hit it from one side
  876. Pivot := vR
  877. else if Pivot = vR then
  878. Pivot := vL;
  879. end;
  880. if Pivot - 1 >= L then
  881. QuickSort(L, Pivot - 1, CompareFn);
  882. if Pivot + 1 <= R then
  883. QuickSort(Pivot + 1, R, CompareFn);
  884. end;
  885. Procedure TStringList.InsertItem(Index: Integer; const S: string);
  886. begin
  887. InsertItem(Index, S, nil);
  888. end;
  889. Procedure TStringList.InsertItem(Index: Integer; const S: string; O: TObject);
  890. begin
  891. Changing;
  892. If FCount=Fcapacity then Grow;
  893. If Index<FCount then
  894. System.Move (FList^[Index],FList^[Index+1],
  895. (FCount-Index)*SizeOf(TStringItem));
  896. Pointer(Flist^[Index].Fstring):=Nil; // Needed to initialize...
  897. Flist^[Index].FString:=S;
  898. Flist^[Index].FObject:=O;
  899. Inc(FCount);
  900. Changed;
  901. end;
  902. Procedure TStringList.SetSorted(Value: Boolean);
  903. begin
  904. If FSorted<>Value then
  905. begin
  906. If Value then sort;
  907. FSorted:=VAlue
  908. end;
  909. end;
  910. Procedure TStringList.Changed;
  911. begin
  912. If (FUpdateCount=0) Then
  913. begin
  914. If Assigned(FOnChange) then
  915. FOnchange(Self);
  916. FPONotifyObservers(Self,ooChange,Nil);
  917. end;
  918. end;
  919. Procedure TStringList.Changing;
  920. begin
  921. If FUpdateCount=0 then
  922. if Assigned(FOnChanging) then
  923. FOnchanging(Self);
  924. end;
  925. Function TStringList.Get(Index: Integer): string;
  926. begin
  927. If (Index<0) or (INdex>=Fcount) then
  928. Error (SListIndexError,Index);
  929. Result:=Flist^[Index].FString;
  930. end;
  931. Function TStringList.GetCapacity: Integer;
  932. begin
  933. Result:=FCapacity;
  934. end;
  935. Function TStringList.GetCount: Integer;
  936. begin
  937. Result:=FCount;
  938. end;
  939. Function TStringList.GetObject(Index: Integer): TObject;
  940. begin
  941. If (Index<0) or (INdex>=Fcount) then
  942. Error (SListIndexError,Index);
  943. Result:=Flist^[Index].FObject;
  944. end;
  945. Procedure TStringList.Put(Index: Integer; const S: string);
  946. begin
  947. If Sorted then
  948. Error(SSortedListError,0);
  949. If (Index<0) or (INdex>=Fcount) then
  950. Error (SListIndexError,Index);
  951. Changing;
  952. Flist^[Index].FString:=S;
  953. Changed;
  954. end;
  955. Procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  956. begin
  957. If (Index<0) or (INdex>=Fcount) then
  958. Error (SListIndexError,Index);
  959. Changing;
  960. Flist^[Index].FObject:=AObject;
  961. Changed;
  962. end;
  963. Procedure TStringList.SetCapacity(NewCapacity: Integer);
  964. Var NewList : Pointer;
  965. MSize : Longint;
  966. begin
  967. If (NewCapacity<0) then
  968. Error (SListCapacityError,NewCapacity);
  969. If NewCapacity>FCapacity then
  970. begin
  971. GetMem (NewList,NewCapacity*SizeOf(TStringItem));
  972. If NewList=Nil then
  973. Error (SListCapacityError,NewCapacity);
  974. If Assigned(FList) then
  975. begin
  976. MSize:=FCapacity*Sizeof(TStringItem);
  977. System.Move (FList^,NewList^,MSize);
  978. FillWord (Pchar(NewList)[MSize],(NewCapacity-FCapacity)*(SizeOf(TStringItem) div SizeOf(Word)), 0);
  979. FreeMem (Flist,MSize);
  980. end;
  981. Flist:=NewList;
  982. FCapacity:=NewCapacity;
  983. end
  984. else if NewCapacity<FCapacity then
  985. begin
  986. if NewCapacity = 0 then
  987. begin
  988. if FCount > 0 then
  989. InternalClear(0,True);
  990. FreeMem(FList);
  991. FList := nil;
  992. end else
  993. begin
  994. InternalClear(NewCapacity,True);
  995. GetMem(NewList, NewCapacity * SizeOf(TStringItem));
  996. System.Move(FList^, NewList^, NewCapacity * SizeOf(TStringItem));
  997. FreeMem(FList);
  998. FList := NewList;
  999. end;
  1000. FCapacity:=NewCapacity;
  1001. end;
  1002. end;
  1003. Procedure TStringList.SetUpdateState(Updating: Boolean);
  1004. begin
  1005. If Updating then
  1006. Changing
  1007. else
  1008. Changed
  1009. end;
  1010. destructor TStringList.Destroy;
  1011. begin
  1012. InternalClear;
  1013. Inherited destroy;
  1014. end;
  1015. Function TStringList.Add(const S: string): Integer;
  1016. begin
  1017. If Not Sorted then
  1018. Result:=FCount
  1019. else
  1020. If Find (S,Result) then
  1021. Case DUplicates of
  1022. DupIgnore : Exit;
  1023. DupError : Error(SDuplicateString,0)
  1024. end;
  1025. InsertItem (Result,S);
  1026. end;
  1027. Procedure TStringList.Clear;
  1028. begin
  1029. if FCount = 0 then Exit;
  1030. Changing;
  1031. InternalClear;
  1032. Changed;
  1033. end;
  1034. Procedure TStringList.Delete(Index: Integer);
  1035. begin
  1036. If (Index<0) or (Index>=FCount) then
  1037. Error(SlistINdexError,Index);
  1038. Changing;
  1039. Flist^[Index].FString:='';
  1040. if FOwnsObjects then
  1041. FreeAndNil(Flist^[Index].FObject);
  1042. Dec(FCount);
  1043. If Index<FCount then
  1044. System.Move(Flist^[Index+1],
  1045. Flist^[Index],
  1046. (Fcount-Index)*SizeOf(TStringItem));
  1047. Changed;
  1048. end;
  1049. Procedure TStringList.Exchange(Index1, Index2: Integer);
  1050. begin
  1051. If (Index1<0) or (Index1>=FCount) then
  1052. Error(SListIndexError,Index1);
  1053. If (Index2<0) or (Index2>=FCount) then
  1054. Error(SListIndexError,Index2);
  1055. Changing;
  1056. ExchangeItemsInt(Index1,Index2);
  1057. changed;
  1058. end;
  1059. procedure TStringList.SetCaseSensitive(b : boolean);
  1060. begin
  1061. if b=FCaseSensitive then
  1062. Exit;
  1063. FCaseSensitive:=b;
  1064. if FSorted then
  1065. begin
  1066. FForceSort:=True;
  1067. sort;
  1068. FForceSort:=False;
  1069. end;
  1070. end;
  1071. Function TStringList.DoCompareText(const s1,s2 : string) : PtrInt;
  1072. begin
  1073. if FCaseSensitive then
  1074. result:=AnsiCompareStr(s1,s2)
  1075. else
  1076. result:=AnsiCompareText(s1,s2);
  1077. end;
  1078. function TStringList.CompareStrings(const s1,s2 : string) : Integer;
  1079. begin
  1080. Result := DoCompareText(s1, s2);
  1081. end;
  1082. Function TStringList.Find(const S: string; Out Index: Integer): Boolean;
  1083. var
  1084. L, R, I: Integer;
  1085. CompareRes: PtrInt;
  1086. begin
  1087. Result := false;
  1088. if Not Sorted then
  1089. exit;
  1090. // Use binary search.
  1091. L := 0;
  1092. R := Count - 1;
  1093. while (L<=R) do
  1094. begin
  1095. I := L + (R - L) div 2;
  1096. CompareRes := DoCompareText(S, Flist^[I].FString);
  1097. if (CompareRes>0) then
  1098. L := I+1
  1099. else begin
  1100. R := I-1;
  1101. if (CompareRes=0) then begin
  1102. Result := true;
  1103. if (Duplicates<>dupAccept) then
  1104. L := I; // forces end of while loop
  1105. end;
  1106. end;
  1107. end;
  1108. Index := L;
  1109. end;
  1110. Function TStringList.IndexOf(const S: string): Integer;
  1111. begin
  1112. If Not Sorted then
  1113. Result:=Inherited indexOf(S)
  1114. else
  1115. // faster using binary search...
  1116. If Not Find (S,Result) then
  1117. Result:=-1;
  1118. end;
  1119. Procedure TStringList.Insert(Index: Integer; const S: string);
  1120. begin
  1121. If Sorted then
  1122. Error (SSortedListError,0)
  1123. else
  1124. If (Index<0) or (Index>FCount) then
  1125. Error (SListIndexError,Index)
  1126. else
  1127. InsertItem (Index,S);
  1128. end;
  1129. Procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1130. begin
  1131. If (FForceSort or (Not Sorted)) and (FCount>1) then
  1132. begin
  1133. Changing;
  1134. QuickSort(0,FCount-1, CompareFn);
  1135. Changed;
  1136. end;
  1137. end;
  1138. function StringListAnsiCompare(List: TStringList; Index1, Index: Integer): Integer;
  1139. begin
  1140. Result := List.DoCompareText(List.FList^[Index1].FString,
  1141. List.FList^[Index].FString);
  1142. end;
  1143. Procedure TStringList.Sort;
  1144. begin
  1145. CustomSort(@StringListAnsiCompare);
  1146. end;
  1147. {$else}
  1148. { generics based implementation of TStringList follows }
  1149. function StringListAnsiCompare(List: TStringList; Index1, Index2: Integer): Integer;
  1150. begin
  1151. Result := List.DoCompareText(List.Strings[Index1], List.Strings[Index2]);
  1152. end;
  1153. constructor TStringList.Create;
  1154. begin
  1155. inherited;
  1156. FOwnsObjects:=false;
  1157. FMap := TFPStrObjMap.Create;
  1158. FMap.OnPtrCompare := @MapPtrCompare;
  1159. FOnCompareText := @DefaultCompareText;
  1160. NameValueSeparator:='=';
  1161. CheckSpecialChars;
  1162. end;
  1163. destructor TStringList.Destroy;
  1164. begin
  1165. FMap.Free;
  1166. inherited;
  1167. end;
  1168. function TStringList.GetDuplicates: TDuplicates;
  1169. begin
  1170. Result := FMap.Duplicates;
  1171. end;
  1172. function TStringList.GetSorted: boolean;
  1173. begin
  1174. Result := FMap.Sorted;
  1175. end;
  1176. procedure TStringList.SetDuplicates(NewDuplicates: TDuplicates);
  1177. begin
  1178. FMap.Duplicates := NewDuplicates;
  1179. end;
  1180. procedure TStringList.SetSorted(NewSorted: Boolean);
  1181. begin
  1182. FMap.Sorted := NewSorted;
  1183. end;
  1184. procedure TStringList.Changed;
  1185. begin
  1186. if FUpdateCount = 0 then
  1187. if Assigned(FOnChange) then
  1188. FOnChange(Self);
  1189. end;
  1190. procedure TStringList.Changing;
  1191. begin
  1192. if FUpdateCount = 0 then
  1193. if Assigned(FOnChanging) then
  1194. FOnChanging(Self);
  1195. end;
  1196. function TStringList.Get(Index: Integer): string;
  1197. begin
  1198. Result := FMap.Keys[Index];
  1199. end;
  1200. function TStringList.GetCapacity: Integer;
  1201. begin
  1202. Result := FMap.Capacity;
  1203. end;
  1204. function TStringList.GetCount: Integer;
  1205. begin
  1206. Result := FMap.Count;
  1207. end;
  1208. function TStringList.GetObject(Index: Integer): TObject;
  1209. begin
  1210. Result := FMap.Data[Index];
  1211. end;
  1212. procedure TStringList.Put(Index: Integer; const S: string);
  1213. begin
  1214. Changing;
  1215. FMap.Keys[Index] := S;
  1216. Changed;
  1217. end;
  1218. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1219. begin
  1220. Changing;
  1221. FMap.Data[Index] := AObject;
  1222. Changed;
  1223. end;
  1224. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1225. begin
  1226. FMap.Capacity := NewCapacity;
  1227. end;
  1228. procedure TStringList.SetUpdateState(Updating: Boolean);
  1229. begin
  1230. if Updating then
  1231. Changing
  1232. else
  1233. Changed
  1234. end;
  1235. function TStringList.Add(const S: string): Integer;
  1236. begin
  1237. Result := FMap.Add(S);
  1238. end;
  1239. procedure TStringList.Clear;
  1240. begin
  1241. if FMap.Count = 0 then exit;
  1242. Changing;
  1243. FMap.Clear;
  1244. Changed;
  1245. end;
  1246. procedure TStringList.Delete(Index: Integer);
  1247. begin
  1248. if (Index < 0) or (Index >= FMap.Count) then
  1249. Error(SListIndexError, Index);
  1250. Changing;
  1251. FMap.Delete(Index);
  1252. Changed;
  1253. end;
  1254. procedure TStringList.Exchange(Index1, Index2: Integer);
  1255. begin
  1256. if (Index1 < 0) or (Index1 >= FMap.Count) then
  1257. Error(SListIndexError, Index1);
  1258. if (Index2 < 0) or (Index2 >= FMap.Count) then
  1259. Error(SListIndexError, Index2);
  1260. Changing;
  1261. FMap.InternalExchange(Index1, Index2);
  1262. Changed;
  1263. end;
  1264. procedure TStringList.SetCaseSensitive(NewSensitive: Boolean);
  1265. begin
  1266. if NewSensitive <> FCaseSensitive then
  1267. begin
  1268. FCaseSensitive := NewSensitive;
  1269. if Sorted then
  1270. Sort;
  1271. end;
  1272. end;
  1273. function TStringList.MapPtrCompare(Key1, Key2: Pointer): Integer;
  1274. begin
  1275. Result := FOnCompareText(string(Key1^), string(Key2^));
  1276. end;
  1277. function TStringList.DefaultCompareText(const s1, s2: string): PtrInt;
  1278. begin
  1279. if FCaseSensitive then
  1280. Result := AnsiCompareStr(s1, s2)
  1281. else
  1282. Result := AnsiCompareText(s1, s2);
  1283. end;
  1284. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1285. begin
  1286. Result := FOnCompareText(s1, s2);
  1287. end;
  1288. function TStringList.Find(const S: string; var Index: Integer): Boolean;
  1289. begin
  1290. Result := FMap.Find(S, Index);
  1291. end;
  1292. function TStringList.IndexOf(const S: string): Integer;
  1293. begin
  1294. Result := FMap.IndexOf(S);
  1295. end;
  1296. procedure TStringList.Insert(Index: Integer; const S: string);
  1297. begin
  1298. if not Sorted and (0 <= Index) and (Index < FMap.Count) then
  1299. Changing;
  1300. FMap.InsertKey(Index, S);
  1301. Changed;
  1302. end;
  1303. procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  1304. var
  1305. I, J, Pivot: Integer;
  1306. begin
  1307. repeat
  1308. I := L;
  1309. J := R;
  1310. Pivot := (L + R) div 2;
  1311. repeat
  1312. while CompareFn(Self, I, Pivot) < 0 do Inc(I);
  1313. while CompareFn(Self, J, Pivot) > 0 do Dec(J);
  1314. if I <= J then
  1315. begin
  1316. FMap.InternalExchange(I, J); // No check, indices are correct.
  1317. if Pivot = I then
  1318. Pivot := J
  1319. else if Pivot = J then
  1320. Pivot := I;
  1321. Inc(I);
  1322. Dec(j);
  1323. end;
  1324. until I > J;
  1325. if L < J then
  1326. QuickSort(L,J, CompareFn);
  1327. L := I;
  1328. until I >= R;
  1329. end;
  1330. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1331. begin
  1332. if not Sorted and (FMap.Count > 1) then
  1333. begin
  1334. Changing;
  1335. QuickSort(0, FMap.Count-1, CompareFn);
  1336. Changed;
  1337. end;
  1338. end;
  1339. procedure TStringList.Sort;
  1340. begin
  1341. if not Sorted and (FMap.Count > 1) then
  1342. begin
  1343. Changing;
  1344. FMap.Sort;
  1345. Changed;
  1346. end;
  1347. end;
  1348. {$endif}