stringl.inc 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 1999-2000 by the Free Pascal development team
  4. See the file COPYING.FPC, included in this distribution,
  5. for details about the copyright.
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. {****************************************************************************}
  11. {* TStringsEnumerator *}
  12. {****************************************************************************}
  13. constructor TStringsEnumerator.Create(AStrings: TStrings);
  14. begin
  15. inherited Create;
  16. FStrings := AStrings;
  17. FPosition := -1;
  18. end;
  19. function TStringsEnumerator.GetCurrent: String;
  20. begin
  21. Result := FStrings[FPosition];
  22. end;
  23. function TStringsEnumerator.MoveNext: Boolean;
  24. begin
  25. Inc(FPosition);
  26. Result := FPosition < FStrings.Count;
  27. end;
  28. {****************************************************************************}
  29. {* TStrings *}
  30. {****************************************************************************}
  31. // Function to quote text. Should move maybe to sysutils !!
  32. // Also, it is not clear at this point what exactly should be done.
  33. { //!! is used to mark unsupported things. }
  34. Function QuoteString (Const S : String; Const Quote : String) : String;
  35. Var
  36. I,J : Integer;
  37. begin
  38. J:=0;
  39. Result:=S;
  40. for i:=1 to length(s) do
  41. begin
  42. inc(j);
  43. if S[i]=Quote then
  44. begin
  45. System.Insert(Quote,Result,J);
  46. inc(j);
  47. end;
  48. end;
  49. Result:=Quote+Result+Quote;
  50. end;
  51. {
  52. For compatibility we can't add a Constructor to TSTrings to initialize
  53. the special characters. Therefore we add a routine which is called whenever
  54. the special chars are needed.
  55. }
  56. Procedure Tstrings.CheckSpecialChars;
  57. begin
  58. If Not FSpecialCharsInited then
  59. begin
  60. FQuoteChar:='"';
  61. FDelimiter:=',';
  62. FNameValueSeparator:='=';
  63. FLBS:=DefaultTextLineBreakStyle;
  64. FSpecialCharsInited:=true;
  65. FLineBreak:=sLineBreak;
  66. end;
  67. end;
  68. Function TStrings.GetSkipLastLineBreak : Boolean;
  69. begin
  70. CheckSpecialChars;
  71. Result:=FSkipLastLineBreak;
  72. end;
  73. procedure TStrings.SetSkipLastLineBreak(const AValue : Boolean);
  74. begin
  75. CheckSpecialChars;
  76. FSkipLastLineBreak:=AValue;
  77. end;
  78. Function TStrings.GetLBS : TTextLineBreakStyle;
  79. begin
  80. CheckSpecialChars;
  81. Result:=FLBS;
  82. end;
  83. Procedure TStrings.SetLBS (AValue : TTextLineBreakStyle);
  84. begin
  85. CheckSpecialChars;
  86. FLBS:=AValue;
  87. end;
  88. procedure TStrings.SetDelimiter(c:Char);
  89. begin
  90. CheckSpecialChars;
  91. FDelimiter:=c;
  92. end;
  93. Procedure TStrings.SetEncoding(const AEncoding: TEncoding);
  94. begin
  95. if (FEncoding<>nil) and not TEncoding.IsStandardEncoding(FEncoding) then
  96. FEncoding.Free;
  97. if TEncoding.IsStandardEncoding(AEncoding) then
  98. FEncoding:=AEncoding
  99. else if AEncoding<>nil then
  100. FEncoding:=AEncoding.Clone
  101. else
  102. FEncoding:=nil;
  103. end;
  104. Function TStrings.GetDelimiter : Char;
  105. begin
  106. CheckSpecialChars;
  107. Result:=FDelimiter;
  108. end;
  109. procedure TStrings.SetLineBreak(Const S : String);
  110. begin
  111. CheckSpecialChars;
  112. FLineBreak:=S;
  113. end;
  114. Function TStrings.GetLineBreak : String;
  115. begin
  116. CheckSpecialChars;
  117. Result:=FLineBreak;
  118. end;
  119. procedure TStrings.SetQuoteChar(c:Char);
  120. begin
  121. CheckSpecialChars;
  122. FQuoteChar:=c;
  123. end;
  124. Function TStrings.GetQuoteChar :Char;
  125. begin
  126. CheckSpecialChars;
  127. Result:=FQuoteChar;
  128. end;
  129. procedure TStrings.SetNameValueSeparator(c:Char);
  130. begin
  131. CheckSpecialChars;
  132. FNameValueSeparator:=c;
  133. end;
  134. Function TStrings.GetNameValueSeparator :Char;
  135. begin
  136. CheckSpecialChars;
  137. Result:=FNameValueSeparator;
  138. end;
  139. function TStrings.GetCommaText: string;
  140. Var
  141. C1,C2 : Char;
  142. FSD : Boolean;
  143. begin
  144. CheckSpecialChars;
  145. FSD:=StrictDelimiter;
  146. C1:=Delimiter;
  147. C2:=QuoteChar;
  148. Delimiter:=',';
  149. QuoteChar:='"';
  150. StrictDelimiter:=False;
  151. Try
  152. Result:=GetDelimitedText;
  153. Finally
  154. Delimiter:=C1;
  155. QuoteChar:=C2;
  156. StrictDelimiter:=FSD;
  157. end;
  158. end;
  159. Function TStrings.GetDelimitedText: string;
  160. Var
  161. I : integer;
  162. p : pchar;
  163. BreakChars : set of char;
  164. S : String;
  165. doQuote : Boolean;
  166. begin
  167. CheckSpecialChars;
  168. result:='';
  169. if StrictDelimiter then
  170. BreakChars:=[#0,QuoteChar,Delimiter]
  171. else
  172. BreakChars:=[#0..' ',QuoteChar,Delimiter];
  173. // Check for break characters and quote if required.
  174. For i:=0 to count-1 do
  175. begin
  176. S:=Strings[i];
  177. doQuote:=FAlwaysQuote;
  178. If not DoQuote then
  179. begin
  180. p:=pchar(S);
  181. //Quote strings that include BreakChars:
  182. while not(p^ in BreakChars) do
  183. inc(p);
  184. DoQuote:=(p<>pchar(S)+length(S));
  185. end;
  186. if DoQuote then
  187. Result:=Result+QuoteString(S,QuoteChar)
  188. else
  189. Result:=Result+S;
  190. if I<Count-1 then
  191. Result:=Result+Delimiter;
  192. end;
  193. // Quote empty string:
  194. If (Length(Result)=0) and (Count=1) then
  195. Result:=QuoteChar+QuoteChar;
  196. end;
  197. procedure TStrings.GetNameValue(Index : Integer; Out AName,AValue : String);
  198. Var L : longint;
  199. begin
  200. CheckSpecialChars;
  201. AValue:=Strings[Index];
  202. L:=Pos(FNameValueSeparator,AValue);
  203. If L<>0 then
  204. begin
  205. AName:=Copy(AValue,1,L-1);
  206. System.Delete(AValue,1,L);
  207. end
  208. else
  209. AName:='';
  210. end;
  211. function TStrings.ExtractName(const s:String):String;
  212. var
  213. L: Longint;
  214. begin
  215. CheckSpecialChars;
  216. L:=Pos(FNameValueSeparator,S);
  217. If L<>0 then
  218. Result:=Copy(S,1,L-1)
  219. else
  220. Result:='';
  221. end;
  222. function TStrings.GetName(Index: Integer): string;
  223. Var
  224. V : String;
  225. begin
  226. GetNameValue(Index,Result,V);
  227. end;
  228. Function TStrings.GetValue(const Name: string): string;
  229. Var
  230. L : longint;
  231. N : String;
  232. begin
  233. Result:='';
  234. L:=IndexOfName(Name);
  235. If L<>-1 then
  236. GetNameValue(L,N,Result);
  237. end;
  238. Function TStrings.GetValueFromIndex(Index: Integer): string;
  239. Var
  240. N : String;
  241. begin
  242. GetNameValue(Index,N,Result);
  243. end;
  244. Procedure TStrings.SetValueFromIndex(Index: Integer; const Value: string);
  245. begin
  246. If (Value='') then
  247. Delete(Index)
  248. else
  249. begin
  250. If (Index<0) then
  251. Index:=Add('');
  252. CheckSpecialChars;
  253. Strings[Index]:=GetName(Index)+FNameValueSeparator+Value;
  254. end;
  255. end;
  256. procedure TStrings.ReadData(Reader: TReader);
  257. begin
  258. Reader.ReadListBegin;
  259. BeginUpdate;
  260. try
  261. Clear;
  262. while not Reader.EndOfList do
  263. Add(Reader.ReadString);
  264. finally
  265. EndUpdate;
  266. end;
  267. Reader.ReadListEnd;
  268. end;
  269. Procedure TStrings.SetDelimitedText(const AValue: string);
  270. var i,j: SizeInt;
  271. aNotFirst:boolean;
  272. begin
  273. CheckSpecialChars;
  274. BeginUpdate;
  275. i:=1;
  276. j:=1;
  277. aNotFirst:=false;
  278. { Paraphrased from Delphi XE2 help:
  279. Strings must be separated by Delimiter characters or spaces.
  280. They may be enclosed in QuoteChars.
  281. QuoteChars in the string must be repeated to distinguish them from the QuoteChars enclosing the string.
  282. }
  283. try
  284. Clear;
  285. If StrictDelimiter then
  286. begin
  287. while i<=length(AValue) do begin
  288. // skip delimiter
  289. if aNotFirst and (i<=length(AValue)) and (AValue[i]=FDelimiter) then inc(i);
  290. // read next string
  291. if i<=length(AValue) then begin
  292. if AValue[i]=FQuoteChar then begin
  293. // next string is quoted
  294. j:=i+1;
  295. while (j<=length(AValue)) and
  296. ( (AValue[j]<>FQuoteChar) or
  297. ( (j+1<=length(AValue)) and (AValue[j+1]=FQuoteChar) ) ) do begin
  298. if (j<=length(AValue)) and (AValue[j]=FQuoteChar) then inc(j,2)
  299. else inc(j);
  300. end;
  301. // j is position of closing quote
  302. Add( StringReplace (Copy(AValue,i+1,j-i-1),
  303. FQuoteChar+FQuoteChar,FQuoteChar, [rfReplaceAll]));
  304. i:=j+1;
  305. end else begin
  306. // next string is not quoted; read until delimiter
  307. j:=i;
  308. while (j<=length(AValue)) and
  309. (AValue[j]<>FDelimiter) do inc(j);
  310. Add( Copy(AValue,i,j-i));
  311. i:=j;
  312. end;
  313. end else begin
  314. if aNotFirst then Add('');
  315. end;
  316. aNotFirst:=true;
  317. end;
  318. end
  319. else
  320. begin
  321. while i<=length(AValue) do begin
  322. // skip delimiter
  323. if aNotFirst and (i<=length(AValue)) and (AValue[i]=FDelimiter) then inc(i);
  324. // skip spaces
  325. while (i<=length(AValue)) and (Ord(AValue[i])<=Ord(' ')) do inc(i);
  326. // read next string
  327. if i<=length(AValue) then begin
  328. if AValue[i]=FQuoteChar then begin
  329. // next string is quoted
  330. j:=i+1;
  331. while (j<=length(AValue)) and
  332. ( (AValue[j]<>FQuoteChar) or
  333. ( (j+1<=length(AValue)) and (AValue[j+1]=FQuoteChar) ) ) do begin
  334. if (j<=length(AValue)) and (AValue[j]=FQuoteChar) then inc(j,2)
  335. else inc(j);
  336. end;
  337. // j is position of closing quote
  338. Add( StringReplace (Copy(AValue,i+1,j-i-1),
  339. FQuoteChar+FQuoteChar,FQuoteChar, [rfReplaceAll]));
  340. i:=j+1;
  341. end else begin
  342. // next string is not quoted; read until control character/space/delimiter
  343. j:=i;
  344. while (j<=length(AValue)) and
  345. (Ord(AValue[j])>Ord(' ')) and
  346. (AValue[j]<>FDelimiter) do inc(j);
  347. Add( Copy(AValue,i,j-i));
  348. i:=j;
  349. end;
  350. end else begin
  351. if aNotFirst then Add('');
  352. end;
  353. // skip spaces
  354. while (i<=length(AValue)) and (Ord(AValue[i])<=Ord(' ')) do inc(i);
  355. aNotFirst:=true;
  356. end;
  357. end;
  358. finally
  359. EndUpdate;
  360. end;
  361. end;
  362. Procedure TStrings.SetCommaText(const Value: string);
  363. Var
  364. C1,C2 : Char;
  365. begin
  366. CheckSpecialChars;
  367. C1:=Delimiter;
  368. C2:=QuoteChar;
  369. Delimiter:=',';
  370. QuoteChar:='"';
  371. Try
  372. SetDelimitedText(Value);
  373. Finally
  374. Delimiter:=C1;
  375. QuoteChar:=C2;
  376. end;
  377. end;
  378. Procedure TStrings.SetStringsAdapter(const Value: IStringsAdapter);
  379. begin
  380. end;
  381. Procedure TStrings.SetDefaultEncoding(const ADefaultEncoding: TEncoding);
  382. begin
  383. if (FDefaultEncoding<>nil) and not TEncoding.IsStandardEncoding(FDefaultEncoding) then
  384. FDefaultEncoding.Free;
  385. if TEncoding.IsStandardEncoding(ADefaultEncoding) then
  386. FDefaultEncoding:=ADefaultEncoding
  387. else if ADefaultEncoding<>nil then
  388. FDefaultEncoding:=ADefaultEncoding.Clone
  389. else
  390. FDefaultEncoding:=TEncoding.Default;
  391. end;
  392. Procedure TStrings.SetValue(const Name, Value: string);
  393. Var L : longint;
  394. begin
  395. CheckSpecialChars;
  396. L:=IndexOfName(Name);
  397. if L=-1 then
  398. Add (Name+FNameValueSeparator+Value)
  399. else
  400. Strings[L]:=Name+FNameValueSeparator+value;
  401. end;
  402. procedure TStrings.WriteData(Writer: TWriter);
  403. var
  404. i: Integer;
  405. begin
  406. Writer.WriteListBegin;
  407. for i := 0 to Count - 1 do
  408. Writer.WriteString(Strings[i]);
  409. Writer.WriteListEnd;
  410. end;
  411. procedure TStrings.DefineProperties(Filer: TFiler);
  412. var
  413. HasData: Boolean;
  414. begin
  415. if Assigned(Filer.Ancestor) then
  416. // Only serialize if string list is different from ancestor
  417. if Filer.Ancestor.InheritsFrom(TStrings) then
  418. HasData := not Equals(TStrings(Filer.Ancestor))
  419. else
  420. HasData := True
  421. else
  422. HasData := Count > 0;
  423. Filer.DefineProperty('Strings', @ReadData, @WriteData, HasData);
  424. end;
  425. Procedure TStrings.Error(const Msg: string; Data: Integer);
  426. begin
  427. Raise EStringListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  428. end;
  429. Procedure TStrings.Error(const Msg: pstring; Data: Integer);
  430. begin
  431. Raise EStringListError.CreateFmt(Msg^,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  432. end;
  433. Function TStrings.GetCapacity: Integer;
  434. begin
  435. Result:=Count;
  436. end;
  437. Function TStrings.GetObject(Index: Integer): TObject;
  438. begin
  439. Result:=Nil;
  440. end;
  441. Function TStrings.GetTextStr: string;
  442. Var P : Pchar;
  443. I,L,NLS : SizeInt;
  444. S,NL : String;
  445. begin
  446. CheckSpecialChars;
  447. // Determine needed place
  448. if FLineBreak<>sLineBreak then
  449. NL:=FLineBreak
  450. else
  451. Case FLBS of
  452. tlbsLF : NL:=#10;
  453. tlbsCRLF : NL:=#13#10;
  454. tlbsCR : NL:=#13;
  455. end;
  456. L:=0;
  457. NLS:=Length(NL);
  458. For I:=0 to count-1 do
  459. L:=L+Length(Strings[I])+NLS;
  460. if SkipLastLineBreak then
  461. Dec(L,NLS);
  462. Setlength(Result,L);
  463. P:=Pointer(Result);
  464. For i:=0 To count-1 do
  465. begin
  466. S:=Strings[I];
  467. L:=Length(S);
  468. if L<>0 then
  469. System.Move(Pointer(S)^,P^,L);
  470. P:=P+L;
  471. if (I<Count-1) or Not SkipLastLineBreak then
  472. For L:=1 to NLS do
  473. begin
  474. P^:=NL[L];
  475. inc(P);
  476. end;
  477. end;
  478. end;
  479. Procedure TStrings.Put(Index: Integer; const S: string);
  480. Var Obj : TObject;
  481. begin
  482. Obj:=Objects[Index];
  483. Delete(Index);
  484. InsertObject(Index,S,Obj);
  485. end;
  486. Procedure TStrings.PutObject(Index: Integer; AObject: TObject);
  487. begin
  488. // Empty.
  489. end;
  490. Procedure TStrings.SetCapacity(NewCapacity: Integer);
  491. begin
  492. // Empty.
  493. end;
  494. Class Function TStrings.GetNextLine (Const Value : String; Var S : String; Var P : SizeInt) : Boolean;
  495. Var
  496. PS : PChar;
  497. IP,L : SizeInt;
  498. begin
  499. L:=Length(Value);
  500. S:='';
  501. Result:=False;
  502. If ((L-P)<0) then
  503. exit;
  504. if ((L-P)=0) and (not (value[P] in [#10,#13])) Then
  505. Begin
  506. s:=value[P];
  507. inc(P);
  508. Exit(True);
  509. End;
  510. PS:=PChar(Value)+P-1;
  511. IP:=P;
  512. While ((L-P)>=0) and (not (PS^ in [#10,#13])) do
  513. begin
  514. P:=P+1;
  515. Inc(PS);
  516. end;
  517. SetLength (S,P-IP);
  518. System.Move (Value[IP],Pointer(S)^,P-IP);
  519. If (P<=L) and (Value[P]=#13) then
  520. Inc(P);
  521. If (P<=L) and (Value[P]=#10) then
  522. Inc(P); // Point to character after #10(#13)
  523. Result:=True;
  524. end;
  525. Function TStrings.GetNextLineBreak (Const Value : String; Var S : String; Var P : SizeInt) : Boolean;
  526. Var
  527. PS,PC,PP : PChar;
  528. begin
  529. S:='';
  530. Result:=False;
  531. If ((Length(Value)-P)<0) then
  532. exit;
  533. PS:=@Value[P];
  534. PC:=PS;
  535. PP:=AnsiStrPos(PS,PChar(FLineBreak));
  536. // Stop on #0.
  537. While (PC^<>#0) and (PC<>PP) do
  538. Inc(PC);
  539. P:=P+(PC-PS)+Length(FLineBreak);
  540. SetString(S,PS,PC-PS);
  541. Result:=True;
  542. end;
  543. {$IF (SizeOf(Integer) < SizeOf(SizeInt)) }
  544. class function TStrings.GetNextLine(const Value: string; var S: string; var P: Integer) : Boolean;
  545. var
  546. LP: SizeInt;
  547. begin
  548. LP := P;
  549. Result := GetNextLine(Value, S, LP);
  550. P := LP;
  551. end;
  552. function TStrings.GetNextLineBreak(const Value: string; var S: string; var P: Integer) : Boolean;
  553. var
  554. LP: SizeInt;
  555. begin
  556. LP := P;
  557. Result := GetNextLineBreak(Value, S, LP);
  558. P := LP;
  559. end;
  560. {$IFEND}
  561. Procedure TStrings.DoSetTextStr(const Value: string; DoClear : Boolean);
  562. Var
  563. S : String;
  564. P : SizeInt;
  565. begin
  566. Try
  567. beginUpdate;
  568. if DoClear then
  569. Clear;
  570. P:=1;
  571. if FLineBreak=sLineBreak then
  572. begin
  573. While GetNextLine (Value,S,P) do
  574. Add(S)
  575. end
  576. else
  577. While GetNextLineBreak (Value,S,P) do
  578. Add(S);
  579. finally
  580. EndUpdate;
  581. end;
  582. end;
  583. Procedure TStrings.SetTextStr(const Value: string);
  584. begin
  585. CheckSpecialChars;
  586. DoSetTextStr(Value,True);
  587. end;
  588. Procedure TStrings.AddText(const S: string);
  589. begin
  590. CheckSpecialChars;
  591. DoSetTextStr(S,False);
  592. end;
  593. Procedure TStrings.SetUpdateState(Updating: Boolean);
  594. begin
  595. FPONotifyObservers(Self,ooChange,Nil);
  596. end;
  597. destructor TSTrings.Destroy;
  598. begin
  599. if (FEncoding<>nil) and not TEncoding.IsStandardEncoding(FEncoding) then
  600. FreeAndNil(FEncoding);
  601. if (FDefaultEncoding<>nil) and not TEncoding.IsStandardEncoding(FDefaultEncoding) then
  602. FreeAndNil(FDefaultEncoding);
  603. inherited destroy;
  604. end;
  605. constructor TStrings.Create;
  606. begin
  607. inherited Create;
  608. FDefaultEncoding:=TEncoding.Default;
  609. FEncoding:=nil;
  610. FWriteBOM:=True;
  611. FAlwaysQuote:=False;
  612. end;
  613. Function TStrings.Add(const S: string): Integer;
  614. begin
  615. Result:=Count;
  616. Insert (Count,S);
  617. end;
  618. function TStrings.Add(const Fmt : string; const Args : Array of const): Integer;
  619. begin
  620. Result:=Add(Format(Fmt,Args));
  621. end;
  622. Function TStrings.AddObject(const S: string; AObject: TObject): Integer;
  623. begin
  624. Result:=Add(S);
  625. Objects[result]:=AObject;
  626. end;
  627. function TStrings.AddObject(const Fmt: string; Args : Array of const; AObject: TObject): Integer;
  628. begin
  629. Result:=AddObject(Format(Fmt,Args),AObject);
  630. end;
  631. function TStrings.AddPair(const AName, AValue: string): TStrings;
  632. begin
  633. Result:=AddPair(AName,AValue,Nil);
  634. end;
  635. function TStrings.AddPair(const AName, AValue: string; AObject: TObject): TStrings;
  636. begin
  637. Result := Self;
  638. AddObject(Concat(AName, NameValueSeparator, AValue), AObject);
  639. end;
  640. Procedure TStrings.Append(const S: string);
  641. begin
  642. Add (S);
  643. end;
  644. Procedure TStrings.AddStrings(TheStrings: TStrings; ClearFirst : Boolean);
  645. Var Runner : longint;
  646. begin
  647. beginupdate;
  648. try
  649. if ClearFirst then
  650. Clear;
  651. if Count + TheStrings.Count > Capacity then
  652. Capacity := Count + TheStrings.Count;
  653. For Runner:=0 to TheStrings.Count-1 do
  654. self.AddObject (Thestrings[Runner],TheStrings.Objects[Runner]);
  655. finally
  656. EndUpdate;
  657. end;
  658. end;
  659. Procedure TStrings.AddStrings(TheStrings: TStrings);
  660. begin
  661. AddStrings(TheStrings, False);
  662. end;
  663. Procedure TStrings.AddStrings(const TheStrings: array of string);
  664. begin
  665. AddStrings(TheStrings, False);
  666. end;
  667. Procedure TStrings.AddStrings(const TheStrings: array of string; ClearFirst : Boolean);
  668. Var Runner : longint;
  669. begin
  670. beginupdate;
  671. try
  672. if ClearFirst then
  673. Clear;
  674. if Count + High(TheStrings)+1 > Capacity then
  675. Capacity := Count + High(TheStrings)+1;
  676. For Runner:=Low(TheStrings) to High(TheStrings) do
  677. self.Add(Thestrings[Runner]);
  678. finally
  679. EndUpdate;
  680. end;
  681. end;
  682. Procedure TStrings.Assign(Source: TPersistent);
  683. Var
  684. S : TStrings;
  685. begin
  686. If Source is TStrings then
  687. begin
  688. S:=TStrings(Source);
  689. BeginUpdate;
  690. Try
  691. clear;
  692. FSpecialCharsInited:=S.FSpecialCharsInited;
  693. FQuoteChar:=S.FQuoteChar;
  694. FDelimiter:=S.FDelimiter;
  695. FNameValueSeparator:=S.FNameValueSeparator;
  696. FLBS:=S.FLBS;
  697. FLineBreak:=S.FLineBreak;
  698. FWriteBOM:=S.FWriteBOM;
  699. DefaultEncoding:=S.DefaultEncoding;
  700. SetEncoding(S.Encoding);
  701. AddStrings(S);
  702. finally
  703. EndUpdate;
  704. end;
  705. end
  706. else
  707. Inherited Assign(Source);
  708. end;
  709. Procedure TStrings.BeginUpdate;
  710. begin
  711. if FUpdateCount = 0 then SetUpdateState(true);
  712. inc(FUpdateCount);
  713. end;
  714. Procedure TStrings.EndUpdate;
  715. begin
  716. If FUpdateCount>0 then
  717. Dec(FUpdateCount);
  718. if FUpdateCount=0 then
  719. SetUpdateState(False);
  720. end;
  721. Function TStrings.Equals(Obj: TObject): Boolean;
  722. begin
  723. if Obj is TStrings then
  724. Result := Equals(TStrings(Obj))
  725. else
  726. Result := inherited Equals(Obj);
  727. end;
  728. Function TStrings.Equals(TheStrings: TStrings): Boolean;
  729. Var Runner,Nr : Longint;
  730. begin
  731. Result:=False;
  732. Nr:=Self.Count;
  733. if Nr<>TheStrings.Count then exit;
  734. For Runner:=0 to Nr-1 do
  735. If Strings[Runner]<>TheStrings[Runner] then exit;
  736. Result:=True;
  737. end;
  738. Procedure TStrings.Exchange(Index1, Index2: Integer);
  739. Var
  740. Obj : TObject;
  741. Str : String;
  742. begin
  743. beginUpdate;
  744. Try
  745. Obj:=Objects[Index1];
  746. Str:=Strings[Index1];
  747. Objects[Index1]:=Objects[Index2];
  748. Strings[Index1]:=Strings[Index2];
  749. Objects[Index2]:=Obj;
  750. Strings[Index2]:=Str;
  751. finally
  752. EndUpdate;
  753. end;
  754. end;
  755. function TStrings.GetEnumerator: TStringsEnumerator;
  756. begin
  757. Result:=TStringsEnumerator.Create(Self);
  758. end;
  759. Function TStrings.GetText: PChar;
  760. begin
  761. Result:=StrNew(Pchar(Self.Text));
  762. end;
  763. Function TStrings.DoCompareText(const s1,s2 : string) : PtrInt;
  764. begin
  765. result:=CompareText(s1,s2);
  766. end;
  767. Function TStrings.IndexOf(const S: string): Integer;
  768. begin
  769. Result:=0;
  770. While (Result<Count) and (DoCompareText(Strings[Result],S)<>0) do Result:=Result+1;
  771. if Result=Count then Result:=-1;
  772. end;
  773. Function TStrings.IndexOfName(const Name: string): Integer;
  774. Var
  775. len : longint;
  776. S : String;
  777. begin
  778. CheckSpecialChars;
  779. Result:=0;
  780. while (Result<Count) do
  781. begin
  782. S:=Strings[Result];
  783. len:=pos(FNameValueSeparator,S)-1;
  784. if (len>=0) and (DoCompareText(Name,Copy(S,1,Len))=0) then
  785. exit;
  786. inc(result);
  787. end;
  788. result:=-1;
  789. end;
  790. Function TStrings.IndexOfObject(AObject: TObject): Integer;
  791. begin
  792. Result:=0;
  793. While (Result<count) and (Objects[Result]<>AObject) do Result:=Result+1;
  794. If Result=Count then Result:=-1;
  795. end;
  796. Procedure TStrings.InsertObject(Index: Integer; const S: string;
  797. AObject: TObject);
  798. begin
  799. Insert (Index,S);
  800. Objects[Index]:=AObject;
  801. end;
  802. Procedure TStrings.LoadFromFile(const FileName: string);
  803. begin
  804. LoadFromFile(FileName,False)
  805. end;
  806. Procedure TStrings.LoadFromFile(const FileName: string; IgnoreEncoding : Boolean);
  807. Var
  808. TheStream : TFileStream;
  809. begin
  810. TheStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
  811. try
  812. LoadFromStream(TheStream, IgnoreEncoding);
  813. finally
  814. TheStream.Free;
  815. end;
  816. end;
  817. Procedure TStrings.LoadFromFile(const FileName: string; AEncoding: TEncoding);
  818. Var
  819. TheStream : TFileStream;
  820. begin
  821. TheStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
  822. try
  823. LoadFromStream(TheStream,AEncoding);
  824. finally
  825. TheStream.Free;
  826. end;
  827. end;
  828. Procedure TStrings.LoadFromStream(Stream: TStream);
  829. begin
  830. LoadFromStream(Stream,False);
  831. end;
  832. Procedure TStrings.LoadFromStream(Stream: TStream; IgnoreEncoding : Boolean);
  833. {
  834. Borlands method is no good, since a pipe for
  835. instance doesn't have a size.
  836. So we must do it the hard way.
  837. }
  838. Const
  839. BufSize = 1024;
  840. MaxGrow = 1 shl 29;
  841. Var
  842. Buffer : AnsiString;
  843. BytesRead,
  844. BufLen,
  845. I,BufDelta : SizeInt;
  846. begin
  847. if not IgnoreEncoding then
  848. begin
  849. LoadFromStream(Stream,Nil);
  850. Exit;
  851. end;
  852. // reread into a buffer
  853. beginupdate;
  854. try
  855. Buffer:='';
  856. BufLen:=0;
  857. I:=1;
  858. Repeat
  859. BufDelta:=BufSize*I;
  860. SetLength(Buffer,BufLen+BufDelta);
  861. BytesRead:=Stream.Read(Buffer[BufLen+1],BufDelta);
  862. inc(BufLen,BufDelta);
  863. If I<MaxGrow then
  864. I:=I shl 1;
  865. Until BytesRead<>BufDelta;
  866. SetLength(Buffer, BufLen-BufDelta+BytesRead);
  867. SetTextStr(Buffer);
  868. SetLength(Buffer,0);
  869. finally
  870. EndUpdate;
  871. end;
  872. end;
  873. Procedure TStrings.LoadFromStream(Stream: TStream; AEncoding: TEncoding);
  874. {
  875. Borlands method is no good, since a pipe for
  876. instance doesn't have a size.
  877. So we must do it the hard way.
  878. }
  879. Const
  880. BufSize = 1024;
  881. MaxGrow = 1 shl 29;
  882. Var
  883. Buffer : TBytes;
  884. T : string;
  885. BytesRead,
  886. BufLen,
  887. I,BufDelta: SizeInt;
  888. PreambleLength : Longint;
  889. begin
  890. // reread into a buffer
  891. beginupdate;
  892. try
  893. SetLength(Buffer,0);
  894. BufLen:=0;
  895. I:=1;
  896. Repeat
  897. BufDelta:=BufSize*I;
  898. SetLength(Buffer,BufLen+BufDelta);
  899. BytesRead:=Stream.Read(Buffer[BufLen],BufDelta);
  900. inc(BufLen,BufDelta);
  901. If I<MaxGrow then
  902. I:=I shl 1;
  903. Until BytesRead<>BufDelta;
  904. SetLength(Buffer,BufLen-BufDelta+BytesRead);
  905. PreambleLength:=TEncoding.GetBufferEncoding(Buffer,AEncoding,FDefaultEncoding);
  906. T:=AEncoding.GetAnsiString(Buffer,PreambleLength,Length(Buffer)-PreambleLength);
  907. SetEncoding(AEncoding);
  908. SetLength(Buffer,0);
  909. SetTextStr(T);
  910. finally
  911. EndUpdate;
  912. end;
  913. end;
  914. Procedure TStrings.Move(CurIndex, NewIndex: Integer);
  915. Var
  916. Obj : TObject;
  917. Str : String;
  918. begin
  919. BeginUpdate;
  920. Try
  921. Obj:=Objects[CurIndex];
  922. Str:=Strings[CurIndex];
  923. Objects[CurIndex]:=Nil; // Prevent Delete from freeing.
  924. Delete(Curindex);
  925. InsertObject(NewIndex,Str,Obj);
  926. finally
  927. EndUpdate;
  928. end;
  929. end;
  930. Procedure TStrings.SaveToFile(const FileName: string);
  931. Var TheStream : TFileStream;
  932. begin
  933. TheStream:=TFileStream.Create(FileName,fmCreate);
  934. try
  935. SaveToStream(TheStream);
  936. finally
  937. TheStream.Free;
  938. end;
  939. end;
  940. Procedure TStrings.SaveToFile(const FileName: string; AEncoding: TEncoding);
  941. Var TheStream : TFileStream;
  942. begin
  943. TheStream:=TFileStream.Create(FileName,fmCreate);
  944. try
  945. SaveToStream(TheStream,AEncoding);
  946. finally
  947. TheStream.Free;
  948. end;
  949. end;
  950. Procedure TStrings.SaveToStream(Stream: TStream);
  951. Var
  952. S : String;
  953. begin
  954. if Encoding<>nil then
  955. SaveToStream(Stream,Encoding)
  956. else
  957. begin
  958. S:=Text;
  959. if S = '' then Exit;
  960. Stream.WriteBuffer(Pointer(S)^,Length(S));
  961. end;
  962. end;
  963. Procedure TStrings.SaveToStream(Stream: TStream; AEncoding: TEncoding);
  964. Var B : TBytes;
  965. begin
  966. if AEncoding=nil then
  967. AEncoding:=FDefaultEncoding;
  968. if FWriteBOM then
  969. begin
  970. B:=AEncoding.GetPreamble;
  971. if Length(B)>0 then
  972. Stream.WriteBuffer(B[0],Length(B));
  973. end;
  974. B:=AEncoding.GetAnsiBytes(Text);
  975. if Length(B)>0 then
  976. Stream.WriteBuffer(B[0],Length(B));
  977. end;
  978. Procedure TStrings.SetText(TheText: PChar);
  979. Var S : String;
  980. begin
  981. If TheText<>Nil then
  982. S:=StrPas(TheText)
  983. else
  984. S:='';
  985. SetTextStr(S);
  986. end;
  987. {****************************************************************************}
  988. {* TStringList *}
  989. {****************************************************************************}
  990. {$if not defined(FPC_TESTGENERICS)}
  991. procedure TStringList.ExchangeItemsInt(Index1, Index2: Integer);
  992. Var P1,P2 : Pointer;
  993. begin
  994. P1:=Pointer(Flist^[Index1].FString);
  995. P2:=Pointer(Flist^[Index1].FObject);
  996. Pointer(Flist^[Index1].Fstring):=Pointer(Flist^[Index2].Fstring);
  997. Pointer(Flist^[Index1].FObject):=Pointer(Flist^[Index2].FObject);
  998. Pointer(Flist^[Index2].Fstring):=P1;
  999. Pointer(Flist^[Index2].FObject):=P2;
  1000. end;
  1001. function TStringList.GetSorted: Boolean;
  1002. begin
  1003. Result:=FSortStyle in [sslUser,sslAuto];
  1004. end;
  1005. procedure TStringList.ExchangeItems(Index1, Index2: Integer);
  1006. begin
  1007. ExchangeItemsInt(Index1, Index2);
  1008. end;
  1009. procedure TStringList.Grow;
  1010. Var
  1011. NC : Integer;
  1012. begin
  1013. NC:=FCapacity;
  1014. If NC>=256 then
  1015. NC:=NC+(NC Div 4)
  1016. else if NC=0 then
  1017. NC:=4
  1018. else
  1019. NC:=NC*4;
  1020. SetCapacity(NC);
  1021. end;
  1022. procedure TStringList.InternalClear(FromIndex: Integer; ClearOnly: Boolean);
  1023. Var
  1024. I: Integer;
  1025. begin
  1026. if FromIndex < FCount then
  1027. begin
  1028. if FOwnsObjects then
  1029. begin
  1030. For I:=FromIndex to FCount-1 do
  1031. begin
  1032. Flist^[I].FString:='';
  1033. freeandnil(Flist^[i].FObject);
  1034. end;
  1035. end
  1036. else
  1037. begin
  1038. For I:=FromIndex to FCount-1 do
  1039. Flist^[I].FString:='';
  1040. end;
  1041. FCount:=FromIndex;
  1042. end;
  1043. if Not ClearOnly then
  1044. SetCapacity(0);
  1045. end;
  1046. procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare
  1047. );
  1048. var
  1049. Pivot, vL, vR: Integer;
  1050. ExchangeProc: procedure(Left, Right: Integer) of object;
  1051. begin
  1052. //if ExchangeItems is override call that, else call (faster) ExchangeItemsInt
  1053. if TMethod(@Self.ExchangeItems).Code = CodePointer(@TStringList.ExchangeItems) then
  1054. ExchangeProc := @ExchangeItemsInt
  1055. else
  1056. ExchangeProc := @ExchangeItems;
  1057. if R - L <= 1 then begin // a little bit of time saver
  1058. if L < R then
  1059. if CompareFn(Self, L, R) > 0 then
  1060. ExchangeProc(L, R);
  1061. Exit;
  1062. end;
  1063. vL := L;
  1064. vR := R;
  1065. Pivot := L + Random(R - L); // they say random is best
  1066. while vL < vR do begin
  1067. while (vL < Pivot) and (CompareFn(Self, vL, Pivot) <= 0) do
  1068. Inc(vL);
  1069. while (vR > Pivot) and (CompareFn(Self, vR, Pivot) > 0) do
  1070. Dec(vR);
  1071. ExchangeProc(vL, vR);
  1072. if Pivot = vL then // swap pivot if we just hit it from one side
  1073. Pivot := vR
  1074. else if Pivot = vR then
  1075. Pivot := vL;
  1076. end;
  1077. if Pivot - 1 >= L then
  1078. QuickSort(L, Pivot - 1, CompareFn);
  1079. if Pivot + 1 <= R then
  1080. QuickSort(Pivot + 1, R, CompareFn);
  1081. end;
  1082. procedure TStringList.InsertItem(Index: Integer; const S: string);
  1083. begin
  1084. InsertItem(Index, S, nil);
  1085. end;
  1086. procedure TStringList.InsertItem(Index: Integer; const S: string; O: TObject);
  1087. begin
  1088. Changing;
  1089. If FCount=Fcapacity then Grow;
  1090. If Index<FCount then
  1091. System.Move (FList^[Index],FList^[Index+1],
  1092. (FCount-Index)*SizeOf(TStringItem));
  1093. Pointer(Flist^[Index].Fstring):=Nil; // Needed to initialize...
  1094. Flist^[Index].FString:=S;
  1095. Flist^[Index].FObject:=O;
  1096. Inc(FCount);
  1097. Changed;
  1098. end;
  1099. procedure TStringList.SetSorted(Value: Boolean);
  1100. begin
  1101. If Value then
  1102. SortStyle:=sslAuto
  1103. else
  1104. SortStyle:=sslNone
  1105. end;
  1106. procedure TStringList.Changed;
  1107. begin
  1108. If (FUpdateCount=0) Then
  1109. begin
  1110. If Assigned(FOnChange) then
  1111. FOnchange(Self);
  1112. FPONotifyObservers(Self,ooChange,Nil);
  1113. end;
  1114. end;
  1115. procedure TStringList.Changing;
  1116. begin
  1117. If FUpdateCount=0 then
  1118. if Assigned(FOnChanging) then
  1119. FOnchanging(Self);
  1120. end;
  1121. function TStringList.Get(Index: Integer): string;
  1122. begin
  1123. CheckIndex(Index);
  1124. Result:=Flist^[Index].FString;
  1125. end;
  1126. function TStringList.GetCapacity: Integer;
  1127. begin
  1128. Result:=FCapacity;
  1129. end;
  1130. function TStringList.GetCount: Integer;
  1131. begin
  1132. Result:=FCount;
  1133. end;
  1134. function TStringList.GetObject(Index: Integer): TObject;
  1135. begin
  1136. CheckIndex(Index);
  1137. Result:=Flist^[Index].FObject;
  1138. end;
  1139. procedure TStringList.Put(Index: Integer; const S: string);
  1140. begin
  1141. If Sorted then
  1142. Error(SSortedListError,0);
  1143. CheckIndex(Index);
  1144. Changing;
  1145. Flist^[Index].FString:=S;
  1146. Changed;
  1147. end;
  1148. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1149. begin
  1150. CheckIndex(Index);
  1151. Changing;
  1152. Flist^[Index].FObject:=AObject;
  1153. Changed;
  1154. end;
  1155. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1156. Var NewList : Pointer;
  1157. MSize : Longint;
  1158. begin
  1159. If (NewCapacity<0) then
  1160. Error (SListCapacityError,NewCapacity);
  1161. If NewCapacity>FCapacity then
  1162. begin
  1163. GetMem (NewList,NewCapacity*SizeOf(TStringItem));
  1164. If NewList=Nil then
  1165. Error (SListCapacityError,NewCapacity);
  1166. If Assigned(FList) then
  1167. begin
  1168. MSize:=FCapacity*Sizeof(TStringItem);
  1169. System.Move (FList^,NewList^,MSize);
  1170. FillWord (Pchar(NewList)[MSize],(NewCapacity-FCapacity)*(SizeOf(TStringItem) div SizeOf(Word)), 0);
  1171. FreeMem (Flist,MSize);
  1172. end;
  1173. Flist:=NewList;
  1174. FCapacity:=NewCapacity;
  1175. end
  1176. else if NewCapacity<FCapacity then
  1177. begin
  1178. if NewCapacity = 0 then
  1179. begin
  1180. if FCount > 0 then
  1181. InternalClear(0,True);
  1182. FreeMem(FList);
  1183. FList := nil;
  1184. end else
  1185. begin
  1186. InternalClear(NewCapacity,True);
  1187. GetMem(NewList, NewCapacity * SizeOf(TStringItem));
  1188. System.Move(FList^, NewList^, NewCapacity * SizeOf(TStringItem));
  1189. FreeMem(FList);
  1190. FList := NewList;
  1191. end;
  1192. FCapacity:=NewCapacity;
  1193. end;
  1194. end;
  1195. procedure TStringList.SetUpdateState(Updating: Boolean);
  1196. begin
  1197. If Updating then
  1198. Changing
  1199. else
  1200. Changed
  1201. end;
  1202. destructor TStringList.Destroy;
  1203. begin
  1204. InternalClear;
  1205. Inherited destroy;
  1206. end;
  1207. function TStringList.Add(const S: string): Integer;
  1208. begin
  1209. If Not (SortStyle=sslAuto) then
  1210. Result:=FCount
  1211. else
  1212. If Find (S,Result) then
  1213. Case DUplicates of
  1214. DupIgnore : Exit;
  1215. DupError : Error(SDuplicateString,0)
  1216. end;
  1217. InsertItem (Result,S);
  1218. end;
  1219. procedure TStringList.Clear;
  1220. begin
  1221. if FCount = 0 then Exit;
  1222. Changing;
  1223. InternalClear;
  1224. Changed;
  1225. end;
  1226. procedure TStringList.Delete(Index: Integer);
  1227. begin
  1228. CheckIndex(Index);
  1229. Changing;
  1230. Flist^[Index].FString:='';
  1231. if FOwnsObjects then
  1232. FreeAndNil(Flist^[Index].FObject);
  1233. Dec(FCount);
  1234. If Index<FCount then
  1235. System.Move(Flist^[Index+1],
  1236. Flist^[Index],
  1237. (Fcount-Index)*SizeOf(TStringItem));
  1238. Changed;
  1239. end;
  1240. procedure TStringList.Exchange(Index1, Index2: Integer);
  1241. begin
  1242. CheckIndex(Index1);
  1243. CheckIndex(Index2);
  1244. Changing;
  1245. ExchangeItemsInt(Index1,Index2);
  1246. changed;
  1247. end;
  1248. procedure TStringList.SetCaseSensitive(b : boolean);
  1249. begin
  1250. if b=FCaseSensitive then
  1251. Exit;
  1252. FCaseSensitive:=b;
  1253. if FSortStyle=sslAuto then
  1254. begin
  1255. FForceSort:=True;
  1256. try
  1257. Sort;
  1258. finally
  1259. FForceSort:=False;
  1260. end;
  1261. end;
  1262. end;
  1263. procedure TStringList.SetSortStyle(AValue: TStringsSortStyle);
  1264. begin
  1265. if FSortStyle=AValue then Exit;
  1266. if (AValue=sslAuto) then
  1267. Sort;
  1268. FSortStyle:=AValue;
  1269. end;
  1270. procedure TStringList.CheckIndex(AIndex: Integer);
  1271. begin
  1272. If (AIndex<0) or (AIndex>=FCount) then
  1273. Error(SListIndexError,AIndex);
  1274. end;
  1275. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1276. begin
  1277. if FCaseSensitive then
  1278. result:=AnsiCompareStr(s1,s2)
  1279. else
  1280. result:=AnsiCompareText(s1,s2);
  1281. end;
  1282. function TStringList.CompareStrings(const s1,s2 : string) : Integer;
  1283. begin
  1284. Result := DoCompareText(s1, s2);
  1285. end;
  1286. function TStringList.Find(const S: string; out Index: Integer): Boolean;
  1287. var
  1288. L, R, I: Integer;
  1289. CompareRes: PtrInt;
  1290. begin
  1291. Result := false;
  1292. Index:=-1;
  1293. if Not Sorted then
  1294. Raise EListError.Create(SErrFindNeedsSortedList);
  1295. // Use binary search.
  1296. L := 0;
  1297. R := Count - 1;
  1298. while (L<=R) do
  1299. begin
  1300. I := L + (R - L) div 2;
  1301. CompareRes := DoCompareText(S, Flist^[I].FString);
  1302. if (CompareRes>0) then
  1303. L := I+1
  1304. else begin
  1305. R := I-1;
  1306. if (CompareRes=0) then begin
  1307. Result := true;
  1308. if (Duplicates<>dupAccept) then
  1309. L := I; // forces end of while loop
  1310. end;
  1311. end;
  1312. end;
  1313. Index := L;
  1314. end;
  1315. function TStringList.IndexOf(const S: string): Integer;
  1316. begin
  1317. If Not Sorted then
  1318. Result:=Inherited indexOf(S)
  1319. else
  1320. // faster using binary search...
  1321. If Not Find (S,Result) then
  1322. Result:=-1;
  1323. end;
  1324. procedure TStringList.Insert(Index: Integer; const S: string);
  1325. begin
  1326. If SortStyle=sslAuto then
  1327. Error (SSortedListError,0)
  1328. else
  1329. begin
  1330. If (Index<0) or (Index>FCount) then
  1331. Error(SListIndexError,Index); // Cannot use CheckIndex, because there >= FCount...
  1332. InsertItem (Index,S);
  1333. end;
  1334. end;
  1335. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1336. begin
  1337. If (FForceSort or (Not (FSortStyle=sslAuto))) and (FCount>1) then
  1338. begin
  1339. Changing;
  1340. QuickSort(0,FCount-1, CompareFn);
  1341. Changed;
  1342. end;
  1343. end;
  1344. function StringListAnsiCompare(List: TStringList; Index1, Index: Integer): Integer;
  1345. begin
  1346. Result := List.DoCompareText(List.FList^[Index1].FString,
  1347. List.FList^[Index].FString);
  1348. end;
  1349. procedure TStringList.Sort;
  1350. begin
  1351. CustomSort(@StringListAnsiCompare);
  1352. end;
  1353. {$else}
  1354. { generics based implementation of TStringList follows }
  1355. function StringListAnsiCompare(List: TStringList; Index1, Index2: Integer): Integer;
  1356. begin
  1357. Result := List.DoCompareText(List.Strings[Index1], List.Strings[Index2]);
  1358. end;
  1359. constructor TStringList.Create;
  1360. begin
  1361. inherited;
  1362. FOwnsObjects:=false;
  1363. FMap := TFPStrObjMap.Create;
  1364. FMap.OnPtrCompare := @MapPtrCompare;
  1365. FOnCompareText := @DefaultCompareText;
  1366. NameValueSeparator:='=';
  1367. CheckSpecialChars;
  1368. end;
  1369. destructor TStringList.Destroy;
  1370. begin
  1371. FMap.Free;
  1372. inherited;
  1373. end;
  1374. function TStringList.GetDuplicates: TDuplicates;
  1375. begin
  1376. Result := FMap.Duplicates;
  1377. end;
  1378. function TStringList.GetSorted: boolean;
  1379. begin
  1380. Result := FMap.Sorted;
  1381. end;
  1382. procedure TStringList.SetDuplicates(NewDuplicates: TDuplicates);
  1383. begin
  1384. FMap.Duplicates := NewDuplicates;
  1385. end;
  1386. procedure TStringList.SetSorted(NewSorted: Boolean);
  1387. begin
  1388. FMap.Sorted := NewSorted;
  1389. end;
  1390. procedure TStringList.Changed;
  1391. begin
  1392. if FUpdateCount = 0 then
  1393. if Assigned(FOnChange) then
  1394. FOnChange(Self);
  1395. end;
  1396. procedure TStringList.Changing;
  1397. begin
  1398. if FUpdateCount = 0 then
  1399. if Assigned(FOnChanging) then
  1400. FOnChanging(Self);
  1401. end;
  1402. function TStringList.Get(Index: Integer): string;
  1403. begin
  1404. Result := FMap.Keys[Index];
  1405. end;
  1406. function TStringList.GetCapacity: Integer;
  1407. begin
  1408. Result := FMap.Capacity;
  1409. end;
  1410. function TStringList.GetCount: Integer;
  1411. begin
  1412. Result := FMap.Count;
  1413. end;
  1414. function TStringList.GetObject(Index: Integer): TObject;
  1415. begin
  1416. Result := FMap.Data[Index];
  1417. end;
  1418. procedure TStringList.Put(Index: Integer; const S: string);
  1419. begin
  1420. Changing;
  1421. FMap.Keys[Index] := S;
  1422. Changed;
  1423. end;
  1424. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1425. begin
  1426. Changing;
  1427. FMap.Data[Index] := AObject;
  1428. Changed;
  1429. end;
  1430. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1431. begin
  1432. FMap.Capacity := NewCapacity;
  1433. end;
  1434. procedure TStringList.SetUpdateState(Updating: Boolean);
  1435. begin
  1436. if Updating then
  1437. Changing
  1438. else
  1439. Changed
  1440. end;
  1441. function TStringList.Add(const S: string): Integer;
  1442. begin
  1443. Result := FMap.Add(S);
  1444. end;
  1445. procedure TStringList.Clear;
  1446. begin
  1447. if FMap.Count = 0 then exit;
  1448. Changing;
  1449. FMap.Clear;
  1450. Changed;
  1451. end;
  1452. procedure TStringList.Delete(Index: Integer);
  1453. begin
  1454. if (Index < 0) or (Index >= FMap.Count) then
  1455. Error(SListIndexError, Index);
  1456. Changing;
  1457. FMap.Delete(Index);
  1458. Changed;
  1459. end;
  1460. procedure TStringList.Exchange(Index1, Index2: Integer);
  1461. begin
  1462. if (Index1 < 0) or (Index1 >= FMap.Count) then
  1463. Error(SListIndexError, Index1);
  1464. if (Index2 < 0) or (Index2 >= FMap.Count) then
  1465. Error(SListIndexError, Index2);
  1466. Changing;
  1467. FMap.InternalExchange(Index1, Index2);
  1468. Changed;
  1469. end;
  1470. procedure TStringList.SetCaseSensitive(NewSensitive: Boolean);
  1471. begin
  1472. if NewSensitive <> FCaseSensitive then
  1473. begin
  1474. FCaseSensitive := NewSensitive;
  1475. if Sorted then
  1476. Sort;
  1477. end;
  1478. end;
  1479. function TStringList.MapPtrCompare(Key1, Key2: Pointer): Integer;
  1480. begin
  1481. Result := FOnCompareText(string(Key1^), string(Key2^));
  1482. end;
  1483. function TStringList.DefaultCompareText(const s1, s2: string): PtrInt;
  1484. begin
  1485. if FCaseSensitive then
  1486. Result := AnsiCompareStr(s1, s2)
  1487. else
  1488. Result := AnsiCompareText(s1, s2);
  1489. end;
  1490. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1491. begin
  1492. Result := FOnCompareText(s1, s2);
  1493. end;
  1494. function TStringList.Find(const S: string; var Index: Integer): Boolean;
  1495. begin
  1496. Result := FMap.Find(S, Index);
  1497. end;
  1498. function TStringList.IndexOf(const S: string): Integer;
  1499. begin
  1500. Result := FMap.IndexOf(S);
  1501. end;
  1502. procedure TStringList.Insert(Index: Integer; const S: string);
  1503. begin
  1504. if not Sorted and (0 <= Index) and (Index < FMap.Count) then
  1505. Changing;
  1506. FMap.InsertKey(Index, S);
  1507. Changed;
  1508. end;
  1509. procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  1510. var
  1511. I, J, Pivot: Integer;
  1512. begin
  1513. repeat
  1514. I := L;
  1515. J := R;
  1516. Pivot := (L + R) div 2;
  1517. repeat
  1518. while CompareFn(Self, I, Pivot) < 0 do Inc(I);
  1519. while CompareFn(Self, J, Pivot) > 0 do Dec(J);
  1520. if I <= J then
  1521. begin
  1522. FMap.InternalExchange(I, J); // No check, indices are correct.
  1523. if Pivot = I then
  1524. Pivot := J
  1525. else if Pivot = J then
  1526. Pivot := I;
  1527. Inc(I);
  1528. Dec(j);
  1529. end;
  1530. until I > J;
  1531. if L < J then
  1532. QuickSort(L,J, CompareFn);
  1533. L := I;
  1534. until I >= R;
  1535. end;
  1536. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1537. begin
  1538. if not Sorted and (FMap.Count > 1) then
  1539. begin
  1540. Changing;
  1541. QuickSort(0, FMap.Count-1, CompareFn);
  1542. Changed;
  1543. end;
  1544. end;
  1545. procedure TStringList.Sort;
  1546. begin
  1547. if not Sorted and (FMap.Count > 1) then
  1548. begin
  1549. Changing;
  1550. FMap.Sort;
  1551. Changed;
  1552. end;
  1553. end;
  1554. {$endif}