stringl.inc 49 KB

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