stringl.inc 32 KB

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