stringl.inc 33 KB

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