stringl.inc 33 KB

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