stringl.inc 49 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505
  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 : SizeInt;
  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 : SizeInt;
  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: SizeInt;
  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, toIndex: integer; aList : TStrings);
  345. var
  346. i: integer;
  347. begin
  348. for i:=fromIndex to toIndex do
  349. aList.Add(Self[i]);
  350. end;
  351. Procedure TStrings.Slice(fromIndex: integer; aList : TStrings);
  352. begin
  353. Slice(fromIndex,Count-1,aList);
  354. end;
  355. Function TStrings.Slice(fromIndex, toIndex: integer) : TStrings;
  356. begin
  357. Result:=TStringsClass(Self.ClassType).Create;
  358. try
  359. Slice(FromIndex, toIndex,Result);
  360. except
  361. FreeAndNil(Result);
  362. Raise;
  363. end;
  364. end;
  365. Function TStrings.Slice(fromIndex: integer) : TStrings;
  366. begin
  367. Result := Slice(fromIndex,Count-1);
  368. end;
  369. function TStrings.GetName(Index: Integer): string;
  370. Var
  371. V : String;
  372. begin
  373. GetNameValue(Index,Result,V);
  374. end;
  375. function TStrings.GetStrictDelimiter: Boolean;
  376. begin
  377. Result:=soStrictDelimiter in FOptions;
  378. end;
  379. function TStrings.GetTrailingLineBreak: Boolean;
  380. begin
  381. Result:=soTrailingLineBreak in FOptions;
  382. end;
  383. function TStrings.GetUseLocale: Boolean;
  384. begin
  385. Result:=soUseLocale in FOptions;
  386. end;
  387. function TStrings.GetWriteBOM: Boolean;
  388. begin
  389. Result:=soWriteBOM in FOptions;
  390. end;
  391. Function TStrings.GetValue(const Name: string): string;
  392. Var
  393. L : Longint;
  394. N : String;
  395. begin
  396. Result:='';
  397. L:=IndexOfName(Name);
  398. If L<>-1 then
  399. GetNameValue(L,N,Result);
  400. end;
  401. Function TStrings.GetValueFromIndex(Index: Integer): string;
  402. Var
  403. N : String;
  404. begin
  405. GetNameValue(Index,N,Result);
  406. end;
  407. Procedure TStrings.SetValueFromIndex(Index: Integer; const Value: string);
  408. begin
  409. If (Value='') then
  410. Delete(Index)
  411. else
  412. begin
  413. If (Index<0) then
  414. Index:=Add('');
  415. CheckSpecialChars;
  416. Strings[Index]:=GetName(Index)+FNameValueSeparator+Value;
  417. end;
  418. end;
  419. procedure TStrings.ReadData(Reader: TReader);
  420. begin
  421. Reader.ReadListBegin;
  422. BeginUpdate;
  423. try
  424. Clear;
  425. while not Reader.EndOfList do
  426. Add(Reader.ReadString);
  427. finally
  428. EndUpdate;
  429. end;
  430. Reader.ReadListEnd;
  431. end;
  432. Procedure TStrings.SetDelimitedText(const AValue: string);
  433. begin
  434. CheckSpecialChars;
  435. DoSetDelimitedText(aValue,True,StrictDelimiter,FQuoteChar,FDelimiter);
  436. end;
  437. Procedure TStrings.DoSetDelimitedText(const AValue: string; DoClear,aStrictDelimiter : Boolean; aQuoteChar,aDelimiter : Char);
  438. var
  439. len,i,j: SizeInt;
  440. aNotFirst:boolean;
  441. Procedure AddQuoted;
  442. begin
  443. Add(StringReplace(Copy(AValue,i+1,j-i-1),aQuoteChar+aQuoteChar,aQuoteChar, [rfReplaceAll]));
  444. end;
  445. Function CheckQuoted : Boolean;
  446. { Paraphrased from Delphi XE2 help:
  447. Strings must be separated by Delimiter characters or spaces.
  448. They may be enclosed in QuoteChars.
  449. QuoteChars in the string must be repeated to distinguish them from the QuoteChars enclosing the string.
  450. }
  451. begin
  452. Result:=(AValue[i]=aQuoteChar) and (aQuoteChar<>#0);
  453. If Not Result then
  454. exit;
  455. // next string is quoted
  456. j:=i+1;
  457. while (j<=len) and
  458. ((AValue[j]<>aQuoteChar) or
  459. ((j+1<=len) and (AValue[j+1]=aQuoteChar))) do
  460. begin
  461. if (j<=len) and (AValue[j]=aQuoteChar) then
  462. inc(j,2)
  463. else
  464. inc(j);
  465. end;
  466. AddQuoted;
  467. i:=j+1;
  468. end;
  469. Procedure MaybeSkipSpaces; inline;
  470. begin
  471. if Not aStrictDelimiter then
  472. while (i<=len) and (Ord(AValue[i])<=Ord(' ')) do
  473. inc(i);
  474. end;
  475. begin
  476. BeginUpdate;
  477. i:=1;
  478. j:=1;
  479. aNotFirst:=false;
  480. try
  481. if DoClear then
  482. Clear;
  483. len:=length(AValue);
  484. while i<=len do
  485. begin
  486. // skip delimiter
  487. if aNotFirst and (i<=len) and (AValue[i]=aDelimiter) then
  488. inc(i);
  489. MaybeSkipSpaces;
  490. // read next string
  491. if i>len then
  492. begin
  493. if aNotFirst then Add('');
  494. end
  495. else
  496. begin
  497. // next string is quoted
  498. if not CheckQuoted then
  499. begin
  500. // next string is not quoted; read until control character/space/delimiter
  501. j:=i;
  502. while (j<=len) and
  503. (aStrictDelimiter or (Ord(AValue[j])>Ord(' '))) and
  504. (AValue[j]<>aDelimiter) do
  505. inc(j);
  506. Add( Copy(AValue,i,j-i));
  507. i:=j;
  508. end;
  509. end;
  510. MaybeSkipSpaces;
  511. aNotFirst:=true;
  512. end; // While I<=Len
  513. finally
  514. EndUpdate;
  515. end;
  516. end;
  517. Procedure TStrings.SetCommaText(const Value: string);
  518. begin
  519. CheckSpecialChars;
  520. DoSetDelimitedText(Value,True,StrictDelimiter,'"',',');
  521. end;
  522. procedure TStrings.SetMissingNameValueSeparatorAction(AValue: TMissingNameValueSeparatorAction);
  523. begin
  524. CheckSpecialChars;
  525. FMissingNameValueSeparatorAction:=aValue;
  526. end;
  527. Procedure TStrings.SetStringsAdapter(const Value: IStringsAdapter);
  528. begin
  529. end;
  530. procedure TStrings.SetStrictDelimiter(AValue: Boolean);
  531. begin
  532. if AValue then
  533. Include(FOptions,soStrictDelimiter)
  534. else
  535. Exclude(FOptions,soStrictDelimiter);
  536. end;
  537. procedure TStrings.SetTrailingLineBreak(AValue: Boolean);
  538. begin
  539. if AValue then
  540. Include(FOptions,soTrailingLineBreak)
  541. else
  542. Exclude(FOptions,soTrailingLineBreak);
  543. end;
  544. procedure TStrings.SetUseLocale(AValue: Boolean);
  545. begin
  546. if AValue then
  547. Include(FOptions,soUseLocale)
  548. else
  549. Exclude(FOptions,soUseLocale);
  550. end;
  551. procedure TStrings.SetWriteBOM(AValue: Boolean);
  552. begin
  553. if AValue then
  554. Include(FOptions,soWriteBOM)
  555. else
  556. Exclude(FOptions,soWriteBOM);
  557. end;
  558. Procedure TStrings.SetDefaultEncoding(const ADefaultEncoding: TEncoding);
  559. begin
  560. if (FDefaultEncoding<>nil) and not TEncoding.IsStandardEncoding(FDefaultEncoding) then
  561. FDefaultEncoding.Free;
  562. if TEncoding.IsStandardEncoding(ADefaultEncoding) then
  563. FDefaultEncoding:=ADefaultEncoding
  564. else if ADefaultEncoding<>nil then
  565. FDefaultEncoding:=ADefaultEncoding.Clone
  566. else
  567. FDefaultEncoding:=TEncoding.Default;
  568. end;
  569. Procedure TStrings.SetValue(const Name, Value: string);
  570. Var L : longint;
  571. begin
  572. CheckSpecialChars;
  573. L:=IndexOfName(Name);
  574. if L=-1 then
  575. begin
  576. if Value<>'' then
  577. Add (Name+FNameValueSeparator+Value)
  578. end
  579. else
  580. begin
  581. if Value='' then
  582. Delete(L)
  583. else
  584. Strings[L]:=Name+FNameValueSeparator+value;
  585. end;
  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*SizeOf(Char));
  651. Inc(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, PChar(@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. BeginUpdate;
  863. try
  864. Result:=Add(S);
  865. Objects[result]:=AObject;
  866. finally
  867. EndUpdate;
  868. end;
  869. end;
  870. function TStrings.AddObject(const Fmt: string; Args : Array of const; AObject: TObject): Integer;
  871. begin
  872. Result:=AddObject(Format(Fmt,Args),AObject);
  873. end;
  874. function TStrings.AddPair(const AName, AValue: string): TStrings;
  875. begin
  876. Result:=AddPair(AName,AValue,Nil);
  877. end;
  878. function TStrings.AddPair(const AName, AValue: string; AObject: TObject): TStrings;
  879. begin
  880. Result := Self;
  881. AddObject(Concat(AName, NameValueSeparator, AValue), AObject);
  882. end;
  883. Procedure TStrings.Append(const S: string);
  884. begin
  885. Add (S);
  886. end;
  887. Procedure TStrings.AddStrings(TheStrings: TStrings; ClearFirst : Boolean);
  888. Var Runner : longint;
  889. begin
  890. beginupdate;
  891. try
  892. if ClearFirst then
  893. Clear;
  894. if Count + TheStrings.Count > Capacity then
  895. Capacity := Count + TheStrings.Count;
  896. For Runner:=0 to TheStrings.Count-1 do
  897. self.AddObject (Thestrings[Runner],TheStrings.Objects[Runner]);
  898. finally
  899. EndUpdate;
  900. end;
  901. end;
  902. Procedure TStrings.AddStrings(TheStrings: TStrings);
  903. begin
  904. AddStrings(TheStrings, False);
  905. end;
  906. Procedure TStrings.AddStrings(const TheStrings: array of string);
  907. begin
  908. AddStrings(TheStrings, False);
  909. end;
  910. Procedure TStrings.AddStrings(const TheStrings: array of string; ClearFirst : Boolean);
  911. Var Runner : longint;
  912. begin
  913. beginupdate;
  914. try
  915. if ClearFirst then
  916. Clear;
  917. if Count + High(TheStrings)+1 > Capacity then
  918. Capacity := Count + High(TheStrings)+1;
  919. For Runner:=Low(TheStrings) to High(TheStrings) do
  920. self.Add(Thestrings[Runner]);
  921. finally
  922. EndUpdate;
  923. end;
  924. end;
  925. procedure TStrings.SetStrings(TheStrings: TStrings);
  926. begin
  927. AddStrings(TheStrings,True);
  928. end;
  929. procedure TStrings.SetStrings(TheStrings: array of string);
  930. begin
  931. AddStrings(TheStrings,True);
  932. end;
  933. Procedure TStrings.Assign(Source: TPersistent);
  934. Var
  935. S : TStrings;
  936. begin
  937. If Source is TStrings then
  938. begin
  939. S:=TStrings(Source);
  940. BeginUpdate;
  941. Try
  942. clear;
  943. FSpecialCharsInited:=S.FSpecialCharsInited;
  944. FQuoteChar:=S.FQuoteChar;
  945. FDelimiter:=S.FDelimiter;
  946. FNameValueSeparator:=S.FNameValueSeparator;
  947. FLBS:=S.FLBS;
  948. FLineBreak:=S.FLineBreak;
  949. FOptions:=S.FOptions;
  950. DefaultEncoding:=S.DefaultEncoding;
  951. SetEncoding(S.Encoding);
  952. AddStrings(S);
  953. finally
  954. EndUpdate;
  955. end;
  956. end
  957. else
  958. Inherited Assign(Source);
  959. end;
  960. Procedure TStrings.BeginUpdate;
  961. begin
  962. if FUpdateCount = 0 then SetUpdateState(true);
  963. inc(FUpdateCount);
  964. end;
  965. Procedure TStrings.EndUpdate;
  966. begin
  967. If FUpdateCount>0 then
  968. Dec(FUpdateCount);
  969. if FUpdateCount=0 then
  970. SetUpdateState(False);
  971. end;
  972. Function TStrings.Equals(Obj: TObject): Boolean;
  973. begin
  974. if Obj is TStrings then
  975. Result := Equals(TStrings(Obj))
  976. else
  977. Result := inherited Equals(Obj);
  978. end;
  979. Function TStrings.Equals(TheStrings: TStrings): Boolean;
  980. Var Runner,Nr : Longint;
  981. begin
  982. Result:=False;
  983. Nr:=Self.Count;
  984. if Nr<>TheStrings.Count then exit;
  985. For Runner:=0 to Nr-1 do
  986. If Strings[Runner]<>TheStrings[Runner] then exit;
  987. Result:=True;
  988. end;
  989. Procedure TStrings.Exchange(Index1, Index2: Integer);
  990. Var
  991. Obj : TObject;
  992. Str : String;
  993. begin
  994. beginUpdate;
  995. Try
  996. Obj:=Objects[Index1];
  997. Str:=Strings[Index1];
  998. Objects[Index1]:=Objects[Index2];
  999. Strings[Index1]:=Strings[Index2];
  1000. Objects[Index2]:=Obj;
  1001. Strings[Index2]:=Str;
  1002. finally
  1003. EndUpdate;
  1004. end;
  1005. end;
  1006. function TStrings.GetEnumerator: TStringsEnumerator;
  1007. begin
  1008. Result:=TStringsEnumerator.Create(Self);
  1009. end;
  1010. Function TStrings.GetText: PChar;
  1011. begin
  1012. Result:=StrNew(PChar(Self.Text));
  1013. end;
  1014. Function TStrings.DoCompareText(const s1,s2 : string) : PtrInt;
  1015. begin
  1016. if UseLocale then
  1017. result:=AnsiCompareText(s1,s2)
  1018. else
  1019. result:=CompareText(s1,s2);
  1020. end;
  1021. Function TStrings.Contains(const S: string): Boolean;
  1022. begin
  1023. Result:=Indexof(S)<>-1;
  1024. end;
  1025. Function TStrings.ContainsObject(const AObject: TObject): Boolean;
  1026. begin
  1027. Result:=IndexOfObject(AObject)<>-1;
  1028. end;
  1029. Function TStrings.IndexOf(const S: string): Integer;
  1030. begin
  1031. Result:=0;
  1032. While (Result<Count) and (DoCompareText(Strings[Result],S)<>0) do Result:=Result+1;
  1033. if Result=Count then Result:=-1;
  1034. end;
  1035. function TStrings.IndexOf(const S: string; aStart: Integer): Integer;
  1036. begin
  1037. if aStart<0 then
  1038. begin
  1039. aStart:=Count+aStart;
  1040. if aStart<0 then
  1041. aStart:=0;
  1042. end;
  1043. Result:=aStart;
  1044. While (Result<Count) and (DoCompareText(Strings[Result],S)<>0) do Result:=Result+1;
  1045. if Result=Count then Result:=-1;
  1046. end;
  1047. Function TStrings.ContainsName(const Name: string): Boolean;
  1048. begin
  1049. Result:=IndexOfName(Name)<>-1;
  1050. end;
  1051. Function TStrings.IndexOfName(const Name: string): Integer;
  1052. Var
  1053. len : SizeInt;
  1054. S : String;
  1055. begin
  1056. CheckSpecialChars;
  1057. Result:=0;
  1058. while (Result<Count) do
  1059. begin
  1060. S:=Strings[Result];
  1061. len:=pos(FNameValueSeparator,S)-1;
  1062. if (len>=0) and (DoCompareText(Name,Copy(S,1,Len))=0) then
  1063. exit;
  1064. inc(result);
  1065. end;
  1066. result:=-1;
  1067. end;
  1068. Function TStrings.IndexOfObject(AObject: TObject): Integer;
  1069. begin
  1070. Result:=0;
  1071. While (Result<count) and (Objects[Result]<>AObject) do Result:=Result+1;
  1072. If Result=Count then Result:=-1;
  1073. end;
  1074. Procedure TStrings.InsertObject(Index: Integer; const S: string;
  1075. AObject: TObject);
  1076. begin
  1077. BeginUpdate;
  1078. try
  1079. Insert (Index,S);
  1080. Objects[Index]:=AObject;
  1081. finally
  1082. EndUpdate;
  1083. end;
  1084. end;
  1085. function TStrings.LastIndexOf(const S: string): Integer;
  1086. begin
  1087. Result:=LastIndexOf(S,Count-1);
  1088. end;
  1089. function TStrings.LastIndexOf(const S: string; aStart : Integer): Integer;
  1090. begin
  1091. if aStart<0 then
  1092. begin
  1093. aStart:=Count+aStart;
  1094. if aStart<0 then
  1095. aStart:=0;
  1096. end;
  1097. Result:=aStart;
  1098. if Result>=Count-1 then
  1099. Result:=Count-1;
  1100. While (Result>=0) and (DoCompareText(Strings[Result],S)<>0) do
  1101. Result:=Result-1;
  1102. end;
  1103. Procedure TStrings.LoadFromFile(const FileName: string);
  1104. begin
  1105. LoadFromFile(FileName,False)
  1106. end;
  1107. Procedure TStrings.LoadFromFile(const FileName: string; IgnoreEncoding : Boolean);
  1108. Var
  1109. TheStream : TFileStream;
  1110. begin
  1111. TheStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
  1112. try
  1113. LoadFromStream(TheStream, IgnoreEncoding);
  1114. finally
  1115. TheStream.Free;
  1116. end;
  1117. end;
  1118. Procedure TStrings.LoadFromFile(const FileName: string; AEncoding: TEncoding);
  1119. Var
  1120. TheStream : TFileStream;
  1121. begin
  1122. TheStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
  1123. try
  1124. LoadFromStream(TheStream,AEncoding);
  1125. finally
  1126. TheStream.Free;
  1127. end;
  1128. end;
  1129. Procedure TStrings.LoadFromStream(Stream: TStream);
  1130. begin
  1131. LoadFromStream(Stream,False);
  1132. end;
  1133. Const
  1134. LoadBufSize = 1024;
  1135. LoadMaxGrow = MaxInt Div 2;
  1136. Procedure TStrings.LoadFromStream(Stream: TStream; IgnoreEncoding : Boolean);
  1137. {
  1138. Borlands method is no good, since a pipe for
  1139. instance doesn't have a size.
  1140. So we must do it the hard way.
  1141. }
  1142. Var
  1143. Buffer : AnsiString;
  1144. BufLen : SizeInt;
  1145. BytesRead, I, BufDelta : Longint;
  1146. begin
  1147. if not IgnoreEncoding then
  1148. begin
  1149. LoadFromStream(Stream,Nil);
  1150. Exit;
  1151. end;
  1152. // reread into a buffer
  1153. beginupdate;
  1154. try
  1155. Buffer:='';
  1156. BufLen:=0;
  1157. I:=1;
  1158. Repeat
  1159. BufDelta:=LoadBufSize*I;
  1160. SetLength(Buffer,BufLen+BufDelta);
  1161. BytesRead:=Stream.Read(Buffer[BufLen+1],BufDelta);
  1162. inc(BufLen,BufDelta);
  1163. If I<LoadMaxGrow then
  1164. I:=I shl 1;
  1165. Until BytesRead<>BufDelta;
  1166. SetLength(Buffer, BufLen-BufDelta+BytesRead);
  1167. SetTextStr(Buffer);
  1168. SetLength(Buffer,0);
  1169. finally
  1170. EndUpdate;
  1171. end;
  1172. if soPreserveBOM in FOptions then
  1173. WriteBOM:=False;
  1174. end;
  1175. Procedure TStrings.LoadFromStream(Stream: TStream; AEncoding: TEncoding);
  1176. {
  1177. Borlands method is no good, since a pipe for
  1178. instance doesn't have a size.
  1179. So we must do it the hard way.
  1180. }
  1181. Var
  1182. Buffer : TBytes;
  1183. T : string;
  1184. BufLen : SizeInt;
  1185. BytesRead, I, BufDelta, PreambleLength : Longint;
  1186. begin
  1187. // reread into a buffer
  1188. beginupdate;
  1189. try
  1190. SetLength(Buffer,0);
  1191. BufLen:=0;
  1192. I:=1;
  1193. Repeat
  1194. BufDelta:=LoadBufSize*I;
  1195. SetLength(Buffer,BufLen+BufDelta);
  1196. BytesRead:=Stream.Read(Buffer[BufLen],BufDelta);
  1197. inc(BufLen,BufDelta);
  1198. If I<LoadMaxGrow then
  1199. I:=I shl 1;
  1200. Until BytesRead<>BufDelta;
  1201. SetLength(Buffer,BufLen-BufDelta+BytesRead);
  1202. PreambleLength:=TEncoding.GetBufferEncoding(Buffer,AEncoding,FDefaultEncoding);
  1203. T:=AEncoding.GetAnsiString(Buffer,PreambleLength,Length(Buffer)-PreambleLength);
  1204. if soPreserveBOM in FOptions then
  1205. WriteBOM:=PreambleLength>0;
  1206. SetEncoding(AEncoding);
  1207. SetLength(Buffer,0);
  1208. SetTextStr(T);
  1209. finally
  1210. EndUpdate;
  1211. end;
  1212. end;
  1213. Procedure TStrings.Move(CurIndex, NewIndex: Integer);
  1214. Var
  1215. Obj : TObject;
  1216. Str : String;
  1217. begin
  1218. if (CurIndex=NewIndex) then
  1219. Exit;
  1220. BeginUpdate;
  1221. Try
  1222. Obj:=Objects[CurIndex];
  1223. Str:=Strings[CurIndex];
  1224. Objects[CurIndex]:=Nil; // Prevent Delete from freeing.
  1225. Delete(Curindex);
  1226. InsertObject(NewIndex,Str,Obj);
  1227. finally
  1228. EndUpdate;
  1229. end;
  1230. end;
  1231. function TStrings.Pop: string;
  1232. var
  1233. C : Integer;
  1234. begin
  1235. Result:='';
  1236. C:=Count-1;
  1237. if (C>=0) then
  1238. begin
  1239. Result:=Strings[C];
  1240. Delete(C);
  1241. end;
  1242. end;
  1243. function TStrings.Shift: String;
  1244. begin
  1245. Result:='';
  1246. if (Count > 0) then
  1247. begin
  1248. Result:=Strings[0];
  1249. Delete(0);
  1250. end;
  1251. end;
  1252. Procedure TStrings.SaveToFile(const FileName: string);
  1253. Var TheStream : TFileStream;
  1254. begin
  1255. TheStream:=TFileStream.Create(FileName,fmCreate);
  1256. try
  1257. SaveToStream(TheStream);
  1258. finally
  1259. TheStream.Free;
  1260. end;
  1261. end;
  1262. Procedure TStrings.SaveToFile(const FileName: string; IgnoreEncoding : Boolean);
  1263. Var TheStream : TFileStream;
  1264. begin
  1265. TheStream:=TFileStream.Create(FileName,fmCreate);
  1266. try
  1267. SaveToStream(TheStream, IgnoreEncoding);
  1268. finally
  1269. TheStream.Free;
  1270. end;
  1271. end;
  1272. Procedure TStrings.SaveToFile(const FileName: string; AEncoding: TEncoding);
  1273. Var TheStream : TFileStream;
  1274. begin
  1275. TheStream:=TFileStream.Create(FileName,fmCreate);
  1276. try
  1277. SaveToStream(TheStream,AEncoding);
  1278. finally
  1279. TheStream.Free;
  1280. end;
  1281. end;
  1282. Procedure TStrings.SaveToStream(Stream: TStream);
  1283. begin
  1284. SaveToStream(Stream,False)
  1285. end;
  1286. Procedure TStrings.SaveToStream(Stream: TStream; IgnoreEncoding: Boolean);
  1287. Var
  1288. I,L,NLS : SizeInt;
  1289. S,NL : String;
  1290. begin
  1291. if not IgnoreEncoding then
  1292. begin
  1293. SaveToStream(Stream,FEncoding);
  1294. Exit;
  1295. end;
  1296. NL:=GetLineBreakCharLBS;
  1297. NLS:=Length(NL)*SizeOf(Char);
  1298. For i:=0 To count-1 do
  1299. begin
  1300. S:=Strings[I];
  1301. L:=Length(S);
  1302. if L<>0 then
  1303. Stream.WriteBuffer(S[1], L*SizeOf(Char));
  1304. if (I<Count-1) or Not SkipLastLineBreak then
  1305. Stream.WriteBuffer(NL[1], NLS);
  1306. end;
  1307. end;
  1308. Procedure TStrings.SaveToStream(Stream: TStream; AEncoding: TEncoding);
  1309. Var B,BNL : TBytes;
  1310. NL,S: string;
  1311. i,BNLS: SizeInt;
  1312. begin
  1313. if AEncoding=nil then
  1314. AEncoding:=FDefaultEncoding;
  1315. if WriteBOM then
  1316. begin
  1317. B:=AEncoding.GetPreamble;
  1318. if Length(B)>0 then
  1319. Stream.WriteBuffer(B[0],Length(B));
  1320. end;
  1321. NL := GetLineBreakCharLBS;
  1322. {$if sizeof(char)=1}
  1323. BNL:=AEncoding.GetAnsiBytes(NL);
  1324. {$else}
  1325. BNL:=AEncoding.GetBytes(NL);
  1326. {$endif}
  1327. BNLS:=Length(BNL);
  1328. For i:=0 To count-1 do
  1329. begin
  1330. S:=Strings[I];
  1331. if S<>'' then
  1332. begin
  1333. {$if sizeof(char)=1}
  1334. B:=AEncoding.GetAnsiBytes(S);
  1335. {$else}
  1336. B:=AEncoding.GetBytes(S);
  1337. {$endif}
  1338. Stream.WriteBuffer(B[0],Length(B));
  1339. end;
  1340. if (I<Count-1) or Not SkipLastLineBreak then
  1341. Stream.WriteBuffer(BNL[0],BNLS);
  1342. end;
  1343. end;
  1344. Procedure TStrings.SetText(TheText: PChar);
  1345. Var S : String;
  1346. begin
  1347. If TheText<>Nil then
  1348. S:=StrPas(TheText)
  1349. else
  1350. S:='';
  1351. SetTextStr(S);
  1352. end;
  1353. {****************************************************************************}
  1354. {* TStringList *}
  1355. {****************************************************************************}
  1356. {$if not defined(FPC_TESTGENERICS)}
  1357. procedure TStringList.ExchangeItemsInt(Index1, Index2: Integer);
  1358. Var P1,P2 : Pointer;
  1359. begin
  1360. P1:=Pointer(Flist^[Index1].FString);
  1361. P2:=Pointer(Flist^[Index1].FObject);
  1362. Pointer(Flist^[Index1].Fstring):=Pointer(Flist^[Index2].Fstring);
  1363. Pointer(Flist^[Index1].FObject):=Pointer(Flist^[Index2].FObject);
  1364. Pointer(Flist^[Index2].Fstring):=P1;
  1365. Pointer(Flist^[Index2].FObject):=P2;
  1366. end;
  1367. function TStringList.GetSorted: Boolean;
  1368. begin
  1369. Result:=FSortStyle in [sslUser,sslAuto];
  1370. end;
  1371. procedure TStringList.ExchangeItems(Index1, Index2: Integer);
  1372. begin
  1373. ExchangeItemsInt(Index1, Index2);
  1374. end;
  1375. procedure TStringList.Grow;
  1376. Var
  1377. NC : Integer;
  1378. begin
  1379. NC:=FCapacity;
  1380. If NC>=256 then
  1381. NC:=NC+(NC Div 4)
  1382. else if NC=0 then
  1383. NC:=4
  1384. else
  1385. NC:=NC*4;
  1386. SetCapacity(NC);
  1387. end;
  1388. procedure TStringList.InternalClear(FromIndex: Integer; ClearOnly: Boolean);
  1389. Var
  1390. I: Integer;
  1391. begin
  1392. if FromIndex < FCount then
  1393. begin
  1394. if FOwnsObjects then
  1395. begin
  1396. For I:=FromIndex to FCount-1 do
  1397. begin
  1398. Flist^[I].FString:='';
  1399. freeandnil(Flist^[i].FObject);
  1400. end;
  1401. end
  1402. else
  1403. begin
  1404. For I:=FromIndex to FCount-1 do
  1405. Flist^[I].FString:='';
  1406. end;
  1407. FCount:=FromIndex;
  1408. end;
  1409. if Not ClearOnly then
  1410. SetCapacity(0);
  1411. end;
  1412. procedure TStringList.InsertItem(Index: Integer; const S: string);
  1413. begin
  1414. InsertItem(Index, S, nil);
  1415. end;
  1416. procedure TStringList.InsertItem(Index: Integer; const S: string; O: TObject);
  1417. begin
  1418. Changing;
  1419. If FCount=Fcapacity then Grow;
  1420. If Index<FCount then
  1421. System.Move (FList^[Index],FList^[Index+1],
  1422. (FCount-Index)*SizeOf(TStringItem));
  1423. Pointer(Flist^[Index].Fstring):=Nil; // Needed to initialize...
  1424. Flist^[Index].FString:=S;
  1425. Flist^[Index].FObject:=O;
  1426. Inc(FCount);
  1427. Changed;
  1428. end;
  1429. procedure TStringList.SetSorted(Value: Boolean);
  1430. begin
  1431. If Value then
  1432. SortStyle:=sslAuto
  1433. else
  1434. SortStyle:=sslNone
  1435. end;
  1436. procedure TStringList.Changed;
  1437. begin
  1438. If (FUpdateCount=0) Then
  1439. begin
  1440. If Assigned(FOnChange) then
  1441. FOnchange(Self);
  1442. FPONotifyObservers(Self,ooChange,Nil);
  1443. end;
  1444. end;
  1445. procedure TStringList.Changing;
  1446. begin
  1447. If FUpdateCount=0 then
  1448. if Assigned(FOnChanging) then
  1449. FOnchanging(Self);
  1450. end;
  1451. function TStringList.Get(Index: Integer): string;
  1452. begin
  1453. CheckIndex(Index);
  1454. Result:=Flist^[Index].FString;
  1455. end;
  1456. function TStringList.GetCapacity: Integer;
  1457. begin
  1458. Result:=FCapacity;
  1459. end;
  1460. function TStringList.GetCount: Integer;
  1461. begin
  1462. Result:=FCount;
  1463. end;
  1464. function TStringList.GetObject(Index: Integer): TObject;
  1465. begin
  1466. CheckIndex(Index);
  1467. Result:=Flist^[Index].FObject;
  1468. end;
  1469. procedure TStringList.Put(Index: Integer; const S: string);
  1470. begin
  1471. If Sorted then
  1472. Error(SSortedListError,0);
  1473. CheckIndex(Index);
  1474. Changing;
  1475. Flist^[Index].FString:=S;
  1476. Changed;
  1477. end;
  1478. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1479. begin
  1480. CheckIndex(Index);
  1481. Changing;
  1482. Flist^[Index].FObject:=AObject;
  1483. Changed;
  1484. end;
  1485. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1486. Var NewList : Pointer;
  1487. MSize : Longint;
  1488. begin
  1489. If (NewCapacity<0) then
  1490. Error (SListCapacityError,NewCapacity);
  1491. If NewCapacity>FCapacity then
  1492. begin
  1493. GetMem (NewList,NewCapacity*SizeOf(TStringItem));
  1494. If NewList=Nil then
  1495. Error (SListCapacityError,NewCapacity);
  1496. If Assigned(FList) then
  1497. begin
  1498. MSize:=FCapacity*Sizeof(TStringItem);
  1499. System.Move (FList^,NewList^,MSize);
  1500. FillWord (PAnsiChar(NewList)[MSize],(NewCapacity-FCapacity)*(SizeOf(TStringItem) div SizeOf(Word)), 0);
  1501. FreeMem (Flist,MSize);
  1502. end;
  1503. Flist:=NewList;
  1504. FCapacity:=NewCapacity;
  1505. end
  1506. else if NewCapacity<FCapacity then
  1507. begin
  1508. if NewCapacity = 0 then
  1509. begin
  1510. if FCount > 0 then
  1511. InternalClear(0,True);
  1512. FreeMem(FList);
  1513. FList := nil;
  1514. end else
  1515. begin
  1516. InternalClear(NewCapacity,True);
  1517. GetMem(NewList, NewCapacity * SizeOf(TStringItem));
  1518. System.Move(FList^, NewList^, NewCapacity * SizeOf(TStringItem));
  1519. FreeMem(FList);
  1520. FList := NewList;
  1521. end;
  1522. FCapacity:=NewCapacity;
  1523. end;
  1524. end;
  1525. procedure TStringList.SetUpdateState(Updating: Boolean);
  1526. begin
  1527. If Updating then
  1528. Changing
  1529. else
  1530. Changed
  1531. end;
  1532. Constructor TStringList.Create;
  1533. begin
  1534. inherited Create;
  1535. end;
  1536. Constructor TStringList.Create(anOwnsObjects : Boolean);
  1537. begin
  1538. inherited Create;
  1539. FOwnsObjects:=anOwnsObjects;
  1540. end;
  1541. destructor TStringList.Destroy;
  1542. begin
  1543. InternalClear;
  1544. Inherited destroy;
  1545. end;
  1546. function TStringList.DoAddObject(const S: string; AObject: TObject): Integer;
  1547. begin
  1548. If (SortStyle<>sslAuto) then
  1549. Result:=FCount
  1550. else
  1551. If Find (S,Result) then
  1552. Case Duplicates of
  1553. DupIgnore : Exit;
  1554. DupError : Error(SDuplicateString,0)
  1555. end;
  1556. BeginUpdate;
  1557. try
  1558. InsertItem (Result,S);
  1559. if (aObject<>Nil) then
  1560. Objects[Result]:=AObject;
  1561. finally
  1562. EndUpdate;
  1563. end;
  1564. end;
  1565. function TStringList.Add(const S: string): Integer;
  1566. begin
  1567. Result:=DoAddObject(S, nil);
  1568. end;
  1569. function TStringList.AddObject(const S: string; AObject: TObject): Integer;
  1570. begin
  1571. Result:=DoAddObject(S,aObject);
  1572. end;
  1573. procedure TStringList.Clear;
  1574. begin
  1575. if FCount = 0 then Exit;
  1576. Changing;
  1577. InternalClear;
  1578. Changed;
  1579. end;
  1580. procedure TStringList.Delete(Index: Integer);
  1581. begin
  1582. CheckIndex(Index);
  1583. Changing;
  1584. Flist^[Index].FString:='';
  1585. if FOwnsObjects then
  1586. FreeAndNil(Flist^[Index].FObject);
  1587. Dec(FCount);
  1588. If Index<FCount then
  1589. System.Move(Flist^[Index+1],
  1590. Flist^[Index],
  1591. (Fcount-Index)*SizeOf(TStringItem));
  1592. Changed;
  1593. end;
  1594. procedure TStringList.Exchange(Index1, Index2: Integer);
  1595. begin
  1596. CheckIndex(Index1);
  1597. CheckIndex(Index2);
  1598. Changing;
  1599. ExchangeItemsInt(Index1,Index2);
  1600. changed;
  1601. end;
  1602. procedure TStringList.SetCaseSensitive(b : boolean);
  1603. begin
  1604. if b=FCaseSensitive then
  1605. Exit;
  1606. FCaseSensitive:=b;
  1607. if FSortStyle=sslAuto then
  1608. begin
  1609. FForceSort:=True;
  1610. try
  1611. Sort;
  1612. finally
  1613. FForceSort:=False;
  1614. end;
  1615. end;
  1616. end;
  1617. procedure TStringList.SetSortStyle(AValue: TStringsSortStyle);
  1618. begin
  1619. if FSortStyle=AValue then Exit;
  1620. if (AValue=sslAuto) then
  1621. Sort;
  1622. FSortStyle:=AValue;
  1623. end;
  1624. procedure TStringList.CheckIndex(AIndex: Integer);
  1625. begin
  1626. If (AIndex<0) or (AIndex>=FCount) then
  1627. Error(SListIndexError,AIndex);
  1628. end;
  1629. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1630. begin
  1631. if FCaseSensitive then
  1632. begin
  1633. if UseLocale then
  1634. result:=AnsiCompareStr(s1,s2)
  1635. else
  1636. result:=CompareStr(s1,s2);
  1637. end else
  1638. begin
  1639. if UseLocale then
  1640. result:=AnsiCompareText(s1,s2)
  1641. else
  1642. result:=CompareText(s1,s2);
  1643. end;
  1644. end;
  1645. function TStringList.Find(const S: string; out Index: Integer): Boolean;
  1646. var
  1647. L, R, I: Integer;
  1648. CompareRes: PtrInt;
  1649. begin
  1650. Result := false;
  1651. Index:=-1;
  1652. if Not Sorted then
  1653. Raise EListError.Create(SErrFindNeedsSortedList);
  1654. // Use binary search.
  1655. L := 0;
  1656. R := Count - 1;
  1657. while (L<=R) do
  1658. begin
  1659. I := L + (R - L) div 2;
  1660. CompareRes := DoCompareText(S, Flist^[I].FString);
  1661. if (CompareRes>0) then
  1662. L := I+1
  1663. else begin
  1664. R := I-1;
  1665. if (CompareRes=0) then begin
  1666. Result := true;
  1667. if (Duplicates<>dupAccept) then
  1668. L := I; // forces end of while loop
  1669. end;
  1670. end;
  1671. end;
  1672. Index := L;
  1673. end;
  1674. function TStringList.IndexOf(const S: string): Integer;
  1675. begin
  1676. If Not Sorted then
  1677. Result:=Inherited indexOf(S)
  1678. else
  1679. // faster using binary search...
  1680. If Not Find (S,Result) then
  1681. Result:=-1;
  1682. end;
  1683. procedure TStringList.Insert(Index: Integer; const S: string);
  1684. begin
  1685. If SortStyle=sslAuto then
  1686. Error (SSortedListError,0)
  1687. else
  1688. begin
  1689. If (Index<0) or (Index>FCount) then
  1690. Error(SListIndexError,Index); // Cannot use CheckIndex, because there >= FCount...
  1691. InsertItem (Index,S);
  1692. end;
  1693. end;
  1694. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1695. begin
  1696. CustomSort(CompareFn, {$IFDEF FPC_DOTTEDUNITS}System.{$ENDIF}SortBase.DefaultSortingAlgorithm);
  1697. end;
  1698. type
  1699. PStringList_CustomSort_Context = ^TStringList_CustomSort_Context;
  1700. TStringList_CustomSort_Context = record
  1701. List: TStringList;
  1702. ListStartPtr: Pointer;
  1703. CompareFn: TStringListSortCompare;
  1704. end;
  1705. function TStringList_CustomSort_Comparer(Item1, Item2, Context: Pointer): Integer;
  1706. begin
  1707. with PStringList_CustomSort_Context(Context)^ do
  1708. Result := CompareFn(List,
  1709. (Item1 - ListStartPtr) div SizeOf(TStringItem),
  1710. (Item2 - ListStartPtr) div SizeOf(TStringItem));
  1711. end;
  1712. procedure TStringList_CustomSort_Exchanger(Item1, Item2, Context: Pointer);
  1713. begin
  1714. with PStringList_CustomSort_Context(Context)^ do
  1715. List.ExchangeItems((Item1 - ListStartPtr) div SizeOf(TStringItem),
  1716. (Item2 - ListStartPtr) div SizeOf(TStringItem));
  1717. end;
  1718. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare; SortingAlgorithm: PSortingAlgorithm);
  1719. var
  1720. Context: TStringList_CustomSort_Context;
  1721. begin
  1722. If (FCount>1) and (FForceSort or (FSortStyle<>sslAuto)) then
  1723. begin
  1724. Changing;
  1725. Context.List := Self;
  1726. Context.ListStartPtr := FList;
  1727. Context.CompareFn := CompareFn;
  1728. //if ExchangeItems is overriden call that, else call (faster) ItemListSorter_ContextComparer
  1729. if TMethod(@Self.ExchangeItems).Code = CodePointer(@TStringList.ExchangeItems) then
  1730. SortingAlgorithm^.ItemListSorter_ContextComparer(
  1731. FList, FCount, SizeOf(TStringItem), @TStringList_CustomSort_Comparer,
  1732. @Context)
  1733. else
  1734. SortingAlgorithm^.ItemListSorter_CustomItemExchanger_ContextComparer(
  1735. FList, FCount, SizeOf(TStringItem), @TStringList_CustomSort_Comparer,
  1736. @TStringList_CustomSort_Exchanger, @Context);
  1737. Changed;
  1738. end;
  1739. end;
  1740. function StringListAnsiCompare(List: TStringList; Index1, Index: Integer): Integer;
  1741. begin
  1742. Result := List.DoCompareText(List.FList^[Index1].FString,
  1743. List.FList^[Index].FString);
  1744. end;
  1745. procedure TStringList.Sort;
  1746. begin
  1747. CustomSort(@StringListAnsiCompare);
  1748. end;
  1749. procedure TStringList.Sort(SortingAlgorithm: PSortingAlgorithm);
  1750. begin
  1751. CustomSort(@StringListAnsiCompare, SortingAlgorithm);
  1752. end;
  1753. {$else}
  1754. { generics based implementation of TStringList follows }
  1755. function StringListAnsiCompare(List: TStringList; Index1, Index2: Integer): Integer;
  1756. begin
  1757. Result := List.DoCompareText(List.Strings[Index1], List.Strings[Index2]);
  1758. end;
  1759. constructor TStringList.Create;
  1760. begin
  1761. inherited;
  1762. FOwnsObjects:=false;
  1763. FMap := TFPStrObjMap.Create;
  1764. FMap.OnPtrCompare := @MapPtrCompare;
  1765. FOnCompareText := @DefaultCompareText;
  1766. NameValueSeparator:='=';
  1767. CheckSpecialChars;
  1768. end;
  1769. destructor TStringList.Destroy;
  1770. begin
  1771. FMap.Free;
  1772. inherited;
  1773. end;
  1774. function TStringList.GetDuplicates: TDuplicates;
  1775. begin
  1776. Result := FMap.Duplicates;
  1777. end;
  1778. function TStringList.GetSorted: boolean;
  1779. begin
  1780. Result := FMap.Sorted;
  1781. end;
  1782. procedure TStringList.SetDuplicates(NewDuplicates: TDuplicates);
  1783. begin
  1784. FMap.Duplicates := NewDuplicates;
  1785. end;
  1786. procedure TStringList.SetSorted(NewSorted: Boolean);
  1787. begin
  1788. FMap.Sorted := NewSorted;
  1789. end;
  1790. procedure TStringList.Changed;
  1791. begin
  1792. if FUpdateCount = 0 then
  1793. if Assigned(FOnChange) then
  1794. FOnChange(Self);
  1795. end;
  1796. procedure TStringList.Changing;
  1797. begin
  1798. if FUpdateCount = 0 then
  1799. if Assigned(FOnChanging) then
  1800. FOnChanging(Self);
  1801. end;
  1802. function TStringList.Get(Index: Integer): string;
  1803. begin
  1804. Result := FMap.Keys[Index];
  1805. end;
  1806. function TStringList.GetCapacity: Integer;
  1807. begin
  1808. Result := FMap.Capacity;
  1809. end;
  1810. function TStringList.GetCount: Integer;
  1811. begin
  1812. Result := FMap.Count;
  1813. end;
  1814. function TStringList.GetObject(Index: Integer): TObject;
  1815. begin
  1816. Result := FMap.Data[Index];
  1817. end;
  1818. procedure TStringList.Put(Index: Integer; const S: string);
  1819. begin
  1820. Changing;
  1821. FMap.Keys[Index] := S;
  1822. Changed;
  1823. end;
  1824. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1825. begin
  1826. Changing;
  1827. FMap.Data[Index] := AObject;
  1828. Changed;
  1829. end;
  1830. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1831. begin
  1832. FMap.Capacity := NewCapacity;
  1833. end;
  1834. procedure TStringList.SetUpdateState(Updating: Boolean);
  1835. begin
  1836. if Updating then
  1837. Changing
  1838. else
  1839. Changed
  1840. end;
  1841. function TStringList.Add(const S: string): Integer;
  1842. begin
  1843. Result := FMap.Add(S);
  1844. end;
  1845. procedure TStringList.Clear;
  1846. begin
  1847. if FMap.Count = 0 then exit;
  1848. Changing;
  1849. FMap.Clear;
  1850. Changed;
  1851. end;
  1852. procedure TStringList.Delete(Index: Integer);
  1853. begin
  1854. if (Index < 0) or (Index >= FMap.Count) then
  1855. Error(SListIndexError, Index);
  1856. Changing;
  1857. FMap.Delete(Index);
  1858. Changed;
  1859. end;
  1860. procedure TStringList.Exchange(Index1, Index2: Integer);
  1861. begin
  1862. if (Index1 < 0) or (Index1 >= FMap.Count) then
  1863. Error(SListIndexError, Index1);
  1864. if (Index2 < 0) or (Index2 >= FMap.Count) then
  1865. Error(SListIndexError, Index2);
  1866. Changing;
  1867. FMap.InternalExchange(Index1, Index2);
  1868. Changed;
  1869. end;
  1870. procedure TStringList.SetCaseSensitive(NewSensitive: Boolean);
  1871. begin
  1872. if NewSensitive <> FCaseSensitive then
  1873. begin
  1874. FCaseSensitive := NewSensitive;
  1875. if Sorted then
  1876. Sort;
  1877. end;
  1878. end;
  1879. function TStringList.MapPtrCompare(Key1, Key2: Pointer): Integer;
  1880. begin
  1881. Result := FOnCompareText(string(Key1^), string(Key2^));
  1882. end;
  1883. function TStringList.DefaultCompareText(const s1, s2: string): PtrInt;
  1884. begin
  1885. if FCaseSensitive then
  1886. Result := AnsiCompareStr(s1, s2)
  1887. else
  1888. Result := AnsiCompareText(s1, s2);
  1889. end;
  1890. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1891. begin
  1892. Result := FOnCompareText(s1, s2);
  1893. end;
  1894. function TStringList.Find(const S: string; var Index: Integer): Boolean;
  1895. begin
  1896. Result := FMap.Find(S, Index);
  1897. end;
  1898. function TStringList.IndexOf(const S: string): Integer;
  1899. begin
  1900. Result := FMap.IndexOf(S);
  1901. end;
  1902. procedure TStringList.Insert(Index: Integer; const S: string);
  1903. begin
  1904. if not Sorted and (0 <= Index) and (Index < FMap.Count) then
  1905. Changing;
  1906. FMap.InsertKey(Index, S);
  1907. Changed;
  1908. end;
  1909. type
  1910. PStringList_CustomSort_Context = ^TStringList_CustomSort_Context;
  1911. TStringList_CustomSort_Context = record
  1912. List: TStringList;
  1913. ListStartPtr: Pointer;
  1914. ItemSize: SizeUInt;
  1915. IndexBase: Integer;
  1916. CompareFn: TStringListSortCompare;
  1917. end;
  1918. function TStringList_CustomSort_Comparer(Item1, Item2, Context: Pointer): Integer;
  1919. begin
  1920. with PStringList_CustomSort_Context(Context)^ do
  1921. Result := CompareFn(List,
  1922. ((Item1 - ListStartPtr) div ItemSize) + IndexBase,
  1923. ((Item2 - ListStartPtr) div ItemSize) + IndexBase);
  1924. end;
  1925. procedure TStringList_CustomSort_Exchanger(Item1, Item2, Context: Pointer);
  1926. begin
  1927. with PStringList_CustomSort_Context(Context)^ do
  1928. List.Exchange(((Item1 - ListStartPtr) div ItemSize) + IndexBase,
  1929. ((Item2 - ListStartPtr) div ItemSize) + IndexBase);
  1930. end;
  1931. procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  1932. var
  1933. Context: TStringList_CustomSort_Context;
  1934. begin
  1935. if L > R then
  1936. exit;
  1937. Context.List := Self;
  1938. Context.ListStartPtr := FMap.Items[L];
  1939. Context.CompareFn := CompareFn;
  1940. Context.ItemSize := FMap.KeySize + FMap.DataSize;
  1941. Context.IndexBase := L;
  1942. DefaultSortingAlgorithm^.ItemListSorter_CustomItemExchanger_ContextComparer(
  1943. Context.ListStartPtr, R - L + 1, Context.ItemSize, @TStringList_CustomSort_Comparer,
  1944. @TStringList_CustomSort_Exchanger, @Context);
  1945. end;
  1946. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1947. begin
  1948. if not Sorted and (FMap.Count > 1) then
  1949. begin
  1950. Changing;
  1951. QuickSort(0, FMap.Count-1, CompareFn);
  1952. Changed;
  1953. end;
  1954. end;
  1955. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare; SortingAlgorithm: PSortingAlgorithm);
  1956. var
  1957. Context: TStringList_CustomSort_Context;
  1958. begin
  1959. if not Sorted and (FMap.Count > 1) then
  1960. begin
  1961. Changing;
  1962. Context.List := Self;
  1963. Context.ListStartPtr := FMap.Items[0];
  1964. Context.CompareFn := CompareFn;
  1965. Context.ItemSize := FMap.KeySize + FMap.DataSize;
  1966. Context.IndexBase := 0;
  1967. SortingAlgorithm^.ItemListSorter_CustomItemExchanger_ContextComparer(
  1968. Context.ListStartPtr, FMap.Count, Context.ItemSize, @TStringList_CustomSort_Comparer,
  1969. @TStringList_CustomSort_Exchanger, @Context);
  1970. Changed;
  1971. end;
  1972. end;
  1973. procedure TStringList.Sort;
  1974. begin
  1975. if not Sorted and (FMap.Count > 1) then
  1976. begin
  1977. Changing;
  1978. FMap.Sort;
  1979. Changed;
  1980. end;
  1981. end;
  1982. procedure TStringList.Sort(SortingAlgorithm: PSortingAlgorithm);
  1983. begin
  1984. if not Sorted and (FMap.Count > 1) then
  1985. begin
  1986. Changing;
  1987. FMap.Sort(SortingAlgorithm);
  1988. Changed;
  1989. end;
  1990. end;
  1991. {$endif}