stringl.inc 50 KB

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