stringl.inc 33 KB

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