stringl.inc 49 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456
  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. begin
  568. if Value<>'' then
  569. Add (Name+FNameValueSeparator+Value)
  570. end
  571. else
  572. begin
  573. if Value='' then
  574. Delete(L)
  575. else
  576. Strings[L]:=Name+FNameValueSeparator+value;
  577. end;
  578. end;
  579. procedure TStrings.WriteData(Writer: TWriter);
  580. var
  581. i: Integer;
  582. begin
  583. Writer.WriteListBegin;
  584. for i := 0 to Count - 1 do
  585. Writer.WriteString(Strings[i]);
  586. Writer.WriteListEnd;
  587. end;
  588. function TStrings.CompareStrings(const s1,s2 : string) : Integer;
  589. begin
  590. Result := DoCompareText(s1, s2);
  591. end;
  592. procedure TStrings.DefineProperties(Filer: TFiler);
  593. var
  594. HasData: Boolean;
  595. begin
  596. if Assigned(Filer.Ancestor) then
  597. // Only serialize if string list is different from ancestor
  598. if Filer.Ancestor.InheritsFrom(TStrings) then
  599. HasData := not Equals(TStrings(Filer.Ancestor))
  600. else
  601. HasData := True
  602. else
  603. HasData := Count > 0;
  604. Filer.DefineProperty('Strings', @ReadData, @WriteData, HasData);
  605. end;
  606. Procedure TStrings.Error(const Msg: string; Data: Integer);
  607. begin
  608. Raise EStringListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  609. end;
  610. Procedure TStrings.Error(const Msg: pstring; Data: Integer);
  611. begin
  612. Raise EStringListError.CreateFmt(Msg^,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  613. end;
  614. Function TStrings.GetCapacity: Integer;
  615. begin
  616. Result:=Count;
  617. end;
  618. Function TStrings.GetObject(Index: Integer): TObject;
  619. begin
  620. Result:=Nil;
  621. end;
  622. Function TStrings.GetTextStr: string;
  623. Var P : PChar;
  624. I,L,NLS : SizeInt;
  625. S,NL : String;
  626. begin
  627. NL:=GetLineBreakCharLBS;
  628. // Determine needed place
  629. L:=0;
  630. NLS:=Length(NL);
  631. For I:=0 to count-1 do
  632. L:=L+Length(Strings[I])+NLS;
  633. if SkipLastLineBreak then
  634. Dec(L,NLS);
  635. Setlength(Result,L);
  636. P:=Pointer(Result);
  637. For i:=0 To count-1 do
  638. begin
  639. S:=Strings[I];
  640. L:=Length(S);
  641. if L<>0 then
  642. System.Move(Pointer(S)^,P^,L*SizeOf(Char));
  643. Inc(P,L);
  644. if (I<Count-1) or Not SkipLastLineBreak then
  645. For L:=1 to NLS do
  646. begin
  647. P^:=NL[L];
  648. inc(P);
  649. end;
  650. end;
  651. end;
  652. Procedure TStrings.Put(Index: Integer; const S: string);
  653. Var Obj : TObject;
  654. begin
  655. Obj:=Objects[Index];
  656. Delete(Index);
  657. InsertObject(Index,S,Obj);
  658. end;
  659. Procedure TStrings.PutObject(Index: Integer; AObject: TObject);
  660. begin
  661. // Empty.
  662. end;
  663. Procedure TStrings.SetCapacity(NewCapacity: Integer);
  664. begin
  665. // Empty.
  666. end;
  667. Class Function TStrings.GetNextLine (Const Value : String; Var S : String; Var P : SizeInt) : Boolean;
  668. var
  669. LengthOfValue: SizeInt;
  670. StartPos, FuturePos: SizeInt;
  671. begin
  672. LengthOfValue := Length(Value);
  673. StartPos := P;
  674. if (StartPos <= 0) or (StartPos > LengthOfValue) then // True for LengthOfValue <= 0
  675. begin
  676. S := '';
  677. Exit(False);
  678. end;
  679. FuturePos := StartPos;
  680. while (FuturePos <= LengthOfValue) and not (Value[FuturePos] in [#10, #13]) do
  681. Inc(FuturePos);
  682. // If we use S := Copy(Value, StartPos, FuturePos - StartPos); then compiler
  683. // generate TempS := Copy(...); S := TempS to eliminate side effects and
  684. // implicit "try finally" for TempS finalization
  685. // When we use SetString then no TempS, no try finally generated,
  686. // but we must check case when Value and S is same (side effects)
  687. if Pointer(S) = Pointer(Value) then
  688. System.Delete(S, FuturePos, High(FuturePos))
  689. else
  690. begin
  691. SetString(S, PChar(@Value[StartPos]), FuturePos - StartPos);
  692. if (FuturePos <= LengthOfValue) and (Value[FuturePos] = #13) then
  693. Inc(FuturePos);
  694. if (FuturePos <= LengthOfValue) and (Value[FuturePos] = #10) then
  695. Inc(FuturePos);
  696. end;
  697. P := FuturePos;
  698. Result := True;
  699. end;
  700. Function TStrings.GetNextLineBreak (Const Value : String; Var S : String; Var P : SizeInt) : Boolean;
  701. var
  702. StartPos, FuturePos: SizeInt;
  703. begin
  704. StartPos := P;
  705. if (StartPos <= 0) or (StartPos > Length(Value)) then // True for Length <= 0
  706. begin
  707. S := '';
  708. Exit(False);
  709. end;
  710. FuturePos := Pos(FLineBreak, Value, StartPos); // Use PosEx in old RTL
  711. // Why we don't use Copy but use SetString read in GetNextLine
  712. if FuturePos = 0 then // No line breaks
  713. begin
  714. FuturePos := Length(Value) + 1;
  715. if Pointer(S) = Pointer(Value) then
  716. // Nothing to do
  717. else
  718. SetString(S, @Value[StartPos], FuturePos - StartPos)
  719. end
  720. else
  721. if Pointer(S) = Pointer(Value) then
  722. System.Delete(S, FuturePos, High(FuturePos))
  723. else
  724. begin
  725. SetString(S, @Value[StartPos], FuturePos - StartPos);
  726. Inc(FuturePos, Length(FLineBreak));
  727. end;
  728. P := FuturePos;
  729. Result := True;
  730. end;
  731. {$IF (SizeOf(Integer) < SizeOf(SizeInt)) }
  732. class function TStrings.GetNextLine(const Value: string; var S: string; var P: Integer) : Boolean;
  733. var
  734. LP: SizeInt;
  735. begin
  736. LP := P;
  737. Result := GetNextLine(Value, S, LP);
  738. P := LP;
  739. end;
  740. function TStrings.GetNextLineBreak(const Value: string; var S: string; var P: Integer) : Boolean;
  741. var
  742. LP: SizeInt;
  743. begin
  744. LP := P;
  745. Result := GetNextLineBreak(Value, S, LP);
  746. P := LP;
  747. end;
  748. {$IFEND}
  749. Procedure TStrings.DoSetTextStr(const Value: string; DoClear : Boolean);
  750. Var
  751. S : String;
  752. P : SizeInt;
  753. begin
  754. Try
  755. beginUpdate;
  756. if DoClear then
  757. Clear;
  758. P:=1;
  759. if FLineBreak=sLineBreak then
  760. begin
  761. While GetNextLine (Value,S,P) do
  762. Add(S)
  763. end
  764. else
  765. While GetNextLineBreak (Value,S,P) do
  766. Add(S);
  767. finally
  768. EndUpdate;
  769. end;
  770. end;
  771. Procedure TStrings.SetTextStr(const Value: string);
  772. begin
  773. CheckSpecialChars;
  774. DoSetTextStr(Value,True);
  775. end;
  776. Procedure TStrings.AddText(const S: string);
  777. begin
  778. CheckSpecialChars;
  779. DoSetTextStr(S,False);
  780. end;
  781. procedure TStrings.AddCommaText(const S: String);
  782. begin
  783. DoSetDelimitedText(S,False,StrictDelimiter,'"',',');
  784. end;
  785. procedure TStrings.AddDelimitedText(const S: String; ADelimiter: Char; AStrictDelimiter: Boolean);
  786. begin
  787. CheckSpecialChars;
  788. DoSetDelimitedText(S,False,AStrictDelimiter,FQuoteChar,ADelimiter);
  789. end;
  790. procedure TStrings.AddDelimitedText(const S: String);
  791. begin
  792. CheckSpecialChars;
  793. DoSetDelimitedText(S,False,StrictDelimiter,FQuoteChar,FDelimiter);
  794. end;
  795. Procedure TStrings.SetUpdateState(Updating: Boolean);
  796. begin
  797. FPONotifyObservers(Self,ooChange,Nil);
  798. end;
  799. destructor TSTrings.Destroy;
  800. begin
  801. if (FEncoding<>nil) and not TEncoding.IsStandardEncoding(FEncoding) then
  802. FreeAndNil(FEncoding);
  803. if (FDefaultEncoding<>nil) and not TEncoding.IsStandardEncoding(FDefaultEncoding) then
  804. FreeAndNil(FDefaultEncoding);
  805. inherited destroy;
  806. end;
  807. function TStrings.ToObjectArray: TObjectDynArray;
  808. begin
  809. Result:=ToObjectArray(0,Count-1);
  810. end;
  811. function TStrings.ToObjectArray(aStart,aEnd : Integer): TObjectDynArray;
  812. Var
  813. I : Integer;
  814. begin
  815. Result:=Nil;
  816. if aStart>aEnd then exit;
  817. SetLength(Result,aEnd-aStart+1);
  818. For I:=aStart to aEnd do
  819. Result[i-aStart]:=Objects[i];
  820. end;
  821. function TStrings.ToStringArray: TStringDynArray;
  822. begin
  823. Result:=ToStringArray(0,Count-1);
  824. end;
  825. function TStrings.ToStringArray(aStart,aEnd : Integer): TStringDynArray;
  826. Var
  827. I : Integer;
  828. begin
  829. Result:=Nil;
  830. if aStart>aEnd then exit;
  831. SetLength(Result,aEnd-aStart+1);
  832. For I:=aStart to aEnd do
  833. Result[i-aStart]:=Strings[i];
  834. end;
  835. constructor TStrings.Create;
  836. begin
  837. inherited Create;
  838. FDefaultEncoding:=TEncoding.Default;
  839. FEncoding:=nil;
  840. FOptions := [soTrailingLineBreak,soUseLocale,soPreserveBOM];
  841. FAlwaysQuote:=False;
  842. end;
  843. Function TStrings.Add(const S: string): Integer;
  844. begin
  845. Result:=Count;
  846. Insert (Count,S);
  847. end;
  848. function TStrings.Add(const Fmt : string; const Args : Array of const): Integer;
  849. begin
  850. Result:=Add(Format(Fmt,Args));
  851. end;
  852. Function TStrings.AddObject(const S: string; AObject: TObject): Integer;
  853. begin
  854. BeginUpdate;
  855. try
  856. Result:=Add(S);
  857. Objects[result]:=AObject;
  858. finally
  859. EndUpdate;
  860. end;
  861. end;
  862. function TStrings.AddObject(const Fmt: string; Args : Array of const; AObject: TObject): Integer;
  863. begin
  864. Result:=AddObject(Format(Fmt,Args),AObject);
  865. end;
  866. function TStrings.AddPair(const AName, AValue: string): TStrings;
  867. begin
  868. Result:=AddPair(AName,AValue,Nil);
  869. end;
  870. function TStrings.AddPair(const AName, AValue: string; AObject: TObject): TStrings;
  871. begin
  872. Result := Self;
  873. AddObject(Concat(AName, NameValueSeparator, AValue), AObject);
  874. end;
  875. Procedure TStrings.Append(const S: string);
  876. begin
  877. Add (S);
  878. end;
  879. Procedure TStrings.AddStrings(TheStrings: TStrings; ClearFirst : Boolean);
  880. Var Runner : longint;
  881. begin
  882. beginupdate;
  883. try
  884. if ClearFirst then
  885. Clear;
  886. if Count + TheStrings.Count > Capacity then
  887. Capacity := Count + TheStrings.Count;
  888. For Runner:=0 to TheStrings.Count-1 do
  889. self.AddObject (Thestrings[Runner],TheStrings.Objects[Runner]);
  890. finally
  891. EndUpdate;
  892. end;
  893. end;
  894. Procedure TStrings.AddStrings(TheStrings: TStrings);
  895. begin
  896. AddStrings(TheStrings, False);
  897. end;
  898. Procedure TStrings.AddStrings(const TheStrings: array of string);
  899. begin
  900. AddStrings(TheStrings, False);
  901. end;
  902. Procedure TStrings.AddStrings(const TheStrings: array of string; ClearFirst : Boolean);
  903. Var Runner : longint;
  904. begin
  905. beginupdate;
  906. try
  907. if ClearFirst then
  908. Clear;
  909. if Count + High(TheStrings)+1 > Capacity then
  910. Capacity := Count + High(TheStrings)+1;
  911. For Runner:=Low(TheStrings) to High(TheStrings) do
  912. self.Add(Thestrings[Runner]);
  913. finally
  914. EndUpdate;
  915. end;
  916. end;
  917. procedure TStrings.SetStrings(TheStrings: TStrings);
  918. begin
  919. AddStrings(TheStrings,True);
  920. end;
  921. procedure TStrings.SetStrings(TheStrings: array of string);
  922. begin
  923. AddStrings(TheStrings,True);
  924. end;
  925. Procedure TStrings.Assign(Source: TPersistent);
  926. Var
  927. S : TStrings;
  928. begin
  929. If Source is TStrings then
  930. begin
  931. S:=TStrings(Source);
  932. BeginUpdate;
  933. Try
  934. clear;
  935. FSpecialCharsInited:=S.FSpecialCharsInited;
  936. FQuoteChar:=S.FQuoteChar;
  937. FDelimiter:=S.FDelimiter;
  938. FNameValueSeparator:=S.FNameValueSeparator;
  939. FLBS:=S.FLBS;
  940. FLineBreak:=S.FLineBreak;
  941. FOptions:=S.FOptions;
  942. DefaultEncoding:=S.DefaultEncoding;
  943. SetEncoding(S.Encoding);
  944. AddStrings(S);
  945. finally
  946. EndUpdate;
  947. end;
  948. end
  949. else
  950. Inherited Assign(Source);
  951. end;
  952. Procedure TStrings.BeginUpdate;
  953. begin
  954. if FUpdateCount = 0 then SetUpdateState(true);
  955. inc(FUpdateCount);
  956. end;
  957. Procedure TStrings.EndUpdate;
  958. begin
  959. If FUpdateCount>0 then
  960. Dec(FUpdateCount);
  961. if FUpdateCount=0 then
  962. SetUpdateState(False);
  963. end;
  964. Function TStrings.Equals(Obj: TObject): Boolean;
  965. begin
  966. if Obj is TStrings then
  967. Result := Equals(TStrings(Obj))
  968. else
  969. Result := inherited Equals(Obj);
  970. end;
  971. Function TStrings.Equals(TheStrings: TStrings): Boolean;
  972. Var Runner,Nr : Longint;
  973. begin
  974. Result:=False;
  975. Nr:=Self.Count;
  976. if Nr<>TheStrings.Count then exit;
  977. For Runner:=0 to Nr-1 do
  978. If Strings[Runner]<>TheStrings[Runner] then exit;
  979. Result:=True;
  980. end;
  981. Procedure TStrings.Exchange(Index1, Index2: Integer);
  982. Var
  983. Obj : TObject;
  984. Str : String;
  985. begin
  986. beginUpdate;
  987. Try
  988. Obj:=Objects[Index1];
  989. Str:=Strings[Index1];
  990. Objects[Index1]:=Objects[Index2];
  991. Strings[Index1]:=Strings[Index2];
  992. Objects[Index2]:=Obj;
  993. Strings[Index2]:=Str;
  994. finally
  995. EndUpdate;
  996. end;
  997. end;
  998. function TStrings.GetEnumerator: TStringsEnumerator;
  999. begin
  1000. Result:=TStringsEnumerator.Create(Self);
  1001. end;
  1002. Function TStrings.GetText: PChar;
  1003. begin
  1004. Result:=StrNew(PChar(Self.Text));
  1005. end;
  1006. Function TStrings.DoCompareText(const s1,s2 : string) : PtrInt;
  1007. begin
  1008. if UseLocale then
  1009. result:=AnsiCompareText(s1,s2)
  1010. else
  1011. result:=CompareText(s1,s2);
  1012. end;
  1013. Function TStrings.IndexOf(const S: string): Integer;
  1014. begin
  1015. Result:=0;
  1016. While (Result<Count) and (DoCompareText(Strings[Result],S)<>0) do Result:=Result+1;
  1017. if Result=Count then Result:=-1;
  1018. end;
  1019. function TStrings.IndexOf(const S: string; aStart: Integer): Integer;
  1020. begin
  1021. if aStart<0 then
  1022. begin
  1023. aStart:=Count+aStart;
  1024. if aStart<0 then
  1025. aStart:=0;
  1026. end;
  1027. Result:=aStart;
  1028. While (Result<Count) and (DoCompareText(Strings[Result],S)<>0) do Result:=Result+1;
  1029. if Result=Count then Result:=-1;
  1030. end;
  1031. Function TStrings.IndexOfName(const Name: string): Integer;
  1032. Var
  1033. len : longint;
  1034. S : String;
  1035. begin
  1036. CheckSpecialChars;
  1037. Result:=0;
  1038. while (Result<Count) do
  1039. begin
  1040. S:=Strings[Result];
  1041. len:=pos(FNameValueSeparator,S)-1;
  1042. if (len>=0) and (DoCompareText(Name,Copy(S,1,Len))=0) then
  1043. exit;
  1044. inc(result);
  1045. end;
  1046. result:=-1;
  1047. end;
  1048. Function TStrings.IndexOfObject(AObject: TObject): Integer;
  1049. begin
  1050. Result:=0;
  1051. While (Result<count) and (Objects[Result]<>AObject) do Result:=Result+1;
  1052. If Result=Count then Result:=-1;
  1053. end;
  1054. Procedure TStrings.InsertObject(Index: Integer; const S: string;
  1055. AObject: TObject);
  1056. begin
  1057. BeginUpdate;
  1058. try
  1059. Insert (Index,S);
  1060. Objects[Index]:=AObject;
  1061. finally
  1062. EndUpdate;
  1063. end;
  1064. end;
  1065. function TStrings.LastIndexOf(const S: string): Integer;
  1066. begin
  1067. Result:=LastIndexOf(S,Count-1);
  1068. end;
  1069. function TStrings.LastIndexOf(const S: string; aStart : Integer): Integer;
  1070. begin
  1071. if aStart<0 then
  1072. begin
  1073. aStart:=Count+aStart;
  1074. if aStart<0 then
  1075. aStart:=0;
  1076. end;
  1077. Result:=aStart;
  1078. if Result>=Count-1 then
  1079. Result:=Count-1;
  1080. While (Result>=0) and (DoCompareText(Strings[Result],S)<>0) do
  1081. Result:=Result-1;
  1082. end;
  1083. Procedure TStrings.LoadFromFile(const FileName: string);
  1084. begin
  1085. LoadFromFile(FileName,False)
  1086. end;
  1087. Procedure TStrings.LoadFromFile(const FileName: string; IgnoreEncoding : Boolean);
  1088. Var
  1089. TheStream : TFileStream;
  1090. begin
  1091. TheStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
  1092. try
  1093. LoadFromStream(TheStream, IgnoreEncoding);
  1094. finally
  1095. TheStream.Free;
  1096. end;
  1097. end;
  1098. Procedure TStrings.LoadFromFile(const FileName: string; AEncoding: TEncoding);
  1099. Var
  1100. TheStream : TFileStream;
  1101. begin
  1102. TheStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
  1103. try
  1104. LoadFromStream(TheStream,AEncoding);
  1105. finally
  1106. TheStream.Free;
  1107. end;
  1108. end;
  1109. Procedure TStrings.LoadFromStream(Stream: TStream);
  1110. begin
  1111. LoadFromStream(Stream,False);
  1112. end;
  1113. Const
  1114. LoadBufSize = 1024;
  1115. LoadMaxGrow = MaxInt Div 2;
  1116. Procedure TStrings.LoadFromStream(Stream: TStream; IgnoreEncoding : Boolean);
  1117. {
  1118. Borlands method is no good, since a pipe for
  1119. instance doesn't have a size.
  1120. So we must do it the hard way.
  1121. }
  1122. Var
  1123. Buffer : AnsiString;
  1124. BufLen : SizeInt;
  1125. BytesRead, I, BufDelta : Longint;
  1126. begin
  1127. if not IgnoreEncoding then
  1128. begin
  1129. LoadFromStream(Stream,Nil);
  1130. Exit;
  1131. end;
  1132. // reread into a buffer
  1133. beginupdate;
  1134. try
  1135. Buffer:='';
  1136. BufLen:=0;
  1137. I:=1;
  1138. Repeat
  1139. BufDelta:=LoadBufSize*I;
  1140. SetLength(Buffer,BufLen+BufDelta);
  1141. BytesRead:=Stream.Read(Buffer[BufLen+1],BufDelta);
  1142. inc(BufLen,BufDelta);
  1143. If I<LoadMaxGrow then
  1144. I:=I shl 1;
  1145. Until BytesRead<>BufDelta;
  1146. SetLength(Buffer, BufLen-BufDelta+BytesRead);
  1147. SetTextStr(Buffer);
  1148. SetLength(Buffer,0);
  1149. finally
  1150. EndUpdate;
  1151. end;
  1152. if soPreserveBOM in FOptions then
  1153. WriteBOM:=False;
  1154. end;
  1155. Procedure TStrings.LoadFromStream(Stream: TStream; AEncoding: TEncoding);
  1156. {
  1157. Borlands method is no good, since a pipe for
  1158. instance doesn't have a size.
  1159. So we must do it the hard way.
  1160. }
  1161. Var
  1162. Buffer : TBytes;
  1163. T : string;
  1164. BufLen : SizeInt;
  1165. BytesRead, I, BufDelta, PreambleLength : Longint;
  1166. begin
  1167. // reread into a buffer
  1168. beginupdate;
  1169. try
  1170. SetLength(Buffer,0);
  1171. BufLen:=0;
  1172. I:=1;
  1173. Repeat
  1174. BufDelta:=LoadBufSize*I;
  1175. SetLength(Buffer,BufLen+BufDelta);
  1176. BytesRead:=Stream.Read(Buffer[BufLen],BufDelta);
  1177. inc(BufLen,BufDelta);
  1178. If I<LoadMaxGrow then
  1179. I:=I shl 1;
  1180. Until BytesRead<>BufDelta;
  1181. SetLength(Buffer,BufLen-BufDelta+BytesRead);
  1182. PreambleLength:=TEncoding.GetBufferEncoding(Buffer,AEncoding,FDefaultEncoding);
  1183. T:=AEncoding.GetAnsiString(Buffer,PreambleLength,Length(Buffer)-PreambleLength);
  1184. if soPreserveBOM in FOptions then
  1185. WriteBOM:=PreambleLength>0;
  1186. SetEncoding(AEncoding);
  1187. SetLength(Buffer,0);
  1188. SetTextStr(T);
  1189. finally
  1190. EndUpdate;
  1191. end;
  1192. end;
  1193. Procedure TStrings.Move(CurIndex, NewIndex: Integer);
  1194. Var
  1195. Obj : TObject;
  1196. Str : String;
  1197. begin
  1198. if (CurIndex=NewIndex) then
  1199. Exit;
  1200. BeginUpdate;
  1201. Try
  1202. Obj:=Objects[CurIndex];
  1203. Str:=Strings[CurIndex];
  1204. Objects[CurIndex]:=Nil; // Prevent Delete from freeing.
  1205. Delete(Curindex);
  1206. InsertObject(NewIndex,Str,Obj);
  1207. finally
  1208. EndUpdate;
  1209. end;
  1210. end;
  1211. function TStrings.Pop: string;
  1212. var
  1213. C : Integer;
  1214. begin
  1215. Result:='';
  1216. C:=Count-1;
  1217. if (C>=0) then
  1218. begin
  1219. Result:=Strings[C];
  1220. Delete(C);
  1221. end;
  1222. end;
  1223. function TStrings.Shift: String;
  1224. begin
  1225. Result:='';
  1226. if (Count > 0) then
  1227. begin
  1228. Result:=Strings[0];
  1229. Delete(0);
  1230. end;
  1231. end;
  1232. Procedure TStrings.SaveToFile(const FileName: string);
  1233. Var TheStream : TFileStream;
  1234. begin
  1235. TheStream:=TFileStream.Create(FileName,fmCreate);
  1236. try
  1237. SaveToStream(TheStream);
  1238. finally
  1239. TheStream.Free;
  1240. end;
  1241. end;
  1242. Procedure TStrings.SaveToFile(const FileName: string; IgnoreEncoding : Boolean);
  1243. Var TheStream : TFileStream;
  1244. begin
  1245. TheStream:=TFileStream.Create(FileName,fmCreate);
  1246. try
  1247. SaveToStream(TheStream, IgnoreEncoding);
  1248. finally
  1249. TheStream.Free;
  1250. end;
  1251. end;
  1252. Procedure TStrings.SaveToFile(const FileName: string; AEncoding: TEncoding);
  1253. Var TheStream : TFileStream;
  1254. begin
  1255. TheStream:=TFileStream.Create(FileName,fmCreate);
  1256. try
  1257. SaveToStream(TheStream,AEncoding);
  1258. finally
  1259. TheStream.Free;
  1260. end;
  1261. end;
  1262. Procedure TStrings.SaveToStream(Stream: TStream);
  1263. begin
  1264. SaveToStream(Stream,False)
  1265. end;
  1266. Procedure TStrings.SaveToStream(Stream: TStream; IgnoreEncoding: Boolean);
  1267. Var
  1268. I,L,NLS : SizeInt;
  1269. S,NL : String;
  1270. begin
  1271. if not IgnoreEncoding then
  1272. begin
  1273. SaveToStream(Stream,FEncoding);
  1274. Exit;
  1275. end;
  1276. NL:=GetLineBreakCharLBS;
  1277. NLS:=Length(NL)*SizeOf(Char);
  1278. For i:=0 To count-1 do
  1279. begin
  1280. S:=Strings[I];
  1281. L:=Length(S);
  1282. if L<>0 then
  1283. Stream.WriteBuffer(S[1], L*SizeOf(Char));
  1284. if (I<Count-1) or Not SkipLastLineBreak then
  1285. Stream.WriteBuffer(NL[1], NLS);
  1286. end;
  1287. end;
  1288. Procedure TStrings.SaveToStream(Stream: TStream; AEncoding: TEncoding);
  1289. Var B,BNL : TBytes;
  1290. NL,S: string;
  1291. i,BNLS: SizeInt;
  1292. begin
  1293. if AEncoding=nil then
  1294. AEncoding:=FDefaultEncoding;
  1295. if WriteBOM then
  1296. begin
  1297. B:=AEncoding.GetPreamble;
  1298. if Length(B)>0 then
  1299. Stream.WriteBuffer(B[0],Length(B));
  1300. end;
  1301. NL := GetLineBreakCharLBS;
  1302. {$if sizeof(char)=1}
  1303. BNL:=AEncoding.GetAnsiBytes(NL);
  1304. {$else}
  1305. BNL:=AEncoding.GetBytes(NL);
  1306. {$endif}
  1307. BNLS:=Length(BNL);
  1308. For i:=0 To count-1 do
  1309. begin
  1310. S:=Strings[I];
  1311. if S<>'' then
  1312. begin
  1313. {$if sizeof(char)=1}
  1314. B:=AEncoding.GetAnsiBytes(S);
  1315. {$else}
  1316. B:=AEncoding.GetBytes(S);
  1317. {$endif}
  1318. Stream.WriteBuffer(B[0],Length(B));
  1319. end;
  1320. if (I<Count-1) or Not SkipLastLineBreak then
  1321. Stream.WriteBuffer(BNL[0],BNLS);
  1322. end;
  1323. end;
  1324. Procedure TStrings.SetText(TheText: PChar);
  1325. Var S : String;
  1326. begin
  1327. If TheText<>Nil then
  1328. S:=StrPas(TheText)
  1329. else
  1330. S:='';
  1331. SetTextStr(S);
  1332. end;
  1333. {****************************************************************************}
  1334. {* TStringList *}
  1335. {****************************************************************************}
  1336. {$if not defined(FPC_TESTGENERICS)}
  1337. procedure TStringList.ExchangeItemsInt(Index1, Index2: Integer);
  1338. Var P1,P2 : Pointer;
  1339. begin
  1340. P1:=Pointer(Flist^[Index1].FString);
  1341. P2:=Pointer(Flist^[Index1].FObject);
  1342. Pointer(Flist^[Index1].Fstring):=Pointer(Flist^[Index2].Fstring);
  1343. Pointer(Flist^[Index1].FObject):=Pointer(Flist^[Index2].FObject);
  1344. Pointer(Flist^[Index2].Fstring):=P1;
  1345. Pointer(Flist^[Index2].FObject):=P2;
  1346. end;
  1347. function TStringList.GetSorted: Boolean;
  1348. begin
  1349. Result:=FSortStyle in [sslUser,sslAuto];
  1350. end;
  1351. procedure TStringList.ExchangeItems(Index1, Index2: Integer);
  1352. begin
  1353. ExchangeItemsInt(Index1, Index2);
  1354. end;
  1355. procedure TStringList.Grow;
  1356. Var
  1357. NC : Integer;
  1358. begin
  1359. NC:=FCapacity;
  1360. If NC>=256 then
  1361. NC:=NC+(NC Div 4)
  1362. else if NC=0 then
  1363. NC:=4
  1364. else
  1365. NC:=NC*4;
  1366. SetCapacity(NC);
  1367. end;
  1368. procedure TStringList.InternalClear(FromIndex: Integer; ClearOnly: Boolean);
  1369. Var
  1370. I: Integer;
  1371. begin
  1372. if FromIndex < FCount then
  1373. begin
  1374. if FOwnsObjects then
  1375. begin
  1376. For I:=FromIndex to FCount-1 do
  1377. begin
  1378. Flist^[I].FString:='';
  1379. freeandnil(Flist^[i].FObject);
  1380. end;
  1381. end
  1382. else
  1383. begin
  1384. For I:=FromIndex to FCount-1 do
  1385. Flist^[I].FString:='';
  1386. end;
  1387. FCount:=FromIndex;
  1388. end;
  1389. if Not ClearOnly then
  1390. SetCapacity(0);
  1391. end;
  1392. procedure TStringList.InsertItem(Index: Integer; const S: string);
  1393. begin
  1394. InsertItem(Index, S, nil);
  1395. end;
  1396. procedure TStringList.InsertItem(Index: Integer; const S: string; O: TObject);
  1397. begin
  1398. Changing;
  1399. If FCount=Fcapacity then Grow;
  1400. If Index<FCount then
  1401. System.Move (FList^[Index],FList^[Index+1],
  1402. (FCount-Index)*SizeOf(TStringItem));
  1403. Pointer(Flist^[Index].Fstring):=Nil; // Needed to initialize...
  1404. Flist^[Index].FString:=S;
  1405. Flist^[Index].FObject:=O;
  1406. Inc(FCount);
  1407. Changed;
  1408. end;
  1409. procedure TStringList.SetSorted(Value: Boolean);
  1410. begin
  1411. If Value then
  1412. SortStyle:=sslAuto
  1413. else
  1414. SortStyle:=sslNone
  1415. end;
  1416. procedure TStringList.Changed;
  1417. begin
  1418. If (FUpdateCount=0) Then
  1419. begin
  1420. If Assigned(FOnChange) then
  1421. FOnchange(Self);
  1422. FPONotifyObservers(Self,ooChange,Nil);
  1423. end;
  1424. end;
  1425. procedure TStringList.Changing;
  1426. begin
  1427. If FUpdateCount=0 then
  1428. if Assigned(FOnChanging) then
  1429. FOnchanging(Self);
  1430. end;
  1431. function TStringList.Get(Index: Integer): string;
  1432. begin
  1433. CheckIndex(Index);
  1434. Result:=Flist^[Index].FString;
  1435. end;
  1436. function TStringList.GetCapacity: Integer;
  1437. begin
  1438. Result:=FCapacity;
  1439. end;
  1440. function TStringList.GetCount: Integer;
  1441. begin
  1442. Result:=FCount;
  1443. end;
  1444. function TStringList.GetObject(Index: Integer): TObject;
  1445. begin
  1446. CheckIndex(Index);
  1447. Result:=Flist^[Index].FObject;
  1448. end;
  1449. procedure TStringList.Put(Index: Integer; const S: string);
  1450. begin
  1451. If Sorted then
  1452. Error(SSortedListError,0);
  1453. CheckIndex(Index);
  1454. Changing;
  1455. Flist^[Index].FString:=S;
  1456. Changed;
  1457. end;
  1458. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1459. begin
  1460. CheckIndex(Index);
  1461. Changing;
  1462. Flist^[Index].FObject:=AObject;
  1463. Changed;
  1464. end;
  1465. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1466. Var NewList : Pointer;
  1467. MSize : Longint;
  1468. begin
  1469. If (NewCapacity<0) then
  1470. Error (SListCapacityError,NewCapacity);
  1471. If NewCapacity>FCapacity then
  1472. begin
  1473. GetMem (NewList,NewCapacity*SizeOf(TStringItem));
  1474. If NewList=Nil then
  1475. Error (SListCapacityError,NewCapacity);
  1476. If Assigned(FList) then
  1477. begin
  1478. MSize:=FCapacity*Sizeof(TStringItem);
  1479. System.Move (FList^,NewList^,MSize);
  1480. FillWord (PAnsiChar(NewList)[MSize],(NewCapacity-FCapacity)*(SizeOf(TStringItem) div SizeOf(Word)), 0);
  1481. FreeMem (Flist,MSize);
  1482. end;
  1483. Flist:=NewList;
  1484. FCapacity:=NewCapacity;
  1485. end
  1486. else if NewCapacity<FCapacity then
  1487. begin
  1488. if NewCapacity = 0 then
  1489. begin
  1490. if FCount > 0 then
  1491. InternalClear(0,True);
  1492. FreeMem(FList);
  1493. FList := nil;
  1494. end else
  1495. begin
  1496. InternalClear(NewCapacity,True);
  1497. GetMem(NewList, NewCapacity * SizeOf(TStringItem));
  1498. System.Move(FList^, NewList^, NewCapacity * SizeOf(TStringItem));
  1499. FreeMem(FList);
  1500. FList := NewList;
  1501. end;
  1502. FCapacity:=NewCapacity;
  1503. end;
  1504. end;
  1505. procedure TStringList.SetUpdateState(Updating: Boolean);
  1506. begin
  1507. If Updating then
  1508. Changing
  1509. else
  1510. Changed
  1511. end;
  1512. Constructor TStringList.Create;
  1513. begin
  1514. inherited Create;
  1515. end;
  1516. Constructor TStringList.Create(anOwnsObjects : Boolean);
  1517. begin
  1518. inherited Create;
  1519. FOwnsObjects:=anOwnsObjects;
  1520. end;
  1521. destructor TStringList.Destroy;
  1522. begin
  1523. InternalClear;
  1524. Inherited destroy;
  1525. end;
  1526. function TStringList.Add(const S: string): Integer;
  1527. begin
  1528. If (SortStyle<>sslAuto) then
  1529. Result:=FCount
  1530. else
  1531. If Find (S,Result) then
  1532. Case DUplicates of
  1533. DupIgnore : Exit;
  1534. DupError : Error(SDuplicateString,0)
  1535. end;
  1536. InsertItem (Result,S);
  1537. end;
  1538. procedure TStringList.Clear;
  1539. begin
  1540. if FCount = 0 then Exit;
  1541. Changing;
  1542. InternalClear;
  1543. Changed;
  1544. end;
  1545. procedure TStringList.Delete(Index: Integer);
  1546. begin
  1547. CheckIndex(Index);
  1548. Changing;
  1549. Flist^[Index].FString:='';
  1550. if FOwnsObjects then
  1551. FreeAndNil(Flist^[Index].FObject);
  1552. Dec(FCount);
  1553. If Index<FCount then
  1554. System.Move(Flist^[Index+1],
  1555. Flist^[Index],
  1556. (Fcount-Index)*SizeOf(TStringItem));
  1557. Changed;
  1558. end;
  1559. procedure TStringList.Exchange(Index1, Index2: Integer);
  1560. begin
  1561. CheckIndex(Index1);
  1562. CheckIndex(Index2);
  1563. Changing;
  1564. ExchangeItemsInt(Index1,Index2);
  1565. changed;
  1566. end;
  1567. procedure TStringList.SetCaseSensitive(b : boolean);
  1568. begin
  1569. if b=FCaseSensitive then
  1570. Exit;
  1571. FCaseSensitive:=b;
  1572. if FSortStyle=sslAuto then
  1573. begin
  1574. FForceSort:=True;
  1575. try
  1576. Sort;
  1577. finally
  1578. FForceSort:=False;
  1579. end;
  1580. end;
  1581. end;
  1582. procedure TStringList.SetSortStyle(AValue: TStringsSortStyle);
  1583. begin
  1584. if FSortStyle=AValue then Exit;
  1585. if (AValue=sslAuto) then
  1586. Sort;
  1587. FSortStyle:=AValue;
  1588. end;
  1589. procedure TStringList.CheckIndex(AIndex: Integer);
  1590. begin
  1591. If (AIndex<0) or (AIndex>=FCount) then
  1592. Error(SListIndexError,AIndex);
  1593. end;
  1594. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1595. begin
  1596. if FCaseSensitive then
  1597. begin
  1598. if UseLocale then
  1599. result:=AnsiCompareStr(s1,s2)
  1600. else
  1601. result:=CompareStr(s1,s2);
  1602. end else
  1603. begin
  1604. if UseLocale then
  1605. result:=AnsiCompareText(s1,s2)
  1606. else
  1607. result:=CompareText(s1,s2);
  1608. end;
  1609. end;
  1610. function TStringList.Find(const S: string; out Index: Integer): Boolean;
  1611. var
  1612. L, R, I: Integer;
  1613. CompareRes: PtrInt;
  1614. begin
  1615. Result := false;
  1616. Index:=-1;
  1617. if Not Sorted then
  1618. Raise EListError.Create(SErrFindNeedsSortedList);
  1619. // Use binary search.
  1620. L := 0;
  1621. R := Count - 1;
  1622. while (L<=R) do
  1623. begin
  1624. I := L + (R - L) div 2;
  1625. CompareRes := DoCompareText(S, Flist^[I].FString);
  1626. if (CompareRes>0) then
  1627. L := I+1
  1628. else begin
  1629. R := I-1;
  1630. if (CompareRes=0) then begin
  1631. Result := true;
  1632. if (Duplicates<>dupAccept) then
  1633. L := I; // forces end of while loop
  1634. end;
  1635. end;
  1636. end;
  1637. Index := L;
  1638. end;
  1639. function TStringList.IndexOf(const S: string): Integer;
  1640. begin
  1641. If Not Sorted then
  1642. Result:=Inherited indexOf(S)
  1643. else
  1644. // faster using binary search...
  1645. If Not Find (S,Result) then
  1646. Result:=-1;
  1647. end;
  1648. procedure TStringList.Insert(Index: Integer; const S: string);
  1649. begin
  1650. If SortStyle=sslAuto then
  1651. Error (SSortedListError,0)
  1652. else
  1653. begin
  1654. If (Index<0) or (Index>FCount) then
  1655. Error(SListIndexError,Index); // Cannot use CheckIndex, because there >= FCount...
  1656. InsertItem (Index,S);
  1657. end;
  1658. end;
  1659. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1660. begin
  1661. CustomSort(CompareFn, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SortBase.DefaultSortingAlgorithm);
  1662. end;
  1663. type
  1664. PStringList_CustomSort_Context = ^TStringList_CustomSort_Context;
  1665. TStringList_CustomSort_Context = record
  1666. List: TStringList;
  1667. ListStartPtr: Pointer;
  1668. CompareFn: TStringListSortCompare;
  1669. end;
  1670. function TStringList_CustomSort_Comparer(Item1, Item2, Context: Pointer): Integer;
  1671. begin
  1672. with PStringList_CustomSort_Context(Context)^ do
  1673. Result := CompareFn(List,
  1674. (Item1 - ListStartPtr) div SizeOf(TStringItem),
  1675. (Item2 - ListStartPtr) div SizeOf(TStringItem));
  1676. end;
  1677. procedure TStringList_CustomSort_Exchanger(Item1, Item2, Context: Pointer);
  1678. begin
  1679. with PStringList_CustomSort_Context(Context)^ do
  1680. List.ExchangeItems((Item1 - ListStartPtr) div SizeOf(TStringItem),
  1681. (Item2 - ListStartPtr) div SizeOf(TStringItem));
  1682. end;
  1683. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare; SortingAlgorithm: PSortingAlgorithm);
  1684. var
  1685. Context: TStringList_CustomSort_Context;
  1686. begin
  1687. If (FCount>1) and (FForceSort or (FSortStyle<>sslAuto)) then
  1688. begin
  1689. Changing;
  1690. Context.List := Self;
  1691. Context.ListStartPtr := FList;
  1692. Context.CompareFn := CompareFn;
  1693. //if ExchangeItems is overriden call that, else call (faster) ItemListSorter_ContextComparer
  1694. if TMethod(@Self.ExchangeItems).Code = CodePointer(@TStringList.ExchangeItems) then
  1695. SortingAlgorithm^.ItemListSorter_ContextComparer(
  1696. FList, FCount, SizeOf(TStringItem), @TStringList_CustomSort_Comparer,
  1697. @Context)
  1698. else
  1699. SortingAlgorithm^.ItemListSorter_CustomItemExchanger_ContextComparer(
  1700. FList, FCount, SizeOf(TStringItem), @TStringList_CustomSort_Comparer,
  1701. @TStringList_CustomSort_Exchanger, @Context);
  1702. Changed;
  1703. end;
  1704. end;
  1705. function StringListAnsiCompare(List: TStringList; Index1, Index: Integer): Integer;
  1706. begin
  1707. Result := List.DoCompareText(List.FList^[Index1].FString,
  1708. List.FList^[Index].FString);
  1709. end;
  1710. procedure TStringList.Sort;
  1711. begin
  1712. CustomSort(@StringListAnsiCompare);
  1713. end;
  1714. procedure TStringList.Sort(SortingAlgorithm: PSortingAlgorithm);
  1715. begin
  1716. CustomSort(@StringListAnsiCompare, SortingAlgorithm);
  1717. end;
  1718. {$else}
  1719. { generics based implementation of TStringList follows }
  1720. function StringListAnsiCompare(List: TStringList; Index1, Index2: Integer): Integer;
  1721. begin
  1722. Result := List.DoCompareText(List.Strings[Index1], List.Strings[Index2]);
  1723. end;
  1724. constructor TStringList.Create;
  1725. begin
  1726. inherited;
  1727. FOwnsObjects:=false;
  1728. FMap := TFPStrObjMap.Create;
  1729. FMap.OnPtrCompare := @MapPtrCompare;
  1730. FOnCompareText := @DefaultCompareText;
  1731. NameValueSeparator:='=';
  1732. CheckSpecialChars;
  1733. end;
  1734. destructor TStringList.Destroy;
  1735. begin
  1736. FMap.Free;
  1737. inherited;
  1738. end;
  1739. function TStringList.GetDuplicates: TDuplicates;
  1740. begin
  1741. Result := FMap.Duplicates;
  1742. end;
  1743. function TStringList.GetSorted: boolean;
  1744. begin
  1745. Result := FMap.Sorted;
  1746. end;
  1747. procedure TStringList.SetDuplicates(NewDuplicates: TDuplicates);
  1748. begin
  1749. FMap.Duplicates := NewDuplicates;
  1750. end;
  1751. procedure TStringList.SetSorted(NewSorted: Boolean);
  1752. begin
  1753. FMap.Sorted := NewSorted;
  1754. end;
  1755. procedure TStringList.Changed;
  1756. begin
  1757. if FUpdateCount = 0 then
  1758. if Assigned(FOnChange) then
  1759. FOnChange(Self);
  1760. end;
  1761. procedure TStringList.Changing;
  1762. begin
  1763. if FUpdateCount = 0 then
  1764. if Assigned(FOnChanging) then
  1765. FOnChanging(Self);
  1766. end;
  1767. function TStringList.Get(Index: Integer): string;
  1768. begin
  1769. Result := FMap.Keys[Index];
  1770. end;
  1771. function TStringList.GetCapacity: Integer;
  1772. begin
  1773. Result := FMap.Capacity;
  1774. end;
  1775. function TStringList.GetCount: Integer;
  1776. begin
  1777. Result := FMap.Count;
  1778. end;
  1779. function TStringList.GetObject(Index: Integer): TObject;
  1780. begin
  1781. Result := FMap.Data[Index];
  1782. end;
  1783. procedure TStringList.Put(Index: Integer; const S: string);
  1784. begin
  1785. Changing;
  1786. FMap.Keys[Index] := S;
  1787. Changed;
  1788. end;
  1789. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1790. begin
  1791. Changing;
  1792. FMap.Data[Index] := AObject;
  1793. Changed;
  1794. end;
  1795. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1796. begin
  1797. FMap.Capacity := NewCapacity;
  1798. end;
  1799. procedure TStringList.SetUpdateState(Updating: Boolean);
  1800. begin
  1801. if Updating then
  1802. Changing
  1803. else
  1804. Changed
  1805. end;
  1806. function TStringList.Add(const S: string): Integer;
  1807. begin
  1808. Result := FMap.Add(S);
  1809. end;
  1810. procedure TStringList.Clear;
  1811. begin
  1812. if FMap.Count = 0 then exit;
  1813. Changing;
  1814. FMap.Clear;
  1815. Changed;
  1816. end;
  1817. procedure TStringList.Delete(Index: Integer);
  1818. begin
  1819. if (Index < 0) or (Index >= FMap.Count) then
  1820. Error(SListIndexError, Index);
  1821. Changing;
  1822. FMap.Delete(Index);
  1823. Changed;
  1824. end;
  1825. procedure TStringList.Exchange(Index1, Index2: Integer);
  1826. begin
  1827. if (Index1 < 0) or (Index1 >= FMap.Count) then
  1828. Error(SListIndexError, Index1);
  1829. if (Index2 < 0) or (Index2 >= FMap.Count) then
  1830. Error(SListIndexError, Index2);
  1831. Changing;
  1832. FMap.InternalExchange(Index1, Index2);
  1833. Changed;
  1834. end;
  1835. procedure TStringList.SetCaseSensitive(NewSensitive: Boolean);
  1836. begin
  1837. if NewSensitive <> FCaseSensitive then
  1838. begin
  1839. FCaseSensitive := NewSensitive;
  1840. if Sorted then
  1841. Sort;
  1842. end;
  1843. end;
  1844. function TStringList.MapPtrCompare(Key1, Key2: Pointer): Integer;
  1845. begin
  1846. Result := FOnCompareText(string(Key1^), string(Key2^));
  1847. end;
  1848. function TStringList.DefaultCompareText(const s1, s2: string): PtrInt;
  1849. begin
  1850. if FCaseSensitive then
  1851. Result := AnsiCompareStr(s1, s2)
  1852. else
  1853. Result := AnsiCompareText(s1, s2);
  1854. end;
  1855. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1856. begin
  1857. Result := FOnCompareText(s1, s2);
  1858. end;
  1859. function TStringList.Find(const S: string; var Index: Integer): Boolean;
  1860. begin
  1861. Result := FMap.Find(S, Index);
  1862. end;
  1863. function TStringList.IndexOf(const S: string): Integer;
  1864. begin
  1865. Result := FMap.IndexOf(S);
  1866. end;
  1867. procedure TStringList.Insert(Index: Integer; const S: string);
  1868. begin
  1869. if not Sorted and (0 <= Index) and (Index < FMap.Count) then
  1870. Changing;
  1871. FMap.InsertKey(Index, S);
  1872. Changed;
  1873. end;
  1874. type
  1875. PStringList_CustomSort_Context = ^TStringList_CustomSort_Context;
  1876. TStringList_CustomSort_Context = record
  1877. List: TStringList;
  1878. ListStartPtr: Pointer;
  1879. ItemSize: SizeUInt;
  1880. IndexBase: Integer;
  1881. CompareFn: TStringListSortCompare;
  1882. end;
  1883. function TStringList_CustomSort_Comparer(Item1, Item2, Context: Pointer): Integer;
  1884. begin
  1885. with PStringList_CustomSort_Context(Context)^ do
  1886. Result := CompareFn(List,
  1887. ((Item1 - ListStartPtr) div ItemSize) + IndexBase,
  1888. ((Item2 - ListStartPtr) div ItemSize) + IndexBase);
  1889. end;
  1890. procedure TStringList_CustomSort_Exchanger(Item1, Item2, Context: Pointer);
  1891. begin
  1892. with PStringList_CustomSort_Context(Context)^ do
  1893. List.Exchange(((Item1 - ListStartPtr) div ItemSize) + IndexBase,
  1894. ((Item2 - ListStartPtr) div ItemSize) + IndexBase);
  1895. end;
  1896. procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  1897. var
  1898. Context: TStringList_CustomSort_Context;
  1899. begin
  1900. if L > R then
  1901. exit;
  1902. Context.List := Self;
  1903. Context.ListStartPtr := FMap.Items[L];
  1904. Context.CompareFn := CompareFn;
  1905. Context.ItemSize := FMap.KeySize + FMap.DataSize;
  1906. Context.IndexBase := L;
  1907. DefaultSortingAlgorithm^.ItemListSorter_CustomItemExchanger_ContextComparer(
  1908. Context.ListStartPtr, R - L + 1, Context.ItemSize, @TStringList_CustomSort_Comparer,
  1909. @TStringList_CustomSort_Exchanger, @Context);
  1910. end;
  1911. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1912. begin
  1913. if not Sorted and (FMap.Count > 1) then
  1914. begin
  1915. Changing;
  1916. QuickSort(0, FMap.Count-1, CompareFn);
  1917. Changed;
  1918. end;
  1919. end;
  1920. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare; SortingAlgorithm: PSortingAlgorithm);
  1921. var
  1922. Context: TStringList_CustomSort_Context;
  1923. begin
  1924. if not Sorted and (FMap.Count > 1) then
  1925. begin
  1926. Changing;
  1927. Context.List := Self;
  1928. Context.ListStartPtr := FMap.Items[0];
  1929. Context.CompareFn := CompareFn;
  1930. Context.ItemSize := FMap.KeySize + FMap.DataSize;
  1931. Context.IndexBase := 0;
  1932. SortingAlgorithm^.ItemListSorter_CustomItemExchanger_ContextComparer(
  1933. Context.ListStartPtr, FMap.Count, Context.ItemSize, @TStringList_CustomSort_Comparer,
  1934. @TStringList_CustomSort_Exchanger, @Context);
  1935. Changed;
  1936. end;
  1937. end;
  1938. procedure TStringList.Sort;
  1939. begin
  1940. if not Sorted and (FMap.Count > 1) then
  1941. begin
  1942. Changing;
  1943. FMap.Sort;
  1944. Changed;
  1945. end;
  1946. end;
  1947. procedure TStringList.Sort(SortingAlgorithm: PSortingAlgorithm);
  1948. begin
  1949. if not Sorted and (FMap.Count > 1) then
  1950. begin
  1951. Changing;
  1952. FMap.Sort(SortingAlgorithm);
  1953. Changed;
  1954. end;
  1955. end;
  1956. {$endif}