stringl.inc 33 KB

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