stringl.inc 46 KB

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