stringl.inc 48 KB

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