stringl.inc 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602
  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; Quote : String) : String;
  35. Var
  36. I,J : Integer;
  37. begin
  38. J:=0;
  39. Result:=S;
  40. for i:=1to 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. FSpecialCharsInited:=true;
  64. FLBS:=DefaultTextLineBreakStyle;
  65. end;
  66. end;
  67. Function TStrings.GetLBS : TTextLineBreakStyle;
  68. begin
  69. CheckSpecialChars;
  70. Result:=FLBS;
  71. end;
  72. Procedure TStrings.SetLBS (AValue : TTextLineBreakStyle);
  73. begin
  74. CheckSpecialChars;
  75. FLBS:=AValue;
  76. end;
  77. procedure TStrings.SetDelimiter(c:Char);
  78. begin
  79. CheckSpecialChars;
  80. FDelimiter:=c;
  81. end;
  82. procedure TStrings.SetQuoteChar(c:Char);
  83. begin
  84. CheckSpecialChars;
  85. FQuoteChar:=c;
  86. end;
  87. procedure TStrings.SetNameValueSeparator(c:Char);
  88. begin
  89. CheckSpecialChars;
  90. FNameValueSeparator:=c;
  91. end;
  92. function TStrings.GetCommaText: string;
  93. Var
  94. C1,C2 : Char;
  95. FSD : Boolean;
  96. begin
  97. CheckSpecialChars;
  98. FSD:=StrictDelimiter;
  99. C1:=Delimiter;
  100. C2:=QuoteChar;
  101. Delimiter:=',';
  102. QuoteChar:='"';
  103. StrictDelimiter:=False;
  104. Try
  105. Result:=GetDelimitedText;
  106. Finally
  107. Delimiter:=C1;
  108. QuoteChar:=C2;
  109. StrictDelimiter:=FSD;
  110. end;
  111. end;
  112. Function TStrings.GetDelimitedText: string;
  113. Var
  114. I : integer;
  115. p : pchar;
  116. BreakChars : set of char;
  117. S : String;
  118. begin
  119. CheckSpecialChars;
  120. result:='';
  121. if StrictDelimiter then
  122. BreakChars:=[#0,QuoteChar,Delimiter]
  123. else
  124. BreakChars:=[#0..' ',QuoteChar,Delimiter];
  125. // Check for break characters and quote if required.
  126. For i:=0 to count-1 do
  127. begin
  128. S:=Strings[i];
  129. p:=pchar(S);
  130. //Quote strings that include BreakChars:
  131. while not(p^ in BreakChars) do
  132. inc(p);
  133. if (p<>pchar(S)+length(S)) then
  134. Result:=Result+QuoteString(S,QuoteChar)
  135. else
  136. Result:=Result+S;
  137. if I<Count-1 then
  138. Result:=Result+Delimiter;
  139. end;
  140. // Quote empty string:
  141. If (Length(Result)=0) and (Count=1) then
  142. Result:=QuoteChar+QuoteChar;
  143. end;
  144. procedure TStrings.GetNameValue(Index : Integer; Out AName,AValue : String);
  145. Var L : longint;
  146. begin
  147. CheckSpecialChars;
  148. AValue:=Strings[Index];
  149. L:=Pos(FNameValueSeparator,AValue);
  150. If L<>0 then
  151. begin
  152. AName:=Copy(AValue,1,L-1);
  153. System.Delete(AValue,1,L);
  154. end
  155. else
  156. AName:='';
  157. end;
  158. function TStrings.ExtractName(const s:String):String;
  159. var
  160. L: Longint;
  161. begin
  162. CheckSpecialChars;
  163. L:=Pos(FNameValueSeparator,S);
  164. If L<>0 then
  165. Result:=Copy(S,1,L-1)
  166. else
  167. Result:='';
  168. end;
  169. function TStrings.GetName(Index: Integer): string;
  170. Var
  171. V : String;
  172. begin
  173. GetNameValue(Index,Result,V);
  174. end;
  175. Function TStrings.GetValue(const Name: string): string;
  176. Var
  177. L : longint;
  178. N : String;
  179. begin
  180. Result:='';
  181. L:=IndexOfName(Name);
  182. If L<>-1 then
  183. GetNameValue(L,N,Result);
  184. end;
  185. Function TStrings.GetValueFromIndex(Index: Integer): string;
  186. Var
  187. N : String;
  188. begin
  189. GetNameValue(Index,N,Result);
  190. end;
  191. Procedure TStrings.SetValueFromIndex(Index: Integer; const Value: string);
  192. begin
  193. If (Value='') then
  194. Delete(Index)
  195. else
  196. begin
  197. If (Index<0) then
  198. Index:=Add('');
  199. CheckSpecialChars;
  200. Strings[Index]:=GetName(Index)+FNameValueSeparator+Value;
  201. end;
  202. end;
  203. procedure TStrings.ReadData(Reader: TReader);
  204. begin
  205. Reader.ReadListBegin;
  206. BeginUpdate;
  207. try
  208. Clear;
  209. while not Reader.EndOfList do
  210. Add(Reader.ReadString);
  211. finally
  212. EndUpdate;
  213. end;
  214. Reader.ReadListEnd;
  215. end;
  216. Procedure TStrings.SetDelimitedText(const AValue: string);
  217. var i,j:integer;
  218. aNotFirst:boolean;
  219. begin
  220. CheckSpecialChars;
  221. BeginUpdate;
  222. i:=1;
  223. j:=1;
  224. aNotFirst:=false;
  225. { Paraphrased from Delphi XE2 help:
  226. Strings must be separated by Delimiter characters or spaces.
  227. They may be enclosed in QuoteChars.
  228. QuoteChars in the string must be repeated to distinguish them from the QuoteChars enclosing the string.
  229. }
  230. try
  231. Clear;
  232. If StrictDelimiter then
  233. begin
  234. while i<=length(AValue) do begin
  235. // skip delimiter
  236. if aNotFirst and (i<=length(AValue)) and (AValue[i]=FDelimiter) then inc(i);
  237. // read next string
  238. if i<=length(AValue) then begin
  239. if AValue[i]=FQuoteChar then begin
  240. // next string is quoted
  241. j:=i+1;
  242. while (j<=length(AValue)) and
  243. ( (AValue[j]<>FQuoteChar) or
  244. ( (j+1<=length(AValue)) and (AValue[j+1]=FQuoteChar) ) ) do begin
  245. if (j<=length(AValue)) and (AValue[j]=FQuoteChar) then inc(j,2)
  246. else inc(j);
  247. end;
  248. // j is position of closing quote
  249. Add( StringReplace (Copy(AValue,i+1,j-i-1),
  250. FQuoteChar+FQuoteChar,FQuoteChar, [rfReplaceAll]));
  251. i:=j+1;
  252. end else begin
  253. // next string is not quoted; read until delimiter
  254. j:=i;
  255. while (j<=length(AValue)) and
  256. (AValue[j]<>FDelimiter) do inc(j);
  257. Add( Copy(AValue,i,j-i));
  258. i:=j;
  259. end;
  260. end else begin
  261. if aNotFirst then Add('');
  262. end;
  263. aNotFirst:=true;
  264. end;
  265. end
  266. else
  267. begin
  268. while i<=length(AValue) do begin
  269. // skip delimiter
  270. if aNotFirst and (i<=length(AValue)) and (AValue[i]=FDelimiter) then inc(i);
  271. // skip spaces
  272. while (i<=length(AValue)) and (Ord(AValue[i])<=Ord(' ')) do inc(i);
  273. // read next string
  274. if i<=length(AValue) then begin
  275. if AValue[i]=FQuoteChar then begin
  276. // next string is quoted
  277. j:=i+1;
  278. while (j<=length(AValue)) and
  279. ( (AValue[j]<>FQuoteChar) or
  280. ( (j+1<=length(AValue)) and (AValue[j+1]=FQuoteChar) ) ) do begin
  281. if (j<=length(AValue)) and (AValue[j]=FQuoteChar) then inc(j,2)
  282. else inc(j);
  283. end;
  284. // j is position of closing quote
  285. Add( StringReplace (Copy(AValue,i+1,j-i-1),
  286. FQuoteChar+FQuoteChar,FQuoteChar, [rfReplaceAll]));
  287. i:=j+1;
  288. end else begin
  289. // next string is not quoted; read until control character/space/delimiter
  290. j:=i;
  291. while (j<=length(AValue)) and
  292. (Ord(AValue[j])>Ord(' ')) and
  293. (AValue[j]<>FDelimiter) do inc(j);
  294. Add( Copy(AValue,i,j-i));
  295. i:=j;
  296. end;
  297. end else begin
  298. if aNotFirst then Add('');
  299. end;
  300. // skip spaces
  301. while (i<=length(AValue)) and (Ord(AValue[i])<=Ord(' ')) do inc(i);
  302. aNotFirst:=true;
  303. end;
  304. end;
  305. finally
  306. EndUpdate;
  307. end;
  308. end;
  309. Procedure TStrings.SetCommaText(const Value: string);
  310. Var
  311. C1,C2 : Char;
  312. begin
  313. CheckSpecialChars;
  314. C1:=Delimiter;
  315. C2:=QuoteChar;
  316. Delimiter:=',';
  317. QuoteChar:='"';
  318. Try
  319. SetDelimitedText(Value);
  320. Finally
  321. Delimiter:=C1;
  322. QuoteChar:=C2;
  323. end;
  324. end;
  325. Procedure TStrings.SetStringsAdapter(const Value: IStringsAdapter);
  326. begin
  327. end;
  328. Procedure TStrings.SetValue(const Name, Value: string);
  329. Var L : longint;
  330. begin
  331. CheckSpecialChars;
  332. L:=IndexOfName(Name);
  333. if L=-1 then
  334. Add (Name+FNameValueSeparator+Value)
  335. else
  336. Strings[L]:=Name+FNameValueSeparator+value;
  337. end;
  338. procedure TStrings.WriteData(Writer: TWriter);
  339. var
  340. i: Integer;
  341. begin
  342. Writer.WriteListBegin;
  343. for i := 0 to Count - 1 do
  344. Writer.WriteString(Strings[i]);
  345. Writer.WriteListEnd;
  346. end;
  347. procedure TStrings.DefineProperties(Filer: TFiler);
  348. var
  349. HasData: Boolean;
  350. begin
  351. if Assigned(Filer.Ancestor) then
  352. // Only serialize if string list is different from ancestor
  353. if Filer.Ancestor.InheritsFrom(TStrings) then
  354. HasData := not Equals(TStrings(Filer.Ancestor))
  355. else
  356. HasData := True
  357. else
  358. HasData := Count > 0;
  359. Filer.DefineProperty('Strings', @ReadData, @WriteData, HasData);
  360. end;
  361. Procedure TStrings.Error(const Msg: string; Data: Integer);
  362. begin
  363. Raise EStringListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  364. end;
  365. Procedure TStrings.Error(const Msg: pstring; Data: Integer);
  366. begin
  367. Raise EStringListError.CreateFmt(Msg^,[Data]) at get_caller_addr(get_frame), get_caller_frame(get_frame);
  368. end;
  369. Function TStrings.GetCapacity: Integer;
  370. begin
  371. Result:=Count;
  372. end;
  373. Function TStrings.GetObject(Index: Integer): TObject;
  374. begin
  375. Result:=Nil;
  376. end;
  377. Function TStrings.GetTextStr: string;
  378. Var P : Pchar;
  379. I,L,NLS : Longint;
  380. S,NL : String;
  381. begin
  382. CheckSpecialChars;
  383. // Determine needed place
  384. Case FLBS of
  385. tlbsLF : NL:=#10;
  386. tlbsCRLF : NL:=#13#10;
  387. tlbsCR : NL:=#13;
  388. end;
  389. L:=0;
  390. NLS:=Length(NL);
  391. For I:=0 to count-1 do
  392. L:=L+Length(Strings[I])+NLS;
  393. Setlength(Result,L);
  394. P:=Pointer(Result);
  395. For i:=0 To count-1 do
  396. begin
  397. S:=Strings[I];
  398. L:=Length(S);
  399. if L<>0 then
  400. System.Move(Pointer(S)^,P^,L);
  401. P:=P+L;
  402. For L:=1 to NLS do
  403. begin
  404. P^:=NL[L];
  405. inc(P);
  406. end;
  407. end;
  408. end;
  409. Procedure TStrings.Put(Index: Integer; const S: string);
  410. Var Obj : TObject;
  411. begin
  412. Obj:=Objects[Index];
  413. Delete(Index);
  414. InsertObject(Index,S,Obj);
  415. end;
  416. Procedure TStrings.PutObject(Index: Integer; AObject: TObject);
  417. begin
  418. // Empty.
  419. end;
  420. Procedure TStrings.SetCapacity(NewCapacity: Integer);
  421. begin
  422. // Empty.
  423. end;
  424. Function GetNextLine (Const Value : String; Var S : String; Var P : Integer) : Boolean;
  425. Var
  426. PS : PChar;
  427. IP,L : Integer;
  428. begin
  429. L:=Length(Value);
  430. S:='';
  431. Result:=False;
  432. If ((L-P)<0) then
  433. exit;
  434. if ((L-P)=0) and (not (value[P] in [#10,#13])) Then
  435. Begin
  436. s:=value[P];
  437. inc(P);
  438. Exit(True);
  439. End;
  440. PS:=PChar(Value)+P-1;
  441. IP:=P;
  442. While ((L-P)>=0) and (not (PS^ in [#10,#13])) do
  443. begin
  444. P:=P+1;
  445. Inc(PS);
  446. end;
  447. SetLength (S,P-IP);
  448. System.Move (Value[IP],Pointer(S)^,P-IP);
  449. If (P<=L) and (Value[P]=#13) then
  450. Inc(P);
  451. If (P<=L) and (Value[P]=#10) then
  452. Inc(P); // Point to character after #10(#13)
  453. Result:=True;
  454. end;
  455. Procedure TStrings.DoSetTextStr(const Value: string; DoClear : Boolean);
  456. Var
  457. S : String;
  458. P : Integer;
  459. begin
  460. Try
  461. beginUpdate;
  462. if DoClear then
  463. Clear;
  464. P:=1;
  465. While GetNextLine (Value,S,P) do
  466. Add(S);
  467. finally
  468. EndUpdate;
  469. end;
  470. end;
  471. Procedure TStrings.SetTextStr(const Value: string);
  472. begin
  473. DoSetTextStr(Value,True);
  474. end;
  475. Procedure TStrings.AddText(const S: string);
  476. begin
  477. DoSetTextStr(S,False);
  478. end;
  479. Procedure TStrings.SetUpdateState(Updating: Boolean);
  480. begin
  481. FPONotifyObservers(Self,ooChange,Nil);
  482. end;
  483. destructor TSTrings.Destroy;
  484. begin
  485. inherited destroy;
  486. end;
  487. Function TStrings.Add(const S: string): Integer;
  488. begin
  489. Result:=Count;
  490. Insert (Count,S);
  491. end;
  492. Function TStrings.AddObject(const S: string; AObject: TObject): Integer;
  493. begin
  494. Result:=Add(S);
  495. Objects[result]:=AObject;
  496. end;
  497. Procedure TStrings.Append(const S: string);
  498. begin
  499. Add (S);
  500. end;
  501. Procedure TStrings.AddStrings(TheStrings: TStrings);
  502. Var Runner : longint;
  503. begin
  504. try
  505. beginupdate;
  506. For Runner:=0 to TheStrings.Count-1 do
  507. self.AddObject (Thestrings[Runner],TheStrings.Objects[Runner]);
  508. finally
  509. EndUpdate;
  510. end;
  511. end;
  512. Procedure TStrings.AddStrings(const TheStrings: array of string);
  513. Var Runner : longint;
  514. begin
  515. try
  516. beginupdate;
  517. if Count + High(TheStrings)+1 > Capacity then
  518. Capacity := Count + High(TheStrings)+1;
  519. For Runner:=Low(TheStrings) to High(TheStrings) do
  520. self.Add(Thestrings[Runner]);
  521. finally
  522. EndUpdate;
  523. end;
  524. end;
  525. Procedure TStrings.Assign(Source: TPersistent);
  526. Var
  527. S : TStrings;
  528. begin
  529. If Source is TStrings then
  530. begin
  531. S:=TStrings(Source);
  532. BeginUpdate;
  533. Try
  534. clear;
  535. FSpecialCharsInited:=S.FSpecialCharsInited;
  536. FQuoteChar:=S.FQuoteChar;
  537. FDelimiter:=S.FDelimiter;
  538. FNameValueSeparator:=S.FNameValueSeparator;
  539. FLBS:=S.FLBS;
  540. AddStrings(S);
  541. finally
  542. EndUpdate;
  543. end;
  544. end
  545. else
  546. Inherited Assign(Source);
  547. end;
  548. Procedure TStrings.BeginUpdate;
  549. begin
  550. if FUpdateCount = 0 then SetUpdateState(true);
  551. inc(FUpdateCount);
  552. end;
  553. Procedure TStrings.EndUpdate;
  554. begin
  555. If FUpdateCount>0 then
  556. Dec(FUpdateCount);
  557. if FUpdateCount=0 then
  558. SetUpdateState(False);
  559. end;
  560. Function TStrings.Equals(Obj: TObject): Boolean;
  561. begin
  562. if Obj is TStrings then
  563. Result := Equals(TStrings(Obj))
  564. else
  565. Result := inherited Equals(Obj);
  566. end;
  567. Function TStrings.Equals(TheStrings: TStrings): Boolean;
  568. Var Runner,Nr : Longint;
  569. begin
  570. Result:=False;
  571. Nr:=Self.Count;
  572. if Nr<>TheStrings.Count then exit;
  573. For Runner:=0 to Nr-1 do
  574. If Strings[Runner]<>TheStrings[Runner] then exit;
  575. Result:=True;
  576. end;
  577. Procedure TStrings.Exchange(Index1, Index2: Integer);
  578. Var
  579. Obj : TObject;
  580. Str : String;
  581. begin
  582. Try
  583. beginUpdate;
  584. Obj:=Objects[Index1];
  585. Str:=Strings[Index1];
  586. Objects[Index1]:=Objects[Index2];
  587. Strings[Index1]:=Strings[Index2];
  588. Objects[Index2]:=Obj;
  589. Strings[Index2]:=Str;
  590. finally
  591. EndUpdate;
  592. end;
  593. end;
  594. function TStrings.GetEnumerator: TStringsEnumerator;
  595. begin
  596. Result:=TStringsEnumerator.Create(Self);
  597. end;
  598. Function TStrings.GetText: PChar;
  599. begin
  600. Result:=StrNew(Pchar(Self.Text));
  601. end;
  602. Function TStrings.DoCompareText(const s1,s2 : string) : PtrInt;
  603. begin
  604. result:=CompareText(s1,s2);
  605. end;
  606. Function TStrings.IndexOf(const S: string): Integer;
  607. begin
  608. Result:=0;
  609. While (Result<Count) and (DoCompareText(Strings[Result],S)<>0) do Result:=Result+1;
  610. if Result=Count then Result:=-1;
  611. end;
  612. Function TStrings.IndexOfName(const Name: string): Integer;
  613. Var
  614. len : longint;
  615. S : String;
  616. begin
  617. CheckSpecialChars;
  618. Result:=0;
  619. while (Result<Count) do
  620. begin
  621. S:=Strings[Result];
  622. len:=pos(FNameValueSeparator,S)-1;
  623. if (len>=0) and (DoCompareText(Name,Copy(S,1,Len))=0) then
  624. exit;
  625. inc(result);
  626. end;
  627. result:=-1;
  628. end;
  629. Function TStrings.IndexOfObject(AObject: TObject): Integer;
  630. begin
  631. Result:=0;
  632. While (Result<count) and (Objects[Result]<>AObject) do Result:=Result+1;
  633. If Result=Count then Result:=-1;
  634. end;
  635. Procedure TStrings.InsertObject(Index: Integer; const S: string;
  636. AObject: TObject);
  637. begin
  638. Insert (Index,S);
  639. Objects[Index]:=AObject;
  640. end;
  641. Procedure TStrings.LoadFromFile(const FileName: string);
  642. Var
  643. TheStream : TFileStream;
  644. begin
  645. TheStream:=TFileStream.Create(FileName,fmOpenRead or fmShareDenyWrite);
  646. try
  647. LoadFromStream(TheStream);
  648. finally
  649. TheStream.Free;
  650. end;
  651. end;
  652. Procedure TStrings.LoadFromStream(Stream: TStream);
  653. {
  654. Borlands method is no good, since a pipe for
  655. instance doesn't have a size.
  656. So we must do it the hard way.
  657. }
  658. Const
  659. BufSize = 1024;
  660. MaxGrow = 1 shl 29;
  661. Var
  662. Buffer : AnsiString;
  663. BytesRead,
  664. BufLen,
  665. I,BufDelta : Longint;
  666. begin
  667. // reread into a buffer
  668. try
  669. beginupdate;
  670. Buffer:='';
  671. BufLen:=0;
  672. I:=1;
  673. Repeat
  674. BufDelta:=BufSize*I;
  675. SetLength(Buffer,BufLen+BufDelta);
  676. BytesRead:=Stream.Read(Buffer[BufLen+1],BufDelta);
  677. inc(BufLen,BufDelta);
  678. If I<MaxGrow then
  679. I:=I shl 1;
  680. Until BytesRead<>BufDelta;
  681. SetLength(Buffer, BufLen-BufDelta+BytesRead);
  682. SetTextStr(Buffer);
  683. SetLength(Buffer,0);
  684. finally
  685. EndUpdate;
  686. end;
  687. end;
  688. Procedure TStrings.Move(CurIndex, NewIndex: Integer);
  689. Var
  690. Obj : TObject;
  691. Str : String;
  692. begin
  693. BeginUpdate;
  694. Obj:=Objects[CurIndex];
  695. Str:=Strings[CurIndex];
  696. Objects[CurIndex]:=Nil; // Prevent Delete from freeing.
  697. Delete(Curindex);
  698. InsertObject(NewIndex,Str,Obj);
  699. EndUpdate;
  700. end;
  701. Procedure TStrings.SaveToFile(const FileName: string);
  702. Var TheStream : TFileStream;
  703. begin
  704. TheStream:=TFileStream.Create(FileName,fmCreate);
  705. try
  706. SaveToStream(TheStream);
  707. finally
  708. TheStream.Free;
  709. end;
  710. end;
  711. Procedure TStrings.SaveToStream(Stream: TStream);
  712. Var
  713. S : String;
  714. begin
  715. S:=Text;
  716. if S = '' then Exit;
  717. Stream.WriteBuffer(Pointer(S)^,Length(S));
  718. end;
  719. Procedure TStrings.SetText(TheText: PChar);
  720. Var S : String;
  721. begin
  722. If TheText<>Nil then
  723. S:=StrPas(TheText)
  724. else
  725. S:='';
  726. SetTextStr(S);
  727. end;
  728. {****************************************************************************}
  729. {* TStringList *}
  730. {****************************************************************************}
  731. {$if not defined(FPC_TESTGENERICS)}
  732. Procedure TStringList.ExchangeItems(Index1, Index2: Integer);
  733. Var P1,P2 : Pointer;
  734. begin
  735. P1:=Pointer(Flist^[Index1].FString);
  736. P2:=Pointer(Flist^[Index1].FObject);
  737. Pointer(Flist^[Index1].Fstring):=Pointer(Flist^[Index2].Fstring);
  738. Pointer(Flist^[Index1].FObject):=Pointer(Flist^[Index2].FObject);
  739. Pointer(Flist^[Index2].Fstring):=P1;
  740. Pointer(Flist^[Index2].FObject):=P2;
  741. end;
  742. Procedure TStringList.Grow;
  743. Var
  744. NC : Integer;
  745. begin
  746. NC:=FCapacity;
  747. If NC>=256 then
  748. NC:=NC+(NC Div 4)
  749. else if NC=0 then
  750. NC:=4
  751. else
  752. NC:=NC*4;
  753. SetCapacity(NC);
  754. end;
  755. Procedure TStringList.InternalClear;
  756. Var
  757. I: Integer;
  758. begin
  759. if FOwnsObjects then
  760. begin
  761. For I:=0 to FCount-1 do
  762. begin
  763. Flist^[I].FString:='';
  764. freeandnil(Flist^[i].FObject);
  765. end;
  766. end
  767. else
  768. begin
  769. For I:=0 to FCount-1 do
  770. Flist^[I].FString:='';
  771. end;
  772. FCount:=0;
  773. SetCapacity(0);
  774. end;
  775. Procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  776. var
  777. Pivot, vL, vR: Integer;
  778. begin
  779. if R - L <= 1 then begin // a little bit of time saver
  780. if L < R then
  781. if CompareFn(Self, L, R) > 0 then
  782. ExchangeItems(L, R);
  783. Exit;
  784. end;
  785. vL := L;
  786. vR := R;
  787. Pivot := L + Random(R - L); // they say random is best
  788. while vL < vR do begin
  789. while (vL < Pivot) and (CompareFn(Self, vL, Pivot) <= 0) do
  790. Inc(vL);
  791. while (vR > Pivot) and (CompareFn(Self, vR, Pivot) > 0) do
  792. Dec(vR);
  793. ExchangeItems(vL, vR);
  794. if Pivot = vL then // swap pivot if we just hit it from one side
  795. Pivot := vR
  796. else if Pivot = vR then
  797. Pivot := vL;
  798. end;
  799. if Pivot - 1 >= L then
  800. QuickSort(L, Pivot - 1, CompareFn);
  801. if Pivot + 1 <= R then
  802. QuickSort(Pivot + 1, R, CompareFn);
  803. end;
  804. Procedure TStringList.InsertItem(Index: Integer; const S: string);
  805. begin
  806. InsertItem(Index, S, nil);
  807. end;
  808. Procedure TStringList.InsertItem(Index: Integer; const S: string; O: TObject);
  809. begin
  810. Changing;
  811. If FCount=Fcapacity then Grow;
  812. If Index<FCount then
  813. System.Move (FList^[Index],FList^[Index+1],
  814. (FCount-Index)*SizeOf(TStringItem));
  815. Pointer(Flist^[Index].Fstring):=Nil; // Needed to initialize...
  816. Flist^[Index].FString:=S;
  817. Flist^[Index].FObject:=O;
  818. Inc(FCount);
  819. Changed;
  820. end;
  821. Procedure TStringList.SetSorted(Value: Boolean);
  822. begin
  823. If FSorted<>Value then
  824. begin
  825. If Value then sort;
  826. FSorted:=VAlue
  827. end;
  828. end;
  829. Procedure TStringList.Changed;
  830. begin
  831. If (FUpdateCount=0) Then
  832. begin
  833. If Assigned(FOnChange) then
  834. FOnchange(Self);
  835. FPONotifyObservers(Self,ooChange,Nil);
  836. end;
  837. end;
  838. Procedure TStringList.Changing;
  839. begin
  840. If FUpdateCount=0 then
  841. if Assigned(FOnChanging) then
  842. FOnchanging(Self);
  843. end;
  844. Function TStringList.Get(Index: Integer): string;
  845. begin
  846. If (Index<0) or (INdex>=Fcount) then
  847. Error (SListIndexError,Index);
  848. Result:=Flist^[Index].FString;
  849. end;
  850. Function TStringList.GetCapacity: Integer;
  851. begin
  852. Result:=FCapacity;
  853. end;
  854. Function TStringList.GetCount: Integer;
  855. begin
  856. Result:=FCount;
  857. end;
  858. Function TStringList.GetObject(Index: Integer): TObject;
  859. begin
  860. If (Index<0) or (INdex>=Fcount) then
  861. Error (SListIndexError,Index);
  862. Result:=Flist^[Index].FObject;
  863. end;
  864. Procedure TStringList.Put(Index: Integer; const S: string);
  865. begin
  866. If Sorted then
  867. Error(SSortedListError,0);
  868. If (Index<0) or (INdex>=Fcount) then
  869. Error (SListIndexError,Index);
  870. Changing;
  871. Flist^[Index].FString:=S;
  872. Changed;
  873. end;
  874. Procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  875. begin
  876. If (Index<0) or (INdex>=Fcount) then
  877. Error (SListIndexError,Index);
  878. Changing;
  879. Flist^[Index].FObject:=AObject;
  880. Changed;
  881. end;
  882. Procedure TStringList.SetCapacity(NewCapacity: Integer);
  883. Var NewList : Pointer;
  884. MSize : Longint;
  885. begin
  886. If (NewCapacity<0) then
  887. Error (SListCapacityError,NewCapacity);
  888. If NewCapacity>FCapacity then
  889. begin
  890. GetMem (NewList,NewCapacity*SizeOf(TStringItem));
  891. If NewList=Nil then
  892. Error (SListCapacityError,NewCapacity);
  893. If Assigned(FList) then
  894. begin
  895. MSize:=FCapacity*Sizeof(TStringItem);
  896. System.Move (FList^,NewList^,MSize);
  897. FillWord (Pchar(NewList)[MSize],(NewCapacity-FCapacity)*WordRatio, 0);
  898. FreeMem (Flist,MSize);
  899. end;
  900. Flist:=NewList;
  901. FCapacity:=NewCapacity;
  902. end
  903. else if NewCapacity<FCapacity then
  904. begin
  905. if NewCapacity = 0 then
  906. begin
  907. FreeMem(FList);
  908. FList := nil;
  909. end else
  910. begin
  911. GetMem(NewList, NewCapacity * SizeOf(TStringItem));
  912. System.Move(FList^, NewList^, NewCapacity * SizeOf(TStringItem));
  913. FreeMem(FList);
  914. FList := NewList;
  915. end;
  916. FCapacity:=NewCapacity;
  917. end;
  918. end;
  919. Procedure TStringList.SetUpdateState(Updating: Boolean);
  920. begin
  921. If Updating then
  922. Changing
  923. else
  924. Changed
  925. end;
  926. destructor TStringList.Destroy;
  927. begin
  928. InternalClear;
  929. Inherited destroy;
  930. end;
  931. Function TStringList.Add(const S: string): Integer;
  932. begin
  933. If Not Sorted then
  934. Result:=FCount
  935. else
  936. If Find (S,Result) then
  937. Case DUplicates of
  938. DupIgnore : Exit;
  939. DupError : Error(SDuplicateString,0)
  940. end;
  941. InsertItem (Result,S);
  942. end;
  943. Procedure TStringList.Clear;
  944. begin
  945. if FCount = 0 then Exit;
  946. Changing;
  947. InternalClear;
  948. Changed;
  949. end;
  950. Procedure TStringList.Delete(Index: Integer);
  951. begin
  952. If (Index<0) or (Index>=FCount) then
  953. Error(SlistINdexError,Index);
  954. Changing;
  955. Flist^[Index].FString:='';
  956. if FOwnsObjects then
  957. FreeAndNil(Flist^[Index].FObject);
  958. Dec(FCount);
  959. If Index<FCount then
  960. System.Move(Flist^[Index+1],
  961. Flist^[Index],
  962. (Fcount-Index)*SizeOf(TStringItem));
  963. Changed;
  964. end;
  965. Procedure TStringList.Exchange(Index1, Index2: Integer);
  966. begin
  967. If (Index1<0) or (Index1>=FCount) then
  968. Error(SListIndexError,Index1);
  969. If (Index2<0) or (Index2>=FCount) then
  970. Error(SListIndexError,Index2);
  971. Changing;
  972. ExchangeItems(Index1,Index2);
  973. changed;
  974. end;
  975. procedure TStringList.SetCaseSensitive(b : boolean);
  976. begin
  977. if b=FCaseSensitive then
  978. Exit;
  979. FCaseSensitive:=b;
  980. if FSorted then
  981. begin
  982. FForceSort:=True;
  983. sort;
  984. FForceSort:=False;
  985. end;
  986. end;
  987. Function TStringList.DoCompareText(const s1,s2 : string) : PtrInt;
  988. begin
  989. if FCaseSensitive then
  990. result:=AnsiCompareStr(s1,s2)
  991. else
  992. result:=AnsiCompareText(s1,s2);
  993. end;
  994. Function TStringList.Find(const S: string; Out Index: Integer): Boolean;
  995. var
  996. L, R, I: Integer;
  997. CompareRes: PtrInt;
  998. begin
  999. Result := false;
  1000. // Use binary search.
  1001. L := 0;
  1002. R := Count - 1;
  1003. while (L<=R) do
  1004. begin
  1005. I := L + (R - L) div 2;
  1006. CompareRes := DoCompareText(S, Flist^[I].FString);
  1007. if (CompareRes>0) then
  1008. L := I+1
  1009. else begin
  1010. R := I-1;
  1011. if (CompareRes=0) then begin
  1012. Result := true;
  1013. if (Duplicates<>dupAccept) then
  1014. L := I; // forces end of while loop
  1015. end;
  1016. end;
  1017. end;
  1018. Index := L;
  1019. end;
  1020. Function TStringList.IndexOf(const S: string): Integer;
  1021. begin
  1022. If Not Sorted then
  1023. Result:=Inherited indexOf(S)
  1024. else
  1025. // faster using binary search...
  1026. If Not Find (S,Result) then
  1027. Result:=-1;
  1028. end;
  1029. Procedure TStringList.Insert(Index: Integer; const S: string);
  1030. begin
  1031. If Sorted then
  1032. Error (SSortedListError,0)
  1033. else
  1034. If (Index<0) or (Index>FCount) then
  1035. Error (SListIndexError,Index)
  1036. else
  1037. InsertItem (Index,S);
  1038. end;
  1039. Procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1040. begin
  1041. If (FForceSort or (Not Sorted)) and (FCount>1) then
  1042. begin
  1043. Changing;
  1044. QuickSort(0,FCount-1, CompareFn);
  1045. Changed;
  1046. end;
  1047. end;
  1048. function StringListAnsiCompare(List: TStringList; Index1, Index: Integer): Integer;
  1049. begin
  1050. Result := List.DoCompareText(List.FList^[Index1].FString,
  1051. List.FList^[Index].FString);
  1052. end;
  1053. Procedure TStringList.Sort;
  1054. begin
  1055. CustomSort(@StringListAnsiCompare);
  1056. end;
  1057. {$else}
  1058. { generics based implementation of TStringList follows }
  1059. function StringListAnsiCompare(List: TStringList; Index1, Index2: Integer): Integer;
  1060. begin
  1061. Result := List.DoCompareText(List.Strings[Index1], List.Strings[Index2]);
  1062. end;
  1063. constructor TStringList.Create;
  1064. begin
  1065. inherited;
  1066. FOwnsObjects:=false;
  1067. FMap := TFPStrObjMap.Create;
  1068. FMap.OnPtrCompare := @MapPtrCompare;
  1069. FOnCompareText := @DefaultCompareText;
  1070. NameValueSeparator:='=';
  1071. CheckSpecialChars;
  1072. end;
  1073. destructor TStringList.Destroy;
  1074. begin
  1075. FMap.Free;
  1076. inherited;
  1077. end;
  1078. function TStringList.GetDuplicates: TDuplicates;
  1079. begin
  1080. Result := FMap.Duplicates;
  1081. end;
  1082. function TStringList.GetSorted: boolean;
  1083. begin
  1084. Result := FMap.Sorted;
  1085. end;
  1086. procedure TStringList.SetDuplicates(NewDuplicates: TDuplicates);
  1087. begin
  1088. FMap.Duplicates := NewDuplicates;
  1089. end;
  1090. procedure TStringList.SetSorted(NewSorted: Boolean);
  1091. begin
  1092. FMap.Sorted := NewSorted;
  1093. end;
  1094. procedure TStringList.Changed;
  1095. begin
  1096. if FUpdateCount = 0 then
  1097. if Assigned(FOnChange) then
  1098. FOnChange(Self);
  1099. end;
  1100. procedure TStringList.Changing;
  1101. begin
  1102. if FUpdateCount = 0 then
  1103. if Assigned(FOnChanging) then
  1104. FOnChanging(Self);
  1105. end;
  1106. function TStringList.Get(Index: Integer): string;
  1107. begin
  1108. Result := FMap.Keys[Index];
  1109. end;
  1110. function TStringList.GetCapacity: Integer;
  1111. begin
  1112. Result := FMap.Capacity;
  1113. end;
  1114. function TStringList.GetCount: Integer;
  1115. begin
  1116. Result := FMap.Count;
  1117. end;
  1118. function TStringList.GetObject(Index: Integer): TObject;
  1119. begin
  1120. Result := FMap.Data[Index];
  1121. end;
  1122. procedure TStringList.Put(Index: Integer; const S: string);
  1123. begin
  1124. Changing;
  1125. FMap.Keys[Index] := S;
  1126. Changed;
  1127. end;
  1128. procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  1129. begin
  1130. Changing;
  1131. FMap.Data[Index] := AObject;
  1132. Changed;
  1133. end;
  1134. procedure TStringList.SetCapacity(NewCapacity: Integer);
  1135. begin
  1136. FMap.Capacity := NewCapacity;
  1137. end;
  1138. procedure TStringList.SetUpdateState(Updating: Boolean);
  1139. begin
  1140. if Updating then
  1141. Changing
  1142. else
  1143. Changed
  1144. end;
  1145. function TStringList.Add(const S: string): Integer;
  1146. begin
  1147. Result := FMap.Add(S);
  1148. end;
  1149. procedure TStringList.Clear;
  1150. begin
  1151. if FMap.Count = 0 then exit;
  1152. Changing;
  1153. FMap.Clear;
  1154. Changed;
  1155. end;
  1156. procedure TStringList.Delete(Index: Integer);
  1157. begin
  1158. if (Index < 0) or (Index >= FMap.Count) then
  1159. Error(SListIndexError, Index);
  1160. Changing;
  1161. FMap.Delete(Index);
  1162. Changed;
  1163. end;
  1164. procedure TStringList.Exchange(Index1, Index2: Integer);
  1165. begin
  1166. if (Index1 < 0) or (Index1 >= FMap.Count) then
  1167. Error(SListIndexError, Index1);
  1168. if (Index2 < 0) or (Index2 >= FMap.Count) then
  1169. Error(SListIndexError, Index2);
  1170. Changing;
  1171. FMap.InternalExchange(Index1, Index2);
  1172. Changed;
  1173. end;
  1174. procedure TStringList.SetCaseSensitive(NewSensitive: Boolean);
  1175. begin
  1176. if NewSensitive <> FCaseSensitive then
  1177. begin
  1178. FCaseSensitive := NewSensitive;
  1179. if Sorted then
  1180. Sort;
  1181. end;
  1182. end;
  1183. function TStringList.MapPtrCompare(Key1, Key2: Pointer): Integer;
  1184. begin
  1185. Result := FOnCompareText(string(Key1^), string(Key2^));
  1186. end;
  1187. function TStringList.DefaultCompareText(const s1, s2: string): PtrInt;
  1188. begin
  1189. if FCaseSensitive then
  1190. Result := AnsiCompareStr(s1, s2)
  1191. else
  1192. Result := AnsiCompareText(s1, s2);
  1193. end;
  1194. function TStringList.DoCompareText(const s1, s2: string): PtrInt;
  1195. begin
  1196. Result := FOnCompareText(s1, s2);
  1197. end;
  1198. function TStringList.Find(const S: string; var Index: Integer): Boolean;
  1199. begin
  1200. Result := FMap.Find(S, Index);
  1201. end;
  1202. function TStringList.IndexOf(const S: string): Integer;
  1203. begin
  1204. Result := FMap.IndexOf(S);
  1205. end;
  1206. procedure TStringList.Insert(Index: Integer; const S: string);
  1207. begin
  1208. if not Sorted and (0 <= Index) and (Index < FMap.Count) then
  1209. Changing;
  1210. FMap.InsertKey(Index, S);
  1211. Changed;
  1212. end;
  1213. procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  1214. var
  1215. I, J, Pivot: Integer;
  1216. begin
  1217. repeat
  1218. I := L;
  1219. J := R;
  1220. Pivot := (L + R) div 2;
  1221. repeat
  1222. while CompareFn(Self, I, Pivot) < 0 do Inc(I);
  1223. while CompareFn(Self, J, Pivot) > 0 do Dec(J);
  1224. if I <= J then
  1225. begin
  1226. FMap.InternalExchange(I, J); // No check, indices are correct.
  1227. if Pivot = I then
  1228. Pivot := J
  1229. else if Pivot = J then
  1230. Pivot := I;
  1231. Inc(I);
  1232. Dec(j);
  1233. end;
  1234. until I > J;
  1235. if L < J then
  1236. QuickSort(L,J, CompareFn);
  1237. L := I;
  1238. until I >= R;
  1239. end;
  1240. procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  1241. begin
  1242. if not Sorted and (FMap.Count > 1) then
  1243. begin
  1244. Changing;
  1245. QuickSort(0, FMap.Count-1, CompareFn);
  1246. Changed;
  1247. end;
  1248. end;
  1249. procedure TStringList.Sort;
  1250. begin
  1251. if not Sorted and (FMap.Count > 1) then
  1252. begin
  1253. Changing;
  1254. FMap.Sort;
  1255. Changed;
  1256. end;
  1257. end;
  1258. {$endif}