stringl.inc 48 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426
  1. {%MainUnit classes.pp}
  2. {
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {****************************************************************************}
  12. {* TStringsEnumerator *}
  13. {****************************************************************************}
  14. constructor TStringsEnumerator.Create(AStrings: TStrings);
  15. begin
  16. inherited Create;
  17. FStrings := AStrings;
  18. FPosition := -1;
  19. end;
  20. function TStringsEnumerator.GetCurrent: String;
  21. begin
  22. Result := FStrings[FPosition];
  23. end;
  24. function TStringsEnumerator.MoveNext: Boolean;
  25. begin
  26. Inc(FPosition);
  27. Result := FPosition < FStrings.Count;
  28. end;
  29. {****************************************************************************}
  30. {* TStrings *}
  31. {****************************************************************************}
  32. // Function to quote text. Should move maybe to sysutils !!
  33. // Also, it is not clear at this point what exactly should be done.
  34. { //!! is used to mark unsupported things. }
  35. Function QuoteString (Const S : String; Const Quote : String) : String;
  36. Var
  37. I,J : Integer;
  38. begin
  39. J:=0;
  40. Result:=S;
  41. for i:=1 to length(s) do
  42. begin
  43. inc(j);
  44. if S[i]=Quote then
  45. begin
  46. System.Insert(Quote,Result,J);
  47. inc(j);
  48. end;
  49. end;
  50. Result:=Quote+Result+Quote;
  51. end;
  52. {
  53. For compatibility we can't add a Constructor to TSTrings to initialize
  54. the special characters. Therefore we add a routine which is called whenever
  55. the special chars are needed.
  56. }
  57. Procedure Tstrings.CheckSpecialChars;
  58. begin
  59. If Not FSpecialCharsInited then
  60. begin
  61. FQuoteChar:='"';
  62. FDelimiter:=',';
  63. FNameValueSeparator:='=';
  64. FLBS:=DefaultTextLineBreakStyle;
  65. FSpecialCharsInited:=true;
  66. FLineBreak:=sLineBreak;
  67. end;
  68. end;
  69. Function TStrings.GetSkipLastLineBreak : Boolean;
  70. begin
  71. Result:=not TrailingLineBreak;
  72. end;
  73. procedure TStrings.SetSkipLastLineBreak(const AValue : Boolean);
  74. begin
  75. TrailingLineBreak:=not AValue;
  76. end;
  77. Function TStrings.GetLBS : TTextLineBreakStyle;
  78. begin
  79. CheckSpecialChars;
  80. Result:=FLBS;
  81. end;
  82. Procedure TStrings.SetLBS (AValue : TTextLineBreakStyle);
  83. begin
  84. CheckSpecialChars;
  85. FLBS:=AValue;
  86. end;
  87. procedure TStrings.SetDelimiter(c:AnsiChar);
  88. begin
  89. CheckSpecialChars;
  90. FDelimiter:=c;
  91. end;
  92. Procedure TStrings.SetEncoding(const AEncoding: TEncoding);
  93. begin
  94. if (FEncoding<>nil) and not TEncoding.IsStandardEncoding(FEncoding) then
  95. FEncoding.Free;
  96. if TEncoding.IsStandardEncoding(AEncoding) then
  97. FEncoding:=AEncoding
  98. else if AEncoding<>nil then
  99. FEncoding:=AEncoding.Clone
  100. else
  101. FEncoding:=nil;
  102. end;
  103. Function TStrings.GetDelimiter : AnsiChar;
  104. begin
  105. CheckSpecialChars;
  106. Result:=FDelimiter;
  107. end;
  108. procedure TStrings.SetLineBreak(Const S : String);
  109. begin
  110. CheckSpecialChars;
  111. FLineBreak:=S;
  112. end;
  113. Function TStrings.GetLineBreak : String;
  114. begin
  115. CheckSpecialChars;
  116. Result:=FLineBreak;
  117. end;
  118. procedure TStrings.SetQuoteChar(c:AnsiChar);
  119. begin
  120. CheckSpecialChars;
  121. FQuoteChar:=c;
  122. end;
  123. Function TStrings.GetQuoteChar :AnsiChar;
  124. begin
  125. CheckSpecialChars;
  126. Result:=FQuoteChar;
  127. end;
  128. procedure TStrings.SetNameValueSeparator(c:AnsiChar);
  129. begin
  130. CheckSpecialChars;
  131. FNameValueSeparator:=c;
  132. end;
  133. Function TStrings.GetNameValueSeparator :AnsiChar;
  134. begin
  135. CheckSpecialChars;
  136. Result:=FNameValueSeparator;
  137. end;
  138. function TStrings.GetCommaText: string;
  139. Var
  140. C1,C2 : AnsiChar;
  141. FSD : Boolean;
  142. begin
  143. CheckSpecialChars;
  144. FSD:=StrictDelimiter;
  145. C1:=Delimiter;
  146. C2:=QuoteChar;
  147. Delimiter:=',';
  148. QuoteChar:='"';
  149. StrictDelimiter:=False;
  150. Try
  151. Result:=GetDelimitedText;
  152. Finally
  153. Delimiter:=C1;
  154. QuoteChar:=C2;
  155. StrictDelimiter:=FSD;
  156. end;
  157. end;
  158. function TStrings.GetLineBreakCharLBS: string;
  159. begin
  160. CheckSpecialChars;
  161. if FLineBreak<>sLineBreak then
  162. Result:=FLineBreak
  163. else
  164. Case FLBS of
  165. tlbsLF : Result:=#10;
  166. tlbsCRLF : Result:=#13#10;
  167. tlbsCR : Result:=#13;
  168. end;
  169. end;
  170. function TStrings.GetMissingNameValueSeparatorAction: TMissingNameValueSeparatorAction;
  171. begin
  172. CheckSpecialChars;
  173. Result:=FMissingNameValueSeparatorAction;
  174. end;
  175. Function TStrings.GetDelimitedText: string;
  176. Var
  177. I : integer;
  178. p : PAnsiChar;
  179. BreakChars : set of AnsiChar;
  180. S : String;
  181. doQuote : Boolean;
  182. begin
  183. CheckSpecialChars;
  184. result:='';
  185. if StrictDelimiter then
  186. BreakChars:=[#0,QuoteChar,Delimiter]
  187. else
  188. BreakChars:=[#0..' ',QuoteChar,Delimiter];
  189. // Check for break characters and quote if required.
  190. For i:=0 to count-1 do
  191. begin
  192. S:=Strings[i];
  193. doQuote:=FAlwaysQuote;
  194. If not DoQuote then
  195. begin
  196. p:=PAnsiChar(S);
  197. //Quote strings that include BreakChars:
  198. while not(p^ in BreakChars) do
  199. inc(p);
  200. DoQuote:=(p<>PAnsiChar(S)+length(S));
  201. end;
  202. if DoQuote and (QuoteChar<>#0) then
  203. Result:=Result+QuoteString(S,QuoteChar)
  204. else
  205. Result:=Result+S;
  206. if I<Count-1 then
  207. Result:=Result+Delimiter;
  208. end;
  209. // Quote empty string:
  210. If (Length(Result)=0) and (Count=1) and (QuoteChar<>#0) then
  211. Result:=QuoteChar+QuoteChar;
  212. end;
  213. procedure TStrings.GetNameValue(Index : Integer; Out AName,AValue : String);
  214. Var L : longint;
  215. begin
  216. aName:='';
  217. CheckSpecialChars;
  218. AValue:=Strings[Index];
  219. L:=Pos(FNameValueSeparator,AValue);
  220. If L<>0 then
  221. begin
  222. AName:=Copy(AValue,1,L-1);
  223. System.Delete(AValue,1,L);
  224. end
  225. else
  226. case FMissingNameValueSeparatorAction of
  227. mnvaValue : ;
  228. mnvaName :
  229. begin
  230. aName:=aValue;
  231. aValue:='';
  232. end;
  233. mnvaEmpty :
  234. aValue:='';
  235. mnvaError :
  236. Raise EStringListError.CreateFmt(SErrNoNameValuePairAt,[Index]);
  237. end;
  238. end;
  239. function TStrings.ExtractName(const s:String):String;
  240. var
  241. L: Longint;
  242. begin
  243. CheckSpecialChars;
  244. L:=Pos(FNameValueSeparator,S);
  245. If L<>0 then
  246. Result:=Copy(S,1,L-1)
  247. else
  248. Result:='';
  249. end;
  250. procedure TStrings.Filter(aFilter: TStringsFilterMethod; aList: TStrings);
  251. var
  252. S : string;
  253. begin
  254. for S in self do
  255. if aFilter(S) then
  256. aList.Add(S);
  257. end;
  258. procedure TStrings.ForEach(aCallback: TStringsForeachMethod);
  259. var
  260. S : String;
  261. begin
  262. for S in self do
  263. aCallBack(S);
  264. end;
  265. procedure TStrings.ForEach(aCallback: TStringsForeachMethodEx);
  266. var
  267. i: integer;
  268. begin
  269. for i:=0 to Count-1 do
  270. aCallBack(Strings[i],i);
  271. end;
  272. procedure TStrings.ForEach(aCallback: TStringsForeachMethodExObj);
  273. var
  274. i: integer;
  275. begin
  276. for i:=0 to Count-1 do
  277. aCallback(Strings[i],i,Objects[i]);
  278. end;
  279. function TStrings.Filter(aFilter: TStringsFilterMethod): TStrings;
  280. begin
  281. Result:=TStringsClass(Self.ClassType).Create;
  282. try
  283. Filter(aFilter,Result);
  284. except
  285. FreeAndNil(Result);
  286. Raise;
  287. end;
  288. end;
  289. procedure TStrings.Fill(const aValue: String; aStart, aEnd: Integer);
  290. var
  291. i: integer;
  292. begin
  293. if aEnd<0 then
  294. aEnd:=Self.Count+aEnd;
  295. if aEnd>=Count then
  296. aEnd:=Count-1;
  297. for i:=aStart to aEnd do
  298. Strings[i]:=aValue;
  299. end;
  300. Procedure TStrings.Map(aMap: TStringsMapMethod; aList : TStrings);
  301. Var
  302. S : String;
  303. begin
  304. For S in self do
  305. aList.Add(aMap(S));
  306. end;
  307. Function TStrings.Map(aMap: TStringsMapMethod) : TStrings;
  308. begin
  309. Result:=TStringsClass(Self.ClassType).Create;
  310. try
  311. Map(aMap,Result);
  312. except
  313. FreeAndNil(Result);
  314. Raise;
  315. end;
  316. end;
  317. function TStrings.Reduce(aReduceMethod: TStringsReduceMethod; const startingValue: string): string;
  318. var
  319. S : String;
  320. begin
  321. Result:=startingValue;
  322. for S in self do
  323. Result:=aReduceMethod(Result, S);
  324. end;
  325. Function TStrings.Reverse : TStrings;
  326. begin
  327. Result:=TStringsClass(Self.ClassType).Create;
  328. try
  329. Reverse(Result);
  330. except
  331. FreeAndNil(Result);
  332. Raise;
  333. end;
  334. end;
  335. Procedure TStrings.Reverse(aList : TStrings);
  336. Var
  337. I : Integer;
  338. begin
  339. for I:=Count-1 downto 0 do
  340. aList.Add(Strings[i]);
  341. end;
  342. Procedure TStrings.Slice(fromIndex: integer; aList : TStrings);
  343. var
  344. i: integer;
  345. begin
  346. for i:=fromIndex to Count-1 do
  347. aList.Add(Self[i]);
  348. end;
  349. Function TStrings.Slice(fromIndex: integer) : TStrings;
  350. begin
  351. Result:=TStringsClass(Self.ClassType).Create;
  352. try
  353. Slice(FromIndex,Result);
  354. except
  355. FreeAndNil(Result);
  356. Raise;
  357. end;
  358. end;
  359. function TStrings.GetName(Index: Integer): string;
  360. Var
  361. V : String;
  362. begin
  363. GetNameValue(Index,Result,V);
  364. end;
  365. function TStrings.GetStrictDelimiter: Boolean;
  366. begin
  367. Result:=soStrictDelimiter in FOptions;
  368. end;
  369. function TStrings.GetTrailingLineBreak: Boolean;
  370. begin
  371. Result:=soTrailingLineBreak in FOptions;
  372. end;
  373. function TStrings.GetUseLocale: Boolean;
  374. begin
  375. Result:=soUseLocale in FOptions;
  376. end;
  377. function TStrings.GetWriteBOM: Boolean;
  378. begin
  379. Result:=soWriteBOM in FOptions;
  380. end;
  381. Function TStrings.GetValue(const Name: string): string;
  382. Var
  383. L : longint;
  384. N : String;
  385. begin
  386. Result:='';
  387. L:=IndexOfName(Name);
  388. If L<>-1 then
  389. GetNameValue(L,N,Result);
  390. end;
  391. Function TStrings.GetValueFromIndex(Index: Integer): string;
  392. Var
  393. N : String;
  394. begin
  395. GetNameValue(Index,N,Result);
  396. end;
  397. Procedure TStrings.SetValueFromIndex(Index: Integer; const Value: string);
  398. begin
  399. If (Value='') then
  400. Delete(Index)
  401. else
  402. begin
  403. If (Index<0) then
  404. Index:=Add('');
  405. CheckSpecialChars;
  406. Strings[Index]:=GetName(Index)+FNameValueSeparator+Value;
  407. end;
  408. end;
  409. procedure TStrings.ReadData(Reader: TReader);
  410. begin
  411. Reader.ReadListBegin;
  412. BeginUpdate;
  413. try
  414. Clear;
  415. while not Reader.EndOfList do
  416. Add(Reader.ReadString);
  417. finally
  418. EndUpdate;
  419. end;
  420. Reader.ReadListEnd;
  421. end;
  422. Procedure TStrings.SetDelimitedText(const AValue: string);
  423. begin
  424. CheckSpecialChars;
  425. DoSetDelimitedText(aValue,True,StrictDelimiter,FQuoteChar,FDelimiter);
  426. end;
  427. Procedure TStrings.DoSetDelimitedText(const AValue: string; DoClear,aStrictDelimiter : Boolean; aQuoteChar,aDelimiter : AnsiChar);
  428. var
  429. len,i,j: SizeInt;
  430. aNotFirst:boolean;
  431. Procedure AddQuoted;
  432. begin
  433. Add(StringReplace(Copy(AValue,i+1,j-i-1),aQuoteChar+aQuoteChar,aQuoteChar, [rfReplaceAll]));
  434. end;
  435. Function CheckQuoted : Boolean;
  436. { Paraphrased from Delphi XE2 help:
  437. Strings must be separated by Delimiter characters or spaces.
  438. They may be enclosed in QuoteChars.
  439. QuoteChars in the string must be repeated to distinguish them from the QuoteChars enclosing the string.
  440. }
  441. begin
  442. Result:=(AValue[i]=aQuoteChar) and (aQuoteChar<>#0);
  443. If Not Result then
  444. exit;
  445. // next string is quoted
  446. j:=i+1;
  447. while (j<=len) and
  448. ((AValue[j]<>aQuoteChar) or
  449. ((j+1<=len) and (AValue[j+1]=aQuoteChar))) do
  450. begin
  451. if (j<=len) and (AValue[j]=aQuoteChar) then
  452. inc(j,2)
  453. else
  454. inc(j);
  455. end;
  456. AddQuoted;
  457. i:=j+1;
  458. end;
  459. Procedure MaybeSkipSpaces; inline;
  460. begin
  461. if Not aStrictDelimiter then
  462. while (i<=len) and (Ord(AValue[i])<=Ord(' ')) do
  463. inc(i);
  464. end;
  465. begin
  466. BeginUpdate;
  467. i:=1;
  468. j:=1;
  469. aNotFirst:=false;
  470. try
  471. if DoClear then
  472. Clear;
  473. len:=length(AValue);
  474. while i<=len do
  475. begin
  476. // skip delimiter
  477. if aNotFirst and (i<=len) and (AValue[i]=aDelimiter) then
  478. inc(i);
  479. MaybeSkipSpaces;
  480. // read next string
  481. if i>len then
  482. begin
  483. if aNotFirst then Add('');
  484. end
  485. else
  486. begin
  487. // next string is quoted
  488. if not CheckQuoted then
  489. begin
  490. // next string is not quoted; read until control character/space/delimiter
  491. j:=i;
  492. while (j<=len) and
  493. (aStrictDelimiter or (Ord(AValue[j])>Ord(' '))) and
  494. (AValue[j]<>aDelimiter) do
  495. inc(j);
  496. Add( Copy(AValue,i,j-i));
  497. i:=j;
  498. end;
  499. end;
  500. MaybeSkipSpaces;
  501. aNotFirst:=true;
  502. end; // While I<=Len
  503. finally
  504. EndUpdate;
  505. end;
  506. end;
  507. Procedure TStrings.SetCommaText(const Value: string);
  508. begin
  509. CheckSpecialChars;
  510. DoSetDelimitedText(Value,True,StrictDelimiter,'"',',');
  511. end;
  512. procedure TStrings.SetMissingNameValueSeparatorAction(AValue: TMissingNameValueSeparatorAction);
  513. begin
  514. CheckSpecialChars;
  515. FMissingNameValueSeparatorAction:=aValue;
  516. end;
  517. Procedure TStrings.SetStringsAdapter(const Value: IStringsAdapter);
  518. begin
  519. end;
  520. procedure TStrings.SetStrictDelimiter(AValue: Boolean);
  521. begin
  522. if AValue then
  523. Include(FOptions,soStrictDelimiter)
  524. else
  525. Exclude(FOptions,soStrictDelimiter);
  526. end;
  527. procedure TStrings.SetTrailingLineBreak(AValue: Boolean);
  528. begin
  529. if AValue then
  530. Include(FOptions,soTrailingLineBreak)
  531. else
  532. Exclude(FOptions,soTrailingLineBreak);
  533. end;
  534. procedure TStrings.SetUseLocale(AValue: Boolean);
  535. begin
  536. if AValue then
  537. Include(FOptions,soUseLocale)
  538. else
  539. Exclude(FOptions,soUseLocale);
  540. end;
  541. procedure TStrings.SetWriteBOM(AValue: Boolean);
  542. begin
  543. if AValue then
  544. Include(FOptions,soWriteBOM)
  545. else
  546. Exclude(FOptions,soWriteBOM);
  547. end;
  548. Procedure TStrings.SetDefaultEncoding(const ADefaultEncoding: TEncoding);
  549. begin
  550. if (FDefaultEncoding<>nil) and not TEncoding.IsStandardEncoding(FDefaultEncoding) then
  551. FDefaultEncoding.Free;
  552. if TEncoding.IsStandardEncoding(ADefaultEncoding) then
  553. FDefaultEncoding:=ADefaultEncoding
  554. else if ADefaultEncoding<>nil then
  555. FDefaultEncoding:=ADefaultEncoding.Clone
  556. else
  557. FDefaultEncoding:=TEncoding.Default;
  558. end;
  559. Procedure TStrings.SetValue(const Name, Value: string);
  560. Var L : longint;
  561. begin
  562. CheckSpecialChars;
  563. L:=IndexOfName(Name);
  564. if L=-1 then
  565. Add (Name+FNameValueSeparator+Value)
  566. else
  567. Strings[L]:=Name+FNameValueSeparator+value;
  568. end;
  569. procedure TStrings.WriteData(Writer: TWriter);
  570. var
  571. i: Integer;
  572. begin
  573. Writer.WriteListBegin;
  574. for i := 0 to Count - 1 do
  575. Writer.WriteString(Strings[i]);
  576. Writer.WriteListEnd;
  577. end;
  578. function TStrings.CompareStrings(const s1,s2 : string) : Integer;
  579. begin
  580. Result := DoCompareText(s1, s2);
  581. end;
  582. procedure TStrings.DefineProperties(Filer: TFiler);
  583. var
  584. HasData: Boolean;
  585. begin
  586. if Assigned(Filer.Ancestor) then
  587. // Only serialize if string list is different from ancestor
  588. if Filer.Ancestor.InheritsFrom(TStrings) then
  589. HasData := not Equals(TStrings(Filer.Ancestor))
  590. else
  591. HasData := True
  592. else
  593. HasData := Count > 0;
  594. Filer.DefineProperty('Strings', @ReadData, @WriteData, HasData);
  595. end;
  596. Procedure TStrings.Error(const Msg: string; Data: Integer);
  597. begin
  598. Raise EStringListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  599. end;
  600. Procedure TStrings.Error(const Msg: pstring; Data: Integer);
  601. begin
  602. Raise EStringListError.CreateFmt(Msg^,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  603. end;
  604. Function TStrings.GetCapacity: Integer;
  605. begin
  606. Result:=Count;
  607. end;
  608. Function TStrings.GetObject(Index: Integer): TObject;
  609. begin
  610. Result:=Nil;
  611. end;
  612. Function TStrings.GetTextStr: string;
  613. Var P : PAnsiChar;
  614. I,L,NLS : SizeInt;
  615. S,NL : String;
  616. begin
  617. NL:=GetLineBreakCharLBS;
  618. // Determine needed place
  619. L:=0;
  620. NLS:=Length(NL);
  621. For I:=0 to count-1 do
  622. L:=L+Length(Strings[I])+NLS;
  623. if SkipLastLineBreak then
  624. Dec(L,NLS);
  625. Setlength(Result,L);
  626. P:=Pointer(Result);
  627. For i:=0 To count-1 do
  628. begin
  629. S:=Strings[I];
  630. L:=Length(S);
  631. if L<>0 then
  632. System.Move(Pointer(S)^,P^,L);
  633. P:=P+L;
  634. if (I<Count-1) or Not SkipLastLineBreak then
  635. For L:=1 to NLS do
  636. begin
  637. P^:=NL[L];
  638. inc(P);
  639. end;
  640. end;
  641. end;
  642. Procedure TStrings.Put(Index: Integer; const S: string);
  643. Var Obj : TObject;
  644. begin
  645. Obj:=Objects[Index];
  646. Delete(Index);
  647. InsertObject(Index,S,Obj);
  648. end;
  649. Procedure TStrings.PutObject(Index: Integer; AObject: TObject);
  650. begin
  651. // Empty.
  652. end;
  653. Procedure TStrings.SetCapacity(NewCapacity: Integer);
  654. begin
  655. // Empty.
  656. end;
  657. Class Function TStrings.GetNextLine (Const Value : String; Var S : String; Var P : SizeInt) : Boolean;
  658. var
  659. LengthOfValue: SizeInt;
  660. StartPos, FuturePos: SizeInt;
  661. begin
  662. LengthOfValue := Length(Value);
  663. StartPos := P;
  664. if (StartPos <= 0) or (StartPos > LengthOfValue) then // True for LengthOfValue <= 0
  665. begin
  666. S := '';
  667. Exit(False);
  668. end;
  669. FuturePos := StartPos;
  670. while (FuturePos <= LengthOfValue) and not (Value[FuturePos] in [#10, #13]) do
  671. Inc(FuturePos);
  672. // If we use S := Copy(Value, StartPos, FuturePos - StartPos); then compiler
  673. // generate TempS := Copy(...); S := TempS to eliminate side effects and
  674. // implicit "try finally" for TempS finalization
  675. // When we use SetString then no TempS, no try finally generated,
  676. // but we must check case when Value and S is same (side effects)
  677. if Pointer(S) = Pointer(Value) then
  678. System.Delete(S, FuturePos, High(FuturePos))
  679. else
  680. begin
  681. SetString(S, @Value[StartPos], FuturePos - StartPos);
  682. if (FuturePos <= LengthOfValue) and (Value[FuturePos] = #13) then
  683. Inc(FuturePos);
  684. if (FuturePos <= LengthOfValue) and (Value[FuturePos] = #10) then
  685. Inc(FuturePos);
  686. end;
  687. P := FuturePos;
  688. Result := True;
  689. end;
  690. Function TStrings.GetNextLineBreak (Const Value : String; Var S : String; Var P : SizeInt) : Boolean;
  691. var
  692. StartPos, FuturePos: SizeInt;
  693. begin
  694. StartPos := P;
  695. if (StartPos <= 0) or (StartPos > Length(Value)) then // True for Length <= 0
  696. begin
  697. S := '';
  698. Exit(False);
  699. end;
  700. FuturePos := Pos(FLineBreak, Value, StartPos); // Use PosEx in old RTL
  701. // Why we don't use Copy but use SetString read in GetNextLine
  702. if FuturePos = 0 then // No line breaks
  703. begin
  704. FuturePos := Length(Value) + 1;
  705. if Pointer(S) = Pointer(Value) then
  706. // Nothing to do
  707. else
  708. SetString(S, @Value[StartPos], FuturePos - StartPos)
  709. end
  710. else
  711. if Pointer(S) = Pointer(Value) then
  712. System.Delete(S, FuturePos, High(FuturePos))
  713. else
  714. begin
  715. SetString(S, @Value[StartPos], FuturePos - StartPos);
  716. Inc(FuturePos, Length(FLineBreak));
  717. end;
  718. P := FuturePos;
  719. Result := True;
  720. end;
  721. {$IF (SizeOf(Integer) < SizeOf(SizeInt)) }
  722. class function TStrings.GetNextLine(const Value: string; var S: string; var P: Integer) : Boolean;
  723. var
  724. LP: SizeInt;
  725. begin
  726. LP := P;
  727. Result := GetNextLine(Value, S, LP);
  728. P := LP;
  729. end;
  730. function TStrings.GetNextLineBreak(const Value: string; var S: string; var P: Integer) : Boolean;
  731. var
  732. LP: SizeInt;
  733. begin
  734. LP := P;
  735. Result := GetNextLineBreak(Value, S, LP);
  736. P := LP;
  737. end;
  738. {$IFEND}
  739. Procedure TStrings.DoSetTextStr(const Value: string; DoClear : Boolean);
  740. Var
  741. S : String;
  742. P : SizeInt;
  743. begin
  744. Try
  745. beginUpdate;
  746. if DoClear then
  747. Clear;
  748. P:=1;
  749. if FLineBreak=sLineBreak then
  750. begin
  751. While GetNextLine (Value,S,P) do
  752. Add(S)
  753. end
  754. else
  755. While GetNextLineBreak (Value,S,P) do
  756. Add(S);
  757. finally
  758. EndUpdate;
  759. end;
  760. end;
  761. Procedure TStrings.SetTextStr(const Value: string);
  762. begin
  763. CheckSpecialChars;
  764. DoSetTextStr(Value,True);
  765. end;
  766. Procedure TStrings.AddText(const S: string);
  767. begin
  768. CheckSpecialChars;
  769. DoSetTextStr(S,False);
  770. end;
  771. procedure TStrings.AddCommaText(const S: String);
  772. begin
  773. DoSetDelimitedText(S,False,StrictDelimiter,'"',',');
  774. end;
  775. procedure TStrings.AddDelimitedText(const S: String; ADelimiter: AnsiChar; AStrictDelimiter: Boolean);
  776. begin
  777. CheckSpecialChars;
  778. DoSetDelimitedText(S,False,AStrictDelimiter,FQuoteChar,ADelimiter);
  779. end;
  780. procedure TStrings.AddDelimitedText(const S: String);
  781. begin
  782. CheckSpecialChars;
  783. DoSetDelimitedText(S,False,StrictDelimiter,FQuoteChar,FDelimiter);
  784. end;
  785. Procedure TStrings.SetUpdateState(Updating: Boolean);
  786. begin
  787. FPONotifyObservers(Self,ooChange,Nil);
  788. end;
  789. destructor TSTrings.Destroy;
  790. begin
  791. if (FEncoding<>nil) and not TEncoding.IsStandardEncoding(FEncoding) then
  792. FreeAndNil(FEncoding);
  793. if (FDefaultEncoding<>nil) and not TEncoding.IsStandardEncoding(FDefaultEncoding) then
  794. FreeAndNil(FDefaultEncoding);
  795. inherited destroy;
  796. end;
  797. function TStrings.ToObjectArray: TObjectDynArray;
  798. begin
  799. Result:=ToObjectArray(0,Count-1);
  800. end;
  801. function TStrings.ToObjectArray(aStart,aEnd : Integer): TObjectDynArray;
  802. Var
  803. I : Integer;
  804. begin
  805. Result:=Nil;
  806. if aStart>aEnd then exit;
  807. SetLength(Result,aEnd-aStart+1);
  808. For I:=aStart to aEnd do
  809. Result[i-aStart]:=Objects[i];
  810. end;
  811. function TStrings.ToStringArray: TStringDynArray;
  812. begin
  813. Result:=ToStringArray(0,Count-1);
  814. end;
  815. function TStrings.ToStringArray(aStart,aEnd : Integer): TStringDynArray;
  816. Var
  817. I : Integer;
  818. begin
  819. Result:=Nil;
  820. if aStart>aEnd then exit;
  821. SetLength(Result,aEnd-aStart+1);
  822. For I:=aStart to aEnd do
  823. Result[i-aStart]:=Strings[i];
  824. end;
  825. constructor TStrings.Create;
  826. begin
  827. inherited Create;
  828. FDefaultEncoding:=TEncoding.Default;
  829. FEncoding:=nil;
  830. FOptions := [soTrailingLineBreak,soUseLocale,soPreserveBOM];
  831. FAlwaysQuote:=False;
  832. end;
  833. Function TStrings.Add(const S: string): Integer;
  834. begin
  835. Result:=Count;
  836. Insert (Count,S);
  837. end;
  838. function TStrings.Add(const Fmt : string; const Args : Array of const): Integer;
  839. begin
  840. Result:=Add(Format(Fmt,Args));
  841. end;
  842. Function TStrings.AddObject(const S: string; AObject: TObject): Integer;
  843. begin
  844. Result:=Add(S);
  845. Objects[result]:=AObject;
  846. end;
  847. function TStrings.AddObject(const Fmt: string; Args : Array of const; AObject: TObject): Integer;
  848. begin
  849. Result:=AddObject(Format(Fmt,Args),AObject);
  850. end;
  851. function TStrings.AddPair(const AName, AValue: string): TStrings;
  852. begin
  853. Result:=AddPair(AName,AValue,Nil);
  854. end;
  855. function TStrings.AddPair(const AName, AValue: string; AObject: TObject): TStrings;
  856. begin
  857. Result := Self;
  858. AddObject(Concat(AName, NameValueSeparator, AValue), AObject);
  859. end;
  860. Procedure TStrings.Append(const S: string);
  861. begin
  862. Add (S);
  863. end;
  864. Procedure TStrings.AddStrings(TheStrings: TStrings; ClearFirst : Boolean);
  865. Var Runner : longint;
  866. begin
  867. beginupdate;
  868. try
  869. if ClearFirst then
  870. Clear;
  871. if Count + TheStrings.Count > Capacity then
  872. Capacity := Count + TheStrings.Count;
  873. For Runner:=0 to TheStrings.Count-1 do
  874. self.AddObject (Thestrings[Runner],TheStrings.Objects[Runner]);
  875. finally
  876. EndUpdate;
  877. end;
  878. end;
  879. Procedure TStrings.AddStrings(TheStrings: TStrings);
  880. begin
  881. AddStrings(TheStrings, False);
  882. end;
  883. Procedure TStrings.AddStrings(const TheStrings: array of string);
  884. begin
  885. AddStrings(TheStrings, False);
  886. end;
  887. Procedure TStrings.AddStrings(const TheStrings: array of string; ClearFirst : Boolean);
  888. Var Runner : longint;
  889. begin
  890. beginupdate;
  891. try
  892. if ClearFirst then
  893. Clear;
  894. if Count + High(TheStrings)+1 > Capacity then
  895. Capacity := Count + High(TheStrings)+1;
  896. For Runner:=Low(TheStrings) to High(TheStrings) do
  897. self.Add(Thestrings[Runner]);
  898. finally
  899. EndUpdate;
  900. end;
  901. end;
  902. procedure TStrings.SetStrings(TheStrings: TStrings);
  903. begin
  904. AddStrings(TheStrings,True);
  905. end;
  906. procedure TStrings.SetStrings(TheStrings: array of string);
  907. begin
  908. AddStrings(TheStrings,True);
  909. end;
  910. Procedure TStrings.Assign(Source: TPersistent);
  911. Var
  912. S : TStrings;
  913. begin
  914. If Source is TStrings then
  915. begin
  916. S:=TStrings(Source);
  917. BeginUpdate;
  918. Try
  919. clear;
  920. FSpecialCharsInited:=S.FSpecialCharsInited;
  921. FQuoteChar:=S.FQuoteChar;
  922. FDelimiter:=S.FDelimiter;
  923. FNameValueSeparator:=S.FNameValueSeparator;
  924. FLBS:=S.FLBS;
  925. FLineBreak:=S.FLineBreak;
  926. FOptions:=S.FOptions;
  927. DefaultEncoding:=S.DefaultEncoding;
  928. SetEncoding(S.Encoding);
  929. AddStrings(S);
  930. finally
  931. EndUpdate;
  932. end;
  933. end
  934. else
  935. Inherited Assign(Source);
  936. end;
  937. Procedure TStrings.BeginUpdate;
  938. begin
  939. if FUpdateCount = 0 then SetUpdateState(true);
  940. inc(FUpdateCount);
  941. end;
  942. Procedure TStrings.EndUpdate;
  943. begin
  944. If FUpdateCount>0 then
  945. Dec(FUpdateCount);
  946. if FUpdateCount=0 then
  947. SetUpdateState(False);
  948. end;
  949. Function TStrings.Equals(Obj: TObject): Boolean;
  950. begin
  951. if Obj is TStrings then
  952. Result := Equals(TStrings(Obj))
  953. else
  954. Result := inherited Equals(Obj);
  955. end;
  956. Function TStrings.Equals(TheStrings: TStrings): Boolean;
  957. Var Runner,Nr : Longint;
  958. begin
  959. Result:=False;
  960. Nr:=Self.Count;
  961. if Nr<>TheStrings.Count then exit;
  962. For Runner:=0 to Nr-1 do
  963. If Strings[Runner]<>TheStrings[Runner] then exit;
  964. Result:=True;
  965. end;
  966. Procedure TStrings.Exchange(Index1, Index2: Integer);
  967. Var
  968. Obj : TObject;
  969. Str : String;
  970. begin
  971. beginUpdate;
  972. Try
  973. Obj:=Objects[Index1];
  974. Str:=Strings[Index1];
  975. Objects[Index1]:=Objects[Index2];
  976. Strings[Index1]:=Strings[Index2];
  977. Objects[Index2]:=Obj;
  978. Strings[Index2]:=Str;
  979. finally
  980. EndUpdate;
  981. end;
  982. end;
  983. function TStrings.GetEnumerator: TStringsEnumerator;
  984. begin
  985. Result:=TStringsEnumerator.Create(Self);
  986. end;
  987. Function TStrings.GetText: PAnsiChar;
  988. begin
  989. Result:=StrNew(PAnsiChar(Self.Text));
  990. end;
  991. Function TStrings.DoCompareText(const s1,s2 : string) : PtrInt;
  992. begin
  993. if UseLocale then
  994. result:=AnsiCompareText(s1,s2)
  995. else
  996. result:=CompareText(s1,s2);
  997. end;
  998. Function TStrings.IndexOf(const S: string): Integer;
  999. begin
  1000. Result:=0;
  1001. While (Result<Count) and (DoCompareText(Strings[Result],S)<>0) do Result:=Result+1;
  1002. if Result=Count then Result:=-1;
  1003. end;
  1004. function TStrings.IndexOf(const S: string; aStart: Integer): Integer;
  1005. begin
  1006. if aStart<0 then
  1007. begin
  1008. aStart:=Count+aStart;
  1009. if aStart<0 then
  1010. aStart:=0;
  1011. end;
  1012. Result:=aStart;
  1013. While (Result<Count) and (DoCompareText(Strings[Result],S)<>0) do Result:=Result+1;
  1014. if Result=Count then Result:=-1;
  1015. end;
  1016. Function TStrings.IndexOfName(const Name: string): Integer;
  1017. Var
  1018. len : longint;
  1019. S : String;
  1020. begin
  1021. CheckSpecialChars;
  1022. Result:=0;
  1023. while (Result<Count) do
  1024. begin
  1025. S:=Strings[Result];
  1026. len:=pos(FNameValueSeparator,S)-1;
  1027. if (len>=0) and (DoCompareText(Name,Copy(S,1,Len))=0) then
  1028. exit;
  1029. inc(result);
  1030. end;
  1031. result:=-1;
  1032. end;
  1033. Function TStrings.IndexOfObject(AObject: TObject): Integer;
  1034. begin
  1035. Result:=0;
  1036. While (Result<count) and (Objects[Result]<>AObject) do Result:=Result+1;
  1037. If Result=Count then Result:=-1;
  1038. end;
  1039. Procedure TStrings.InsertObject(Index: Integer; const S: string;
  1040. AObject: TObject);
  1041. begin
  1042. Insert (Index,S);
  1043. Objects[Index]:=AObject;
  1044. end;
  1045. function TStrings.LastIndexOf(const S: string): Integer;
  1046. begin
  1047. Result:=LastIndexOf(S,Count-1);
  1048. end;
  1049. function TStrings.LastIndexOf(const S: string; aStart : Integer): Integer;
  1050. begin
  1051. if aStart<0 then
  1052. begin
  1053. aStart:=Count+aStart;
  1054. if aStart<0 then
  1055. aStart:=0;
  1056. end;
  1057. Result:=aStart;
  1058. if Result>=Count-1 then
  1059. Result:=Count-1;
  1060. While (Result>=0) and (DoCompareText(Strings[Result],S)<>0) do
  1061. Result:=Result-1;
  1062. end;
  1063. Procedure TStrings.LoadFromFile(const FileName: string);
  1064. begin
  1065. LoadFromFile(FileName,False)
  1066. end;
  1067. Procedure TStrings.LoadFromFile(const FileName: string; IgnoreEncoding : Boolean);
  1068. Var
  1069. TheStream : TFileStream;
  1070. begin
  1071. TheStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
  1072. try
  1073. LoadFromStream(TheStream, IgnoreEncoding);
  1074. finally
  1075. TheStream.Free;
  1076. end;
  1077. end;
  1078. Procedure TStrings.LoadFromFile(const FileName: string; AEncoding: TEncoding);
  1079. Var
  1080. TheStream : TFileStream;
  1081. begin
  1082. TheStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
  1083. try
  1084. LoadFromStream(TheStream,AEncoding);
  1085. finally
  1086. TheStream.Free;
  1087. end;
  1088. end;
  1089. Procedure TStrings.LoadFromStream(Stream: TStream);
  1090. begin
  1091. LoadFromStream(Stream,False);
  1092. end;
  1093. Const
  1094. LoadBufSize = 1024;
  1095. LoadMaxGrow = MaxInt Div 2;
  1096. Procedure TStrings.LoadFromStream(Stream: TStream; IgnoreEncoding : Boolean);
  1097. {
  1098. Borlands method is no good, since a pipe for
  1099. instance doesn't have a size.
  1100. So we must do it the hard way.
  1101. }
  1102. Var
  1103. Buffer : AnsiString;
  1104. BufLen : SizeInt;
  1105. BytesRead, I, BufDelta : Longint;
  1106. begin
  1107. if not IgnoreEncoding then
  1108. begin
  1109. LoadFromStream(Stream,Nil);
  1110. Exit;
  1111. end;
  1112. // reread into a buffer
  1113. beginupdate;
  1114. try
  1115. Buffer:='';
  1116. BufLen:=0;
  1117. I:=1;
  1118. Repeat
  1119. BufDelta:=LoadBufSize*I;
  1120. SetLength(Buffer,BufLen+BufDelta);
  1121. BytesRead:=Stream.Read(Buffer[BufLen+1],BufDelta);
  1122. inc(BufLen,BufDelta);
  1123. If I<LoadMaxGrow then
  1124. I:=I shl 1;
  1125. Until BytesRead<>BufDelta;
  1126. SetLength(Buffer, BufLen-BufDelta+BytesRead);
  1127. SetTextStr(Buffer);
  1128. SetLength(Buffer,0);
  1129. finally
  1130. EndUpdate;
  1131. end;
  1132. if soPreserveBOM in FOptions then
  1133. WriteBOM:=False;
  1134. end;
  1135. Procedure TStrings.LoadFromStream(Stream: TStream; AEncoding: TEncoding);
  1136. {
  1137. Borlands method is no good, since a pipe for
  1138. instance doesn't have a size.
  1139. So we must do it the hard way.
  1140. }
  1141. Var
  1142. Buffer : TBytes;
  1143. T : string;
  1144. BufLen : SizeInt;
  1145. BytesRead, I, BufDelta, PreambleLength : Longint;
  1146. begin
  1147. // reread into a buffer
  1148. beginupdate;
  1149. try
  1150. SetLength(Buffer,0);
  1151. BufLen:=0;
  1152. I:=1;
  1153. Repeat
  1154. BufDelta:=LoadBufSize*I;
  1155. SetLength(Buffer,BufLen+BufDelta);
  1156. BytesRead:=Stream.Read(Buffer[BufLen],BufDelta);
  1157. inc(BufLen,BufDelta);
  1158. If I<LoadMaxGrow then
  1159. I:=I shl 1;
  1160. Until BytesRead<>BufDelta;
  1161. SetLength(Buffer,BufLen-BufDelta+BytesRead);
  1162. PreambleLength:=TEncoding.GetBufferEncoding(Buffer,AEncoding,FDefaultEncoding);
  1163. T:=AEncoding.GetAnsiString(Buffer,PreambleLength,Length(Buffer)-PreambleLength);
  1164. if soPreserveBOM in FOptions then
  1165. WriteBOM:=PreambleLength>0;
  1166. SetEncoding(AEncoding);
  1167. SetLength(Buffer,0);
  1168. SetTextStr(T);
  1169. finally
  1170. EndUpdate;
  1171. end;
  1172. end;
  1173. Procedure TStrings.Move(CurIndex, NewIndex: Integer);
  1174. Var
  1175. Obj : TObject;
  1176. Str : String;
  1177. begin
  1178. if (CurIndex=NewIndex) then
  1179. Exit;
  1180. BeginUpdate;
  1181. Try
  1182. Obj:=Objects[CurIndex];
  1183. Str:=Strings[CurIndex];
  1184. Objects[CurIndex]:=Nil; // Prevent Delete from freeing.
  1185. Delete(Curindex);
  1186. InsertObject(NewIndex,Str,Obj);
  1187. finally
  1188. EndUpdate;
  1189. end;
  1190. end;
  1191. function TStrings.Pop: string;
  1192. var
  1193. C : Integer;
  1194. begin
  1195. Result:='';
  1196. C:=Count-1;
  1197. if (C>=0) then
  1198. begin
  1199. Result:=Strings[C];
  1200. Delete(C);
  1201. end;
  1202. end;
  1203. function TStrings.Shift: String;
  1204. begin
  1205. Result:='';
  1206. if (Count > 0) then
  1207. begin
  1208. Result:=Strings[0];
  1209. Delete(0);
  1210. end;
  1211. end;
  1212. Procedure TStrings.SaveToFile(const FileName: string);
  1213. Var TheStream : TFileStream;
  1214. begin
  1215. TheStream:=TFileStream.Create(FileName,fmCreate);
  1216. try
  1217. SaveToStream(TheStream);
  1218. finally
  1219. TheStream.Free;
  1220. end;
  1221. end;
  1222. Procedure TStrings.SaveToFile(const FileName: string; IgnoreEncoding : Boolean);
  1223. Var TheStream : TFileStream;
  1224. begin
  1225. TheStream:=TFileStream.Create(FileName,fmCreate);
  1226. try
  1227. SaveToStream(TheStream, IgnoreEncoding);
  1228. finally
  1229. TheStream.Free;
  1230. end;
  1231. end;
  1232. Procedure TStrings.SaveToFile(const FileName: string; AEncoding: TEncoding);
  1233. Var TheStream : TFileStream;
  1234. begin
  1235. TheStream:=TFileStream.Create(FileName,fmCreate);
  1236. try
  1237. SaveToStream(TheStream,AEncoding);
  1238. finally
  1239. TheStream.Free;
  1240. end;
  1241. end;
  1242. Procedure TStrings.SaveToStream(Stream: TStream);
  1243. begin
  1244. SaveToStream(Stream,False)
  1245. end;
  1246. Procedure TStrings.SaveToStream(Stream: TStream; IgnoreEncoding: Boolean);
  1247. Var
  1248. I,L,NLS : SizeInt;
  1249. S,NL : String;
  1250. begin
  1251. if not IgnoreEncoding then
  1252. begin
  1253. SaveToStream(Stream,FEncoding);
  1254. Exit;
  1255. end;
  1256. NL:=GetLineBreakCharLBS;
  1257. NLS:=Length(NL)*SizeOf(AnsiChar);
  1258. For i:=0 To count-1 do
  1259. begin
  1260. S:=Strings[I];
  1261. L:=Length(S);
  1262. if L<>0 then
  1263. Stream.WriteBuffer(S[1], L*SizeOf(AnsiChar));
  1264. if (I<Count-1) or Not SkipLastLineBreak then
  1265. Stream.WriteBuffer(NL[1], NLS);
  1266. end;
  1267. end;
  1268. Procedure TStrings.SaveToStream(Stream: TStream; AEncoding: TEncoding);
  1269. Var B,BNL : TBytes;
  1270. NL,S: string;
  1271. i,BNLS: SizeInt;
  1272. begin
  1273. if AEncoding=nil then
  1274. AEncoding:=FDefaultEncoding;
  1275. if WriteBOM then
  1276. begin
  1277. B:=AEncoding.GetPreamble;
  1278. if Length(B)>0 then
  1279. Stream.WriteBuffer(B[0],Length(B));
  1280. end;
  1281. NL := GetLineBreakCharLBS;
  1282. BNL:=AEncoding.GetAnsiBytes(NL);
  1283. BNLS:=Length(BNL);
  1284. For i:=0 To count-1 do
  1285. begin
  1286. S:=Strings[I];
  1287. if S<>'' then
  1288. begin
  1289. B:=AEncoding.GetAnsiBytes(S);
  1290. Stream.WriteBuffer(B[0],Length(B));
  1291. end;
  1292. if (I<Count-1) or Not SkipLastLineBreak then
  1293. Stream.WriteBuffer(BNL[0],BNLS);
  1294. end;
  1295. end;
  1296. Procedure TStrings.SetText(TheText: PAnsiChar);
  1297. Var S : String;
  1298. begin
  1299. If TheText<>Nil then
  1300. S:=StrPas(TheText)
  1301. else
  1302. S:='';
  1303. SetTextStr(S);
  1304. end;
  1305. {****************************************************************************}
  1306. {* TStringList *}
  1307. {****************************************************************************}
  1308. {$if not defined(FPC_TESTGENERICS)}
  1309. procedure TStringList.ExchangeItemsInt(Index1, Index2: Integer);
  1310. Var P1,P2 : Pointer;
  1311. begin
  1312. P1:=Pointer(Flist^[Index1].FString);
  1313. P2:=Pointer(Flist^[Index1].FObject);
  1314. Pointer(Flist^[Index1].Fstring):=Pointer(Flist^[Index2].Fstring);
  1315. Pointer(Flist^[Index1].FObject):=Pointer(Flist^[Index2].FObject);
  1316. Pointer(Flist^[Index2].Fstring):=P1;
  1317. Pointer(Flist^[Index2].FObject):=P2;
  1318. end;
  1319. function TStringList.GetSorted: Boolean;
  1320. begin
  1321. Result:=FSortStyle in [sslUser,sslAuto];
  1322. end;
  1323. procedure TStringList.ExchangeItems(Index1, Index2: Integer);
  1324. begin
  1325. ExchangeItemsInt(Index1, Index2);
  1326. end;
  1327. procedure TStringList.Grow;
  1328. Var
  1329. NC : Integer;
  1330. begin
  1331. NC:=FCapacity;
  1332. If NC>=256 then
  1333. NC:=NC+(NC Div 4)
  1334. else if NC=0 then
  1335. NC:=4
  1336. else
  1337. NC:=NC*4;
  1338. SetCapacity(NC);
  1339. end;
  1340. procedure TStringList.InternalClear(FromIndex: Integer; ClearOnly: Boolean);
  1341. Var
  1342. I: Integer;
  1343. begin
  1344. if FromIndex < FCount then
  1345. begin
  1346. if FOwnsObjects then
  1347. begin
  1348. For I:=FromIndex to FCount-1 do
  1349. begin
  1350. Flist^[I].FString:='';
  1351. freeandnil(Flist^[i].FObject);
  1352. end;
  1353. end
  1354. else
  1355. begin
  1356. For I:=FromIndex to FCount-1 do
  1357. Flist^[I].FString:='';
  1358. end;
  1359. FCount:=FromIndex;
  1360. end;
  1361. if Not ClearOnly then
  1362. SetCapacity(0);
  1363. end;
  1364. procedure TStringList.InsertItem(Index: Integer; const S: string);
  1365. begin
  1366. InsertItem(Index, S, nil);
  1367. end;
  1368. procedure TStringList.InsertItem(Index: Integer; const S: string; O: TObject);
  1369. begin
  1370. Changing;
  1371. If FCount=Fcapacity then Grow;
  1372. If Index<FCount then
  1373. System.Move (FList^[Index],FList^[Index+1],
  1374. (FCount-Index)*SizeOf(TStringItem));
  1375. Pointer(Flist^[Index].Fstring):=Nil; // Needed to initialize...
  1376. Flist^[Index].FString:=S;
  1377. Flist^[Index].FObject:=O;
  1378. Inc(FCount);
  1379. Changed;
  1380. end;
  1381. procedure TStringList.SetSorted(Value: Boolean);
  1382. begin
  1383. If Value then
  1384. SortStyle:=sslAuto
  1385. else
  1386. SortStyle:=sslNone
  1387. end;
  1388. procedure TStringList.Changed;
  1389. begin
  1390. If (FUpdateCount=0) Then
  1391. begin
  1392. If Assigned(FOnChange) then
  1393. FOnchange(Self);
  1394. FPONotifyObservers(Self,ooChange,Nil);
  1395. end;
  1396. end;
  1397. procedure TStringList.Changing;
  1398. begin
  1399. If FUpdateCount=0 then
  1400. if Assigned(FOnChanging) then
  1401. FOnchanging(Self);
  1402. end;
  1403. function TStringList.Get(Index: Integer): string;
  1404. begin
  1405. CheckIndex(Index);
  1406. Result:=Flist^[Index].FString;
  1407. end;
  1408. function TStringList.GetCapacity: Integer;
  1409. begin
  1410. Result:=FCapacity;
  1411. end;
  1412. function TStringList.GetCount: Integer;
  1413. begin
  1414. Result:=FCount;
  1415. end;
  1416. function TStringList.GetObject(Index: Integer): TObject;
  1417. begin
  1418. CheckIndex(Index);
  1419. Result:=Flist^[Index].FObject;
  1420. end;
  1421. procedure TStringList.Put(Index: Integer; const S: string);
  1422. begin
  1423. If Sorted then
  1424. Error(SSortedListError,0);
  1425. CheckIndex(Index);
  1426. Changing;
  1427. Flist^[Index].FString:=S;
  1428. Changed;
  1429. end;
  1430. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1431. begin
  1432. CheckIndex(Index);
  1433. Changing;
  1434. Flist^[Index].FObject:=AObject;
  1435. Changed;
  1436. end;
  1437. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1438. Var NewList : Pointer;
  1439. MSize : Longint;
  1440. begin
  1441. If (NewCapacity<0) then
  1442. Error (SListCapacityError,NewCapacity);
  1443. If NewCapacity>FCapacity then
  1444. begin
  1445. GetMem (NewList,NewCapacity*SizeOf(TStringItem));
  1446. If NewList=Nil then
  1447. Error (SListCapacityError,NewCapacity);
  1448. If Assigned(FList) then
  1449. begin
  1450. MSize:=FCapacity*Sizeof(TStringItem);
  1451. System.Move (FList^,NewList^,MSize);
  1452. FillWord (PAnsiChar(NewList)[MSize],(NewCapacity-FCapacity)*(SizeOf(TStringItem) div SizeOf(Word)), 0);
  1453. FreeMem (Flist,MSize);
  1454. end;
  1455. Flist:=NewList;
  1456. FCapacity:=NewCapacity;
  1457. end
  1458. else if NewCapacity<FCapacity then
  1459. begin
  1460. if NewCapacity = 0 then
  1461. begin
  1462. if FCount > 0 then
  1463. InternalClear(0,True);
  1464. FreeMem(FList);
  1465. FList := nil;
  1466. end else
  1467. begin
  1468. InternalClear(NewCapacity,True);
  1469. GetMem(NewList, NewCapacity * SizeOf(TStringItem));
  1470. System.Move(FList^, NewList^, NewCapacity * SizeOf(TStringItem));
  1471. FreeMem(FList);
  1472. FList := NewList;
  1473. end;
  1474. FCapacity:=NewCapacity;
  1475. end;
  1476. end;
  1477. procedure TStringList.SetUpdateState(Updating: Boolean);
  1478. begin
  1479. If Updating then
  1480. Changing
  1481. else
  1482. Changed
  1483. end;
  1484. Constructor TStringList.Create;
  1485. begin
  1486. inherited Create;
  1487. end;
  1488. Constructor TStringList.Create(anOwnsObjects : Boolean);
  1489. begin
  1490. inherited Create;
  1491. FOwnsObjects:=anOwnsObjects;
  1492. end;
  1493. destructor TStringList.Destroy;
  1494. begin
  1495. InternalClear;
  1496. Inherited destroy;
  1497. end;
  1498. function TStringList.Add(const S: string): Integer;
  1499. begin
  1500. If (SortStyle<>sslAuto) then
  1501. Result:=FCount
  1502. else
  1503. If Find (S,Result) then
  1504. Case DUplicates of
  1505. DupIgnore : Exit;
  1506. DupError : Error(SDuplicateString,0)
  1507. end;
  1508. InsertItem (Result,S);
  1509. end;
  1510. procedure TStringList.Clear;
  1511. begin
  1512. if FCount = 0 then Exit;
  1513. Changing;
  1514. InternalClear;
  1515. Changed;
  1516. end;
  1517. procedure TStringList.Delete(Index: Integer);
  1518. begin
  1519. CheckIndex(Index);
  1520. Changing;
  1521. Flist^[Index].FString:='';
  1522. if FOwnsObjects then
  1523. FreeAndNil(Flist^[Index].FObject);
  1524. Dec(FCount);
  1525. If Index<FCount then
  1526. System.Move(Flist^[Index+1],
  1527. Flist^[Index],
  1528. (Fcount-Index)*SizeOf(TStringItem));
  1529. Changed;
  1530. end;
  1531. procedure TStringList.Exchange(Index1, Index2: Integer);
  1532. begin
  1533. CheckIndex(Index1);
  1534. CheckIndex(Index2);
  1535. Changing;
  1536. ExchangeItemsInt(Index1,Index2);
  1537. changed;
  1538. end;
  1539. procedure TStringList.SetCaseSensitive(b : boolean);
  1540. begin
  1541. if b=FCaseSensitive then
  1542. Exit;
  1543. FCaseSensitive:=b;
  1544. if FSortStyle=sslAuto then
  1545. begin
  1546. FForceSort:=True;
  1547. try
  1548. Sort;
  1549. finally
  1550. FForceSort:=False;
  1551. end;
  1552. end;
  1553. end;
  1554. procedure TStringList.SetSortStyle(AValue: TStringsSortStyle);
  1555. begin
  1556. if FSortStyle=AValue then Exit;
  1557. if (AValue=sslAuto) then
  1558. Sort;
  1559. FSortStyle:=AValue;
  1560. end;
  1561. procedure TStringList.CheckIndex(AIndex: Integer);
  1562. begin
  1563. If (AIndex<0) or (AIndex>=FCount) then
  1564. Error(SListIndexError,AIndex);
  1565. end;
  1566. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1567. begin
  1568. if FCaseSensitive then
  1569. begin
  1570. if UseLocale then
  1571. result:=AnsiCompareStr(s1,s2)
  1572. else
  1573. result:=CompareStr(s1,s2);
  1574. end else
  1575. begin
  1576. if UseLocale then
  1577. result:=AnsiCompareText(s1,s2)
  1578. else
  1579. result:=CompareText(s1,s2);
  1580. end;
  1581. end;
  1582. function TStringList.Find(const S: string; out Index: Integer): Boolean;
  1583. var
  1584. L, R, I: Integer;
  1585. CompareRes: PtrInt;
  1586. begin
  1587. Result := false;
  1588. Index:=-1;
  1589. if Not Sorted then
  1590. Raise EListError.Create(SErrFindNeedsSortedList);
  1591. // Use binary search.
  1592. L := 0;
  1593. R := Count - 1;
  1594. while (L<=R) do
  1595. begin
  1596. I := L + (R - L) div 2;
  1597. CompareRes := DoCompareText(S, Flist^[I].FString);
  1598. if (CompareRes>0) then
  1599. L := I+1
  1600. else begin
  1601. R := I-1;
  1602. if (CompareRes=0) then begin
  1603. Result := true;
  1604. if (Duplicates<>dupAccept) then
  1605. L := I; // forces end of while loop
  1606. end;
  1607. end;
  1608. end;
  1609. Index := L;
  1610. end;
  1611. function TStringList.IndexOf(const S: string): Integer;
  1612. begin
  1613. If Not Sorted then
  1614. Result:=Inherited indexOf(S)
  1615. else
  1616. // faster using binary search...
  1617. If Not Find (S,Result) then
  1618. Result:=-1;
  1619. end;
  1620. procedure TStringList.Insert(Index: Integer; const S: string);
  1621. begin
  1622. If SortStyle=sslAuto then
  1623. Error (SSortedListError,0)
  1624. else
  1625. begin
  1626. If (Index<0) or (Index>FCount) then
  1627. Error(SListIndexError,Index); // Cannot use CheckIndex, because there >= FCount...
  1628. InsertItem (Index,S);
  1629. end;
  1630. end;
  1631. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1632. begin
  1633. CustomSort(CompareFn, SortBase.DefaultSortingAlgorithm);
  1634. end;
  1635. type
  1636. PStringList_CustomSort_Context = ^TStringList_CustomSort_Context;
  1637. TStringList_CustomSort_Context = record
  1638. List: TStringList;
  1639. ListStartPtr: Pointer;
  1640. CompareFn: TStringListSortCompare;
  1641. end;
  1642. function TStringList_CustomSort_Comparer(Item1, Item2, Context: Pointer): Integer;
  1643. begin
  1644. with PStringList_CustomSort_Context(Context)^ do
  1645. Result := CompareFn(List,
  1646. (Item1 - ListStartPtr) div SizeOf(TStringItem),
  1647. (Item2 - ListStartPtr) div SizeOf(TStringItem));
  1648. end;
  1649. procedure TStringList_CustomSort_Exchanger(Item1, Item2, Context: Pointer);
  1650. begin
  1651. with PStringList_CustomSort_Context(Context)^ do
  1652. List.ExchangeItems((Item1 - ListStartPtr) div SizeOf(TStringItem),
  1653. (Item2 - ListStartPtr) div SizeOf(TStringItem));
  1654. end;
  1655. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare; SortingAlgorithm: PSortingAlgorithm);
  1656. var
  1657. Context: TStringList_CustomSort_Context;
  1658. begin
  1659. If (FCount>1) and (FForceSort or (FSortStyle<>sslAuto)) then
  1660. begin
  1661. Changing;
  1662. Context.List := Self;
  1663. Context.ListStartPtr := FList;
  1664. Context.CompareFn := CompareFn;
  1665. //if ExchangeItems is overriden call that, else call (faster) ItemListSorter_ContextComparer
  1666. if TMethod(@Self.ExchangeItems).Code = CodePointer(@TStringList.ExchangeItems) then
  1667. SortingAlgorithm^.ItemListSorter_ContextComparer(
  1668. FList, FCount, SizeOf(TStringItem), @TStringList_CustomSort_Comparer,
  1669. @Context)
  1670. else
  1671. SortingAlgorithm^.ItemListSorter_CustomItemExchanger_ContextComparer(
  1672. FList, FCount, SizeOf(TStringItem), @TStringList_CustomSort_Comparer,
  1673. @TStringList_CustomSort_Exchanger, @Context);
  1674. Changed;
  1675. end;
  1676. end;
  1677. function StringListAnsiCompare(List: TStringList; Index1, Index: Integer): Integer;
  1678. begin
  1679. Result := List.DoCompareText(List.FList^[Index1].FString,
  1680. List.FList^[Index].FString);
  1681. end;
  1682. procedure TStringList.Sort;
  1683. begin
  1684. CustomSort(@StringListAnsiCompare);
  1685. end;
  1686. procedure TStringList.Sort(SortingAlgorithm: PSortingAlgorithm);
  1687. begin
  1688. CustomSort(@StringListAnsiCompare, SortingAlgorithm);
  1689. end;
  1690. {$else}
  1691. { generics based implementation of TStringList follows }
  1692. function StringListAnsiCompare(List: TStringList; Index1, Index2: Integer): Integer;
  1693. begin
  1694. Result := List.DoCompareText(List.Strings[Index1], List.Strings[Index2]);
  1695. end;
  1696. constructor TStringList.Create;
  1697. begin
  1698. inherited;
  1699. FOwnsObjects:=false;
  1700. FMap := TFPStrObjMap.Create;
  1701. FMap.OnPtrCompare := @MapPtrCompare;
  1702. FOnCompareText := @DefaultCompareText;
  1703. NameValueSeparator:='=';
  1704. CheckSpecialChars;
  1705. end;
  1706. destructor TStringList.Destroy;
  1707. begin
  1708. FMap.Free;
  1709. inherited;
  1710. end;
  1711. function TStringList.GetDuplicates: TDuplicates;
  1712. begin
  1713. Result := FMap.Duplicates;
  1714. end;
  1715. function TStringList.GetSorted: boolean;
  1716. begin
  1717. Result := FMap.Sorted;
  1718. end;
  1719. procedure TStringList.SetDuplicates(NewDuplicates: TDuplicates);
  1720. begin
  1721. FMap.Duplicates := NewDuplicates;
  1722. end;
  1723. procedure TStringList.SetSorted(NewSorted: Boolean);
  1724. begin
  1725. FMap.Sorted := NewSorted;
  1726. end;
  1727. procedure TStringList.Changed;
  1728. begin
  1729. if FUpdateCount = 0 then
  1730. if Assigned(FOnChange) then
  1731. FOnChange(Self);
  1732. end;
  1733. procedure TStringList.Changing;
  1734. begin
  1735. if FUpdateCount = 0 then
  1736. if Assigned(FOnChanging) then
  1737. FOnChanging(Self);
  1738. end;
  1739. function TStringList.Get(Index: Integer): string;
  1740. begin
  1741. Result := FMap.Keys[Index];
  1742. end;
  1743. function TStringList.GetCapacity: Integer;
  1744. begin
  1745. Result := FMap.Capacity;
  1746. end;
  1747. function TStringList.GetCount: Integer;
  1748. begin
  1749. Result := FMap.Count;
  1750. end;
  1751. function TStringList.GetObject(Index: Integer): TObject;
  1752. begin
  1753. Result := FMap.Data[Index];
  1754. end;
  1755. procedure TStringList.Put(Index: Integer; const S: string);
  1756. begin
  1757. Changing;
  1758. FMap.Keys[Index] := S;
  1759. Changed;
  1760. end;
  1761. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1762. begin
  1763. Changing;
  1764. FMap.Data[Index] := AObject;
  1765. Changed;
  1766. end;
  1767. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1768. begin
  1769. FMap.Capacity := NewCapacity;
  1770. end;
  1771. procedure TStringList.SetUpdateState(Updating: Boolean);
  1772. begin
  1773. if Updating then
  1774. Changing
  1775. else
  1776. Changed
  1777. end;
  1778. function TStringList.Add(const S: string): Integer;
  1779. begin
  1780. Result := FMap.Add(S);
  1781. end;
  1782. procedure TStringList.Clear;
  1783. begin
  1784. if FMap.Count = 0 then exit;
  1785. Changing;
  1786. FMap.Clear;
  1787. Changed;
  1788. end;
  1789. procedure TStringList.Delete(Index: Integer);
  1790. begin
  1791. if (Index < 0) or (Index >= FMap.Count) then
  1792. Error(SListIndexError, Index);
  1793. Changing;
  1794. FMap.Delete(Index);
  1795. Changed;
  1796. end;
  1797. procedure TStringList.Exchange(Index1, Index2: Integer);
  1798. begin
  1799. if (Index1 < 0) or (Index1 >= FMap.Count) then
  1800. Error(SListIndexError, Index1);
  1801. if (Index2 < 0) or (Index2 >= FMap.Count) then
  1802. Error(SListIndexError, Index2);
  1803. Changing;
  1804. FMap.InternalExchange(Index1, Index2);
  1805. Changed;
  1806. end;
  1807. procedure TStringList.SetCaseSensitive(NewSensitive: Boolean);
  1808. begin
  1809. if NewSensitive <> FCaseSensitive then
  1810. begin
  1811. FCaseSensitive := NewSensitive;
  1812. if Sorted then
  1813. Sort;
  1814. end;
  1815. end;
  1816. function TStringList.MapPtrCompare(Key1, Key2: Pointer): Integer;
  1817. begin
  1818. Result := FOnCompareText(string(Key1^), string(Key2^));
  1819. end;
  1820. function TStringList.DefaultCompareText(const s1, s2: string): PtrInt;
  1821. begin
  1822. if FCaseSensitive then
  1823. Result := AnsiCompareStr(s1, s2)
  1824. else
  1825. Result := AnsiCompareText(s1, s2);
  1826. end;
  1827. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1828. begin
  1829. Result := FOnCompareText(s1, s2);
  1830. end;
  1831. function TStringList.Find(const S: string; var Index: Integer): Boolean;
  1832. begin
  1833. Result := FMap.Find(S, Index);
  1834. end;
  1835. function TStringList.IndexOf(const S: string): Integer;
  1836. begin
  1837. Result := FMap.IndexOf(S);
  1838. end;
  1839. procedure TStringList.Insert(Index: Integer; const S: string);
  1840. begin
  1841. if not Sorted and (0 <= Index) and (Index < FMap.Count) then
  1842. Changing;
  1843. FMap.InsertKey(Index, S);
  1844. Changed;
  1845. end;
  1846. type
  1847. PStringList_CustomSort_Context = ^TStringList_CustomSort_Context;
  1848. TStringList_CustomSort_Context = record
  1849. List: TStringList;
  1850. ListStartPtr: Pointer;
  1851. ItemSize: SizeUInt;
  1852. IndexBase: Integer;
  1853. CompareFn: TStringListSortCompare;
  1854. end;
  1855. function TStringList_CustomSort_Comparer(Item1, Item2, Context: Pointer): Integer;
  1856. begin
  1857. with PStringList_CustomSort_Context(Context)^ do
  1858. Result := CompareFn(List,
  1859. ((Item1 - ListStartPtr) div ItemSize) + IndexBase,
  1860. ((Item2 - ListStartPtr) div ItemSize) + IndexBase);
  1861. end;
  1862. procedure TStringList_CustomSort_Exchanger(Item1, Item2, Context: Pointer);
  1863. begin
  1864. with PStringList_CustomSort_Context(Context)^ do
  1865. List.Exchange(((Item1 - ListStartPtr) div ItemSize) + IndexBase,
  1866. ((Item2 - ListStartPtr) div ItemSize) + IndexBase);
  1867. end;
  1868. procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  1869. var
  1870. Context: TStringList_CustomSort_Context;
  1871. begin
  1872. if L > R then
  1873. exit;
  1874. Context.List := Self;
  1875. Context.ListStartPtr := FMap.Items[L];
  1876. Context.CompareFn := CompareFn;
  1877. Context.ItemSize := FMap.KeySize + FMap.DataSize;
  1878. Context.IndexBase := L;
  1879. DefaultSortingAlgorithm^.ItemListSorter_CustomItemExchanger_ContextComparer(
  1880. Context.ListStartPtr, R - L + 1, Context.ItemSize, @TStringList_CustomSort_Comparer,
  1881. @TStringList_CustomSort_Exchanger, @Context);
  1882. end;
  1883. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1884. begin
  1885. if not Sorted and (FMap.Count > 1) then
  1886. begin
  1887. Changing;
  1888. QuickSort(0, FMap.Count-1, CompareFn);
  1889. Changed;
  1890. end;
  1891. end;
  1892. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare; SortingAlgorithm: PSortingAlgorithm);
  1893. var
  1894. Context: TStringList_CustomSort_Context;
  1895. begin
  1896. if not Sorted and (FMap.Count > 1) then
  1897. begin
  1898. Changing;
  1899. Context.List := Self;
  1900. Context.ListStartPtr := FMap.Items[0];
  1901. Context.CompareFn := CompareFn;
  1902. Context.ItemSize := FMap.KeySize + FMap.DataSize;
  1903. Context.IndexBase := 0;
  1904. SortingAlgorithm^.ItemListSorter_CustomItemExchanger_ContextComparer(
  1905. Context.ListStartPtr, FMap.Count, Context.ItemSize, @TStringList_CustomSort_Comparer,
  1906. @TStringList_CustomSort_Exchanger, @Context);
  1907. Changed;
  1908. end;
  1909. end;
  1910. procedure TStringList.Sort;
  1911. begin
  1912. if not Sorted and (FMap.Count > 1) then
  1913. begin
  1914. Changing;
  1915. FMap.Sort;
  1916. Changed;
  1917. end;
  1918. end;
  1919. procedure TStringList.Sort(SortingAlgorithm: PSortingAlgorithm);
  1920. begin
  1921. if not Sorted and (FMap.Count > 1) then
  1922. begin
  1923. Changing;
  1924. FMap.Sort(SortingAlgorithm);
  1925. Changed;
  1926. end;
  1927. end;
  1928. {$endif}