stringl.inc 48 KB

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