stringl.inc 50 KB

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