stringl.inc 48 KB

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