stringl.inc 48 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430
  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 : PAnsiChar;
  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);
  635. P:=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, @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, @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, @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. BNL:=AEncoding.GetAnsiBytes(NL);
  1285. BNLS:=Length(BNL);
  1286. For i:=0 To count-1 do
  1287. begin
  1288. S:=Strings[I];
  1289. if S<>'' then
  1290. begin
  1291. B:=AEncoding.GetAnsiBytes(S);
  1292. Stream.WriteBuffer(B[0],Length(B));
  1293. end;
  1294. if (I<Count-1) or Not SkipLastLineBreak then
  1295. Stream.WriteBuffer(BNL[0],BNLS);
  1296. end;
  1297. end;
  1298. Procedure TStrings.SetText(TheText: PChar);
  1299. Var S : String;
  1300. begin
  1301. If TheText<>Nil then
  1302. S:=StrPas(TheText)
  1303. else
  1304. S:='';
  1305. SetTextStr(S);
  1306. end;
  1307. {****************************************************************************}
  1308. {* TStringList *}
  1309. {****************************************************************************}
  1310. {$if not defined(FPC_TESTGENERICS)}
  1311. procedure TStringList.ExchangeItemsInt(Index1, Index2: Integer);
  1312. Var P1,P2 : Pointer;
  1313. begin
  1314. P1:=Pointer(Flist^[Index1].FString);
  1315. P2:=Pointer(Flist^[Index1].FObject);
  1316. Pointer(Flist^[Index1].Fstring):=Pointer(Flist^[Index2].Fstring);
  1317. Pointer(Flist^[Index1].FObject):=Pointer(Flist^[Index2].FObject);
  1318. Pointer(Flist^[Index2].Fstring):=P1;
  1319. Pointer(Flist^[Index2].FObject):=P2;
  1320. end;
  1321. function TStringList.GetSorted: Boolean;
  1322. begin
  1323. Result:=FSortStyle in [sslUser,sslAuto];
  1324. end;
  1325. procedure TStringList.ExchangeItems(Index1, Index2: Integer);
  1326. begin
  1327. ExchangeItemsInt(Index1, Index2);
  1328. end;
  1329. procedure TStringList.Grow;
  1330. Var
  1331. NC : Integer;
  1332. begin
  1333. NC:=FCapacity;
  1334. If NC>=256 then
  1335. NC:=NC+(NC Div 4)
  1336. else if NC=0 then
  1337. NC:=4
  1338. else
  1339. NC:=NC*4;
  1340. SetCapacity(NC);
  1341. end;
  1342. procedure TStringList.InternalClear(FromIndex: Integer; ClearOnly: Boolean);
  1343. Var
  1344. I: Integer;
  1345. begin
  1346. if FromIndex < FCount then
  1347. begin
  1348. if FOwnsObjects then
  1349. begin
  1350. For I:=FromIndex to FCount-1 do
  1351. begin
  1352. Flist^[I].FString:='';
  1353. freeandnil(Flist^[i].FObject);
  1354. end;
  1355. end
  1356. else
  1357. begin
  1358. For I:=FromIndex to FCount-1 do
  1359. Flist^[I].FString:='';
  1360. end;
  1361. FCount:=FromIndex;
  1362. end;
  1363. if Not ClearOnly then
  1364. SetCapacity(0);
  1365. end;
  1366. procedure TStringList.InsertItem(Index: Integer; const S: string);
  1367. begin
  1368. InsertItem(Index, S, nil);
  1369. end;
  1370. procedure TStringList.InsertItem(Index: Integer; const S: string; O: TObject);
  1371. begin
  1372. Changing;
  1373. If FCount=Fcapacity then Grow;
  1374. If Index<FCount then
  1375. System.Move (FList^[Index],FList^[Index+1],
  1376. (FCount-Index)*SizeOf(TStringItem));
  1377. Pointer(Flist^[Index].Fstring):=Nil; // Needed to initialize...
  1378. Flist^[Index].FString:=S;
  1379. Flist^[Index].FObject:=O;
  1380. Inc(FCount);
  1381. Changed;
  1382. end;
  1383. procedure TStringList.SetSorted(Value: Boolean);
  1384. begin
  1385. If Value then
  1386. SortStyle:=sslAuto
  1387. else
  1388. SortStyle:=sslNone
  1389. end;
  1390. procedure TStringList.Changed;
  1391. begin
  1392. If (FUpdateCount=0) Then
  1393. begin
  1394. If Assigned(FOnChange) then
  1395. FOnchange(Self);
  1396. FPONotifyObservers(Self,ooChange,Nil);
  1397. end;
  1398. end;
  1399. procedure TStringList.Changing;
  1400. begin
  1401. If FUpdateCount=0 then
  1402. if Assigned(FOnChanging) then
  1403. FOnchanging(Self);
  1404. end;
  1405. function TStringList.Get(Index: Integer): string;
  1406. begin
  1407. CheckIndex(Index);
  1408. Result:=Flist^[Index].FString;
  1409. end;
  1410. function TStringList.GetCapacity: Integer;
  1411. begin
  1412. Result:=FCapacity;
  1413. end;
  1414. function TStringList.GetCount: Integer;
  1415. begin
  1416. Result:=FCount;
  1417. end;
  1418. function TStringList.GetObject(Index: Integer): TObject;
  1419. begin
  1420. CheckIndex(Index);
  1421. Result:=Flist^[Index].FObject;
  1422. end;
  1423. procedure TStringList.Put(Index: Integer; const S: string);
  1424. begin
  1425. If Sorted then
  1426. Error(SSortedListError,0);
  1427. CheckIndex(Index);
  1428. Changing;
  1429. Flist^[Index].FString:=S;
  1430. Changed;
  1431. end;
  1432. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1433. begin
  1434. CheckIndex(Index);
  1435. Changing;
  1436. Flist^[Index].FObject:=AObject;
  1437. Changed;
  1438. end;
  1439. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1440. Var NewList : Pointer;
  1441. MSize : Longint;
  1442. begin
  1443. If (NewCapacity<0) then
  1444. Error (SListCapacityError,NewCapacity);
  1445. If NewCapacity>FCapacity then
  1446. begin
  1447. GetMem (NewList,NewCapacity*SizeOf(TStringItem));
  1448. If NewList=Nil then
  1449. Error (SListCapacityError,NewCapacity);
  1450. If Assigned(FList) then
  1451. begin
  1452. MSize:=FCapacity*Sizeof(TStringItem);
  1453. System.Move (FList^,NewList^,MSize);
  1454. FillWord (PAnsiChar(NewList)[MSize],(NewCapacity-FCapacity)*(SizeOf(TStringItem) div SizeOf(Word)), 0);
  1455. FreeMem (Flist,MSize);
  1456. end;
  1457. Flist:=NewList;
  1458. FCapacity:=NewCapacity;
  1459. end
  1460. else if NewCapacity<FCapacity then
  1461. begin
  1462. if NewCapacity = 0 then
  1463. begin
  1464. if FCount > 0 then
  1465. InternalClear(0,True);
  1466. FreeMem(FList);
  1467. FList := nil;
  1468. end else
  1469. begin
  1470. InternalClear(NewCapacity,True);
  1471. GetMem(NewList, NewCapacity * SizeOf(TStringItem));
  1472. System.Move(FList^, NewList^, NewCapacity * SizeOf(TStringItem));
  1473. FreeMem(FList);
  1474. FList := NewList;
  1475. end;
  1476. FCapacity:=NewCapacity;
  1477. end;
  1478. end;
  1479. procedure TStringList.SetUpdateState(Updating: Boolean);
  1480. begin
  1481. If Updating then
  1482. Changing
  1483. else
  1484. Changed
  1485. end;
  1486. Constructor TStringList.Create;
  1487. begin
  1488. inherited Create;
  1489. end;
  1490. Constructor TStringList.Create(anOwnsObjects : Boolean);
  1491. begin
  1492. inherited Create;
  1493. FOwnsObjects:=anOwnsObjects;
  1494. end;
  1495. destructor TStringList.Destroy;
  1496. begin
  1497. InternalClear;
  1498. Inherited destroy;
  1499. end;
  1500. function TStringList.Add(const S: string): Integer;
  1501. begin
  1502. If (SortStyle<>sslAuto) then
  1503. Result:=FCount
  1504. else
  1505. If Find (S,Result) then
  1506. Case DUplicates of
  1507. DupIgnore : Exit;
  1508. DupError : Error(SDuplicateString,0)
  1509. end;
  1510. InsertItem (Result,S);
  1511. end;
  1512. procedure TStringList.Clear;
  1513. begin
  1514. if FCount = 0 then Exit;
  1515. Changing;
  1516. InternalClear;
  1517. Changed;
  1518. end;
  1519. procedure TStringList.Delete(Index: Integer);
  1520. begin
  1521. CheckIndex(Index);
  1522. Changing;
  1523. Flist^[Index].FString:='';
  1524. if FOwnsObjects then
  1525. FreeAndNil(Flist^[Index].FObject);
  1526. Dec(FCount);
  1527. If Index<FCount then
  1528. System.Move(Flist^[Index+1],
  1529. Flist^[Index],
  1530. (Fcount-Index)*SizeOf(TStringItem));
  1531. Changed;
  1532. end;
  1533. procedure TStringList.Exchange(Index1, Index2: Integer);
  1534. begin
  1535. CheckIndex(Index1);
  1536. CheckIndex(Index2);
  1537. Changing;
  1538. ExchangeItemsInt(Index1,Index2);
  1539. changed;
  1540. end;
  1541. procedure TStringList.SetCaseSensitive(b : boolean);
  1542. begin
  1543. if b=FCaseSensitive then
  1544. Exit;
  1545. FCaseSensitive:=b;
  1546. if FSortStyle=sslAuto then
  1547. begin
  1548. FForceSort:=True;
  1549. try
  1550. Sort;
  1551. finally
  1552. FForceSort:=False;
  1553. end;
  1554. end;
  1555. end;
  1556. procedure TStringList.SetSortStyle(AValue: TStringsSortStyle);
  1557. begin
  1558. if FSortStyle=AValue then Exit;
  1559. if (AValue=sslAuto) then
  1560. Sort;
  1561. FSortStyle:=AValue;
  1562. end;
  1563. procedure TStringList.CheckIndex(AIndex: Integer);
  1564. begin
  1565. If (AIndex<0) or (AIndex>=FCount) then
  1566. Error(SListIndexError,AIndex);
  1567. end;
  1568. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1569. begin
  1570. if FCaseSensitive then
  1571. begin
  1572. if UseLocale then
  1573. result:=AnsiCompareStr(s1,s2)
  1574. else
  1575. result:=CompareStr(s1,s2);
  1576. end else
  1577. begin
  1578. if UseLocale then
  1579. result:=AnsiCompareText(s1,s2)
  1580. else
  1581. result:=CompareText(s1,s2);
  1582. end;
  1583. end;
  1584. function TStringList.Find(const S: string; out Index: Integer): Boolean;
  1585. var
  1586. L, R, I: Integer;
  1587. CompareRes: PtrInt;
  1588. begin
  1589. Result := false;
  1590. Index:=-1;
  1591. if Not Sorted then
  1592. Raise EListError.Create(SErrFindNeedsSortedList);
  1593. // Use binary search.
  1594. L := 0;
  1595. R := Count - 1;
  1596. while (L<=R) do
  1597. begin
  1598. I := L + (R - L) div 2;
  1599. CompareRes := DoCompareText(S, Flist^[I].FString);
  1600. if (CompareRes>0) then
  1601. L := I+1
  1602. else begin
  1603. R := I-1;
  1604. if (CompareRes=0) then begin
  1605. Result := true;
  1606. if (Duplicates<>dupAccept) then
  1607. L := I; // forces end of while loop
  1608. end;
  1609. end;
  1610. end;
  1611. Index := L;
  1612. end;
  1613. function TStringList.IndexOf(const S: string): Integer;
  1614. begin
  1615. If Not Sorted then
  1616. Result:=Inherited indexOf(S)
  1617. else
  1618. // faster using binary search...
  1619. If Not Find (S,Result) then
  1620. Result:=-1;
  1621. end;
  1622. procedure TStringList.Insert(Index: Integer; const S: string);
  1623. begin
  1624. If SortStyle=sslAuto then
  1625. Error (SSortedListError,0)
  1626. else
  1627. begin
  1628. If (Index<0) or (Index>FCount) then
  1629. Error(SListIndexError,Index); // Cannot use CheckIndex, because there >= FCount...
  1630. InsertItem (Index,S);
  1631. end;
  1632. end;
  1633. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1634. begin
  1635. CustomSort(CompareFn, SortBase.DefaultSortingAlgorithm);
  1636. end;
  1637. type
  1638. PStringList_CustomSort_Context = ^TStringList_CustomSort_Context;
  1639. TStringList_CustomSort_Context = record
  1640. List: TStringList;
  1641. ListStartPtr: Pointer;
  1642. CompareFn: TStringListSortCompare;
  1643. end;
  1644. function TStringList_CustomSort_Comparer(Item1, Item2, Context: Pointer): Integer;
  1645. begin
  1646. with PStringList_CustomSort_Context(Context)^ do
  1647. Result := CompareFn(List,
  1648. (Item1 - ListStartPtr) div SizeOf(TStringItem),
  1649. (Item2 - ListStartPtr) div SizeOf(TStringItem));
  1650. end;
  1651. procedure TStringList_CustomSort_Exchanger(Item1, Item2, Context: Pointer);
  1652. begin
  1653. with PStringList_CustomSort_Context(Context)^ do
  1654. List.ExchangeItems((Item1 - ListStartPtr) div SizeOf(TStringItem),
  1655. (Item2 - ListStartPtr) div SizeOf(TStringItem));
  1656. end;
  1657. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare; SortingAlgorithm: PSortingAlgorithm);
  1658. var
  1659. Context: TStringList_CustomSort_Context;
  1660. begin
  1661. If (FCount>1) and (FForceSort or (FSortStyle<>sslAuto)) then
  1662. begin
  1663. Changing;
  1664. Context.List := Self;
  1665. Context.ListStartPtr := FList;
  1666. Context.CompareFn := CompareFn;
  1667. //if ExchangeItems is overriden call that, else call (faster) ItemListSorter_ContextComparer
  1668. if TMethod(@Self.ExchangeItems).Code = CodePointer(@TStringList.ExchangeItems) then
  1669. SortingAlgorithm^.ItemListSorter_ContextComparer(
  1670. FList, FCount, SizeOf(TStringItem), @TStringList_CustomSort_Comparer,
  1671. @Context)
  1672. else
  1673. SortingAlgorithm^.ItemListSorter_CustomItemExchanger_ContextComparer(
  1674. FList, FCount, SizeOf(TStringItem), @TStringList_CustomSort_Comparer,
  1675. @TStringList_CustomSort_Exchanger, @Context);
  1676. Changed;
  1677. end;
  1678. end;
  1679. function StringListAnsiCompare(List: TStringList; Index1, Index: Integer): Integer;
  1680. begin
  1681. Result := List.DoCompareText(List.FList^[Index1].FString,
  1682. List.FList^[Index].FString);
  1683. end;
  1684. procedure TStringList.Sort;
  1685. begin
  1686. CustomSort(@StringListAnsiCompare);
  1687. end;
  1688. procedure TStringList.Sort(SortingAlgorithm: PSortingAlgorithm);
  1689. begin
  1690. CustomSort(@StringListAnsiCompare, SortingAlgorithm);
  1691. end;
  1692. {$else}
  1693. { generics based implementation of TStringList follows }
  1694. function StringListAnsiCompare(List: TStringList; Index1, Index2: Integer): Integer;
  1695. begin
  1696. Result := List.DoCompareText(List.Strings[Index1], List.Strings[Index2]);
  1697. end;
  1698. constructor TStringList.Create;
  1699. begin
  1700. inherited;
  1701. FOwnsObjects:=false;
  1702. FMap := TFPStrObjMap.Create;
  1703. FMap.OnPtrCompare := @MapPtrCompare;
  1704. FOnCompareText := @DefaultCompareText;
  1705. NameValueSeparator:='=';
  1706. CheckSpecialChars;
  1707. end;
  1708. destructor TStringList.Destroy;
  1709. begin
  1710. FMap.Free;
  1711. inherited;
  1712. end;
  1713. function TStringList.GetDuplicates: TDuplicates;
  1714. begin
  1715. Result := FMap.Duplicates;
  1716. end;
  1717. function TStringList.GetSorted: boolean;
  1718. begin
  1719. Result := FMap.Sorted;
  1720. end;
  1721. procedure TStringList.SetDuplicates(NewDuplicates: TDuplicates);
  1722. begin
  1723. FMap.Duplicates := NewDuplicates;
  1724. end;
  1725. procedure TStringList.SetSorted(NewSorted: Boolean);
  1726. begin
  1727. FMap.Sorted := NewSorted;
  1728. end;
  1729. procedure TStringList.Changed;
  1730. begin
  1731. if FUpdateCount = 0 then
  1732. if Assigned(FOnChange) then
  1733. FOnChange(Self);
  1734. end;
  1735. procedure TStringList.Changing;
  1736. begin
  1737. if FUpdateCount = 0 then
  1738. if Assigned(FOnChanging) then
  1739. FOnChanging(Self);
  1740. end;
  1741. function TStringList.Get(Index: Integer): string;
  1742. begin
  1743. Result := FMap.Keys[Index];
  1744. end;
  1745. function TStringList.GetCapacity: Integer;
  1746. begin
  1747. Result := FMap.Capacity;
  1748. end;
  1749. function TStringList.GetCount: Integer;
  1750. begin
  1751. Result := FMap.Count;
  1752. end;
  1753. function TStringList.GetObject(Index: Integer): TObject;
  1754. begin
  1755. Result := FMap.Data[Index];
  1756. end;
  1757. procedure TStringList.Put(Index: Integer; const S: string);
  1758. begin
  1759. Changing;
  1760. FMap.Keys[Index] := S;
  1761. Changed;
  1762. end;
  1763. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1764. begin
  1765. Changing;
  1766. FMap.Data[Index] := AObject;
  1767. Changed;
  1768. end;
  1769. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1770. begin
  1771. FMap.Capacity := NewCapacity;
  1772. end;
  1773. procedure TStringList.SetUpdateState(Updating: Boolean);
  1774. begin
  1775. if Updating then
  1776. Changing
  1777. else
  1778. Changed
  1779. end;
  1780. function TStringList.Add(const S: string): Integer;
  1781. begin
  1782. Result := FMap.Add(S);
  1783. end;
  1784. procedure TStringList.Clear;
  1785. begin
  1786. if FMap.Count = 0 then exit;
  1787. Changing;
  1788. FMap.Clear;
  1789. Changed;
  1790. end;
  1791. procedure TStringList.Delete(Index: Integer);
  1792. begin
  1793. if (Index < 0) or (Index >= FMap.Count) then
  1794. Error(SListIndexError, Index);
  1795. Changing;
  1796. FMap.Delete(Index);
  1797. Changed;
  1798. end;
  1799. procedure TStringList.Exchange(Index1, Index2: Integer);
  1800. begin
  1801. if (Index1 < 0) or (Index1 >= FMap.Count) then
  1802. Error(SListIndexError, Index1);
  1803. if (Index2 < 0) or (Index2 >= FMap.Count) then
  1804. Error(SListIndexError, Index2);
  1805. Changing;
  1806. FMap.InternalExchange(Index1, Index2);
  1807. Changed;
  1808. end;
  1809. procedure TStringList.SetCaseSensitive(NewSensitive: Boolean);
  1810. begin
  1811. if NewSensitive <> FCaseSensitive then
  1812. begin
  1813. FCaseSensitive := NewSensitive;
  1814. if Sorted then
  1815. Sort;
  1816. end;
  1817. end;
  1818. function TStringList.MapPtrCompare(Key1, Key2: Pointer): Integer;
  1819. begin
  1820. Result := FOnCompareText(string(Key1^), string(Key2^));
  1821. end;
  1822. function TStringList.DefaultCompareText(const s1, s2: string): PtrInt;
  1823. begin
  1824. if FCaseSensitive then
  1825. Result := AnsiCompareStr(s1, s2)
  1826. else
  1827. Result := AnsiCompareText(s1, s2);
  1828. end;
  1829. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1830. begin
  1831. Result := FOnCompareText(s1, s2);
  1832. end;
  1833. function TStringList.Find(const S: string; var Index: Integer): Boolean;
  1834. begin
  1835. Result := FMap.Find(S, Index);
  1836. end;
  1837. function TStringList.IndexOf(const S: string): Integer;
  1838. begin
  1839. Result := FMap.IndexOf(S);
  1840. end;
  1841. procedure TStringList.Insert(Index: Integer; const S: string);
  1842. begin
  1843. if not Sorted and (0 <= Index) and (Index < FMap.Count) then
  1844. Changing;
  1845. FMap.InsertKey(Index, S);
  1846. Changed;
  1847. end;
  1848. type
  1849. PStringList_CustomSort_Context = ^TStringList_CustomSort_Context;
  1850. TStringList_CustomSort_Context = record
  1851. List: TStringList;
  1852. ListStartPtr: Pointer;
  1853. ItemSize: SizeUInt;
  1854. IndexBase: Integer;
  1855. CompareFn: TStringListSortCompare;
  1856. end;
  1857. function TStringList_CustomSort_Comparer(Item1, Item2, Context: Pointer): Integer;
  1858. begin
  1859. with PStringList_CustomSort_Context(Context)^ do
  1860. Result := CompareFn(List,
  1861. ((Item1 - ListStartPtr) div ItemSize) + IndexBase,
  1862. ((Item2 - ListStartPtr) div ItemSize) + IndexBase);
  1863. end;
  1864. procedure TStringList_CustomSort_Exchanger(Item1, Item2, Context: Pointer);
  1865. begin
  1866. with PStringList_CustomSort_Context(Context)^ do
  1867. List.Exchange(((Item1 - ListStartPtr) div ItemSize) + IndexBase,
  1868. ((Item2 - ListStartPtr) div ItemSize) + IndexBase);
  1869. end;
  1870. procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  1871. var
  1872. Context: TStringList_CustomSort_Context;
  1873. begin
  1874. if L > R then
  1875. exit;
  1876. Context.List := Self;
  1877. Context.ListStartPtr := FMap.Items[L];
  1878. Context.CompareFn := CompareFn;
  1879. Context.ItemSize := FMap.KeySize + FMap.DataSize;
  1880. Context.IndexBase := L;
  1881. DefaultSortingAlgorithm^.ItemListSorter_CustomItemExchanger_ContextComparer(
  1882. Context.ListStartPtr, R - L + 1, Context.ItemSize, @TStringList_CustomSort_Comparer,
  1883. @TStringList_CustomSort_Exchanger, @Context);
  1884. end;
  1885. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1886. begin
  1887. if not Sorted and (FMap.Count > 1) then
  1888. begin
  1889. Changing;
  1890. QuickSort(0, FMap.Count-1, CompareFn);
  1891. Changed;
  1892. end;
  1893. end;
  1894. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare; SortingAlgorithm: PSortingAlgorithm);
  1895. var
  1896. Context: TStringList_CustomSort_Context;
  1897. begin
  1898. if not Sorted and (FMap.Count > 1) then
  1899. begin
  1900. Changing;
  1901. Context.List := Self;
  1902. Context.ListStartPtr := FMap.Items[0];
  1903. Context.CompareFn := CompareFn;
  1904. Context.ItemSize := FMap.KeySize + FMap.DataSize;
  1905. Context.IndexBase := 0;
  1906. SortingAlgorithm^.ItemListSorter_CustomItemExchanger_ContextComparer(
  1907. Context.ListStartPtr, FMap.Count, Context.ItemSize, @TStringList_CustomSort_Comparer,
  1908. @TStringList_CustomSort_Exchanger, @Context);
  1909. Changed;
  1910. end;
  1911. end;
  1912. procedure TStringList.Sort;
  1913. begin
  1914. if not Sorted and (FMap.Count > 1) then
  1915. begin
  1916. Changing;
  1917. FMap.Sort;
  1918. Changed;
  1919. end;
  1920. end;
  1921. procedure TStringList.Sort(SortingAlgorithm: PSortingAlgorithm);
  1922. begin
  1923. if not Sorted and (FMap.Count > 1) then
  1924. begin
  1925. Changing;
  1926. FMap.Sort(SortingAlgorithm);
  1927. Changed;
  1928. end;
  1929. end;
  1930. {$endif}