stringl.inc 48 KB

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