stringl.inc 18 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063
  1. {
  2. $Id$
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 by the Free Pascal development team
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {****************************************************************************}
  12. {* TStrings *}
  13. {****************************************************************************}
  14. // Function to quote text. Should move maybe to sysutils !!
  15. // Also, it is not clear at this point what exactly should be done.
  16. { //!! is used to mark unsupported things. }
  17. Function QuoteString (Const S : String; Quote : String) : String;
  18. Var
  19. I,J : Integer;
  20. begin
  21. J:=0;
  22. Result:=S;
  23. for i:=1to length(s) do
  24. begin
  25. inc(j);
  26. if S[i]=Quote then
  27. begin
  28. System.Insert(Quote,Result,J);
  29. inc(j);
  30. end;
  31. end;
  32. Result:=Quote+Result+Quote;
  33. end;
  34. function TStrings.GetCommaText: string;
  35. Var
  36. I : integer;
  37. p : pchar;
  38. begin
  39. result:='';
  40. For i:=0 to count-1 do
  41. begin
  42. p:=pchar(strings[i]);
  43. while not(p^ in [#0..' ','"',',']) do
  44. inc(p);
  45. if p^<>#0 then
  46. Result:=Result+QuoteString (Strings[I],'"')
  47. else
  48. result:=result+strings[i];
  49. if I<Count-1 then Result:=Result+',';
  50. end;
  51. If Length(Result)=0 then
  52. Result:='""';
  53. end;
  54. function TStrings.GetName(Index: Integer): string;
  55. Var L : longint;
  56. begin
  57. Result:=Strings[Index];
  58. L:=Pos('=',Result);
  59. If L<>0 then
  60. Result:=Copy(Result,1,L-1)
  61. else
  62. Result:='';
  63. end;
  64. Function TStrings.GetValue(const Name: string): string;
  65. Var L : longint;
  66. begin
  67. Result:='';
  68. L:=IndexOfName(Name);
  69. If L<>-1 then
  70. begin
  71. Result:=Strings[L];
  72. L:=Pos('=',Result);
  73. System.Delete (Result,1,L);
  74. end;
  75. end;
  76. procedure TStrings.ReadData(Reader: TReader);
  77. begin
  78. Reader.ReadListBegin;
  79. BeginUpdate;
  80. try
  81. Clear;
  82. while not Reader.EndOfList do
  83. Add(Reader.ReadString);
  84. finally
  85. EndUpdate;
  86. end;
  87. Reader.ReadListEnd;
  88. end;
  89. Function GetQuotedString (Var P : Pchar) : AnsiString;
  90. Var P1,L : Pchar;
  91. begin
  92. Result:='';
  93. P1:=P+1;
  94. While P1^<>#0 do
  95. begin
  96. If (P1^='"') then
  97. begin
  98. if (P1[1]<>'"') then
  99. break;
  100. inc(p1);
  101. end;
  102. inc(p1);
  103. end;
  104. // P1 points to last quote, or to #0;
  105. P:=P+1;
  106. If P1-P>0 then
  107. begin
  108. SetLength(Result,(P1-P));
  109. L:=Pointer(Result);
  110. Move (P^,L^,P1-P);
  111. P:=P1+1;
  112. end;
  113. end;
  114. Function GetNextQuotedChar (var P : PChar; Var S : String): Boolean;
  115. Var PS,L : PChar;
  116. begin
  117. Result:=False;
  118. S:='';
  119. While (p^<>#0) and (byte(p^)<=byte(' ')) do
  120. inc(p);
  121. If P^=#0 then exit;
  122. PS:=P;
  123. If P^='"' then
  124. begin
  125. S:=GetQuotedString(P);
  126. While (p^<>#0) and (byte(p^)<=byte(' ')) do
  127. inc(p);
  128. end
  129. else
  130. begin
  131. While (p^>' ') and (P^<>',') do
  132. inc(p);
  133. Setlength (S,P-PS);
  134. L:=Pointer(S);
  135. Move (PS^,L^,P-PS);
  136. end;
  137. if p^=',' then
  138. inc(p);
  139. Result:=True;
  140. end;
  141. Procedure TStrings.SetCommaText(const Value: string);
  142. Var
  143. P : PChar;
  144. S : String;
  145. begin
  146. BeginUpdate;
  147. try
  148. Clear;
  149. P:=PChar(Value);
  150. if assigned(p) then
  151. begin
  152. While GetNextQuotedChar (P,S) do
  153. Add (S);
  154. end;
  155. finally
  156. EndUpdate;
  157. end;
  158. end;
  159. Procedure TStrings.SetStringsAdapter(const Value: IStringsAdapter);
  160. begin
  161. end;
  162. Procedure TStrings.SetValue(const Name, Value: string);
  163. Var L : longint;
  164. begin
  165. L:=IndexOfName(Name);
  166. if L=-1 then
  167. Add (Name+'='+Value)
  168. else
  169. Strings[L]:=Name+'='+value;
  170. end;
  171. procedure TStrings.WriteData(Writer: TWriter);
  172. var
  173. i: Integer;
  174. begin
  175. Writer.WriteListBegin;
  176. for i := 0 to Count - 1 do
  177. Writer.WriteString(Strings[i]);
  178. Writer.WriteListEnd;
  179. end;
  180. procedure TStrings.DefineProperties(Filer: TFiler);
  181. var
  182. HasData: Boolean;
  183. begin
  184. if Assigned(Filer.Ancestor) then
  185. // Only serialize if string list is different from ancestor
  186. if Filer.Ancestor.InheritsFrom(TStrings) then
  187. HasData := not Equals(TStrings(Filer.Ancestor))
  188. else
  189. HasData := True
  190. else
  191. HasData := Count > 0;
  192. Filer.DefineProperty('Strings', @ReadData, @WriteData, HasData);
  193. end;
  194. Procedure TStrings.Error(const Msg: string; Data: Integer);
  195. begin
  196. Raise EStringListError.CreateFmt(Msg,[Data]) at get_caller_addr(get_frame);
  197. end;
  198. Function TStrings.GetCapacity: Integer;
  199. begin
  200. Result:=Count;
  201. end;
  202. Function TStrings.GetObject(Index: Integer): TObject;
  203. begin
  204. Result:=Nil;
  205. end;
  206. Function TStrings.GetTextStr: string;
  207. Const
  208. {$ifdef Unix}
  209. NewLineSize=1;
  210. {$else}
  211. NewLineSize=2;
  212. {$endif}
  213. Var P : Pchar;
  214. I,L : Longint;
  215. S : String;
  216. begin
  217. // Determine needed place
  218. L:=0;
  219. For I:=0 to count-1 do
  220. L:=L+Length(Strings[I])+NewLineSize;
  221. Setlength(Result,L);
  222. P:=Pointer(Result);
  223. For i:=0 To count-1 do
  224. begin
  225. S:=Strings[I];
  226. L:=Length(S);
  227. if L<>0 then
  228. System.Move(Pointer(S)^,P^,L);
  229. P:=P+L;
  230. {$ifndef Unix}
  231. p[0]:=#13;
  232. p[1]:=#10;
  233. {$else}
  234. p[0]:=#10;
  235. {$endif}
  236. P:=P+NewLineSize;
  237. end;
  238. end;
  239. Procedure TStrings.Put(Index: Integer; const S: string);
  240. Var Obj : TObject;
  241. begin
  242. Obj:=Objects[Index];
  243. Delete(Index);
  244. InsertObject(Index,S,Obj);
  245. end;
  246. Procedure TStrings.PutObject(Index: Integer; AObject: TObject);
  247. begin
  248. // Empty.
  249. end;
  250. Procedure TStrings.SetCapacity(NewCapacity: Integer);
  251. begin
  252. // Empty.
  253. end;
  254. Procedure TStrings.SetTextStr(const Value: string);
  255. begin
  256. SetText(PChar(Value));
  257. end;
  258. Procedure TStrings.SetUpdateState(Updating: Boolean);
  259. begin
  260. end;
  261. destructor TSTrings.Destroy;
  262. begin
  263. inherited destroy;
  264. end;
  265. Function TStrings.Add(const S: string): Integer;
  266. begin
  267. Result:=Count;
  268. Insert (Count,S);
  269. end;
  270. Function TStrings.AddObject(const S: string; AObject: TObject): Integer;
  271. begin
  272. Result:=Add(S);
  273. Objects[result]:=AObject;
  274. end;
  275. Procedure TStrings.Append(const S: string);
  276. begin
  277. Add (S);
  278. end;
  279. Procedure TStrings.AddStrings(TheStrings: TStrings);
  280. Var Runner : longint;
  281. begin
  282. try
  283. beginupdate;
  284. For Runner:=0 to TheStrings.Count-1 do
  285. self.AddObject (Thestrings[Runner],TheStrings.Objects[Runner]);
  286. finally
  287. EndUpdate;
  288. end;
  289. end;
  290. Procedure TStrings.Assign(Source: TPersistent);
  291. begin
  292. Try
  293. BeginUpdate;
  294. If Source is TStrings then
  295. begin
  296. clear;
  297. AddStrings(TStrings(Source));
  298. exit;
  299. end;
  300. Inherited Assign(Source);
  301. finally
  302. EndUpdate;
  303. end;
  304. end;
  305. Procedure TStrings.BeginUpdate;
  306. begin
  307. inc(FUpdateCount);
  308. if FUpdateCount = 1 then SetUpdateState(true);
  309. end;
  310. Procedure TStrings.EndUpdate;
  311. begin
  312. If FUpdateCount>0 then
  313. Dec(FUpdateCount);
  314. if FUpdateCount=0 then
  315. SetUpdateState(False);
  316. end;
  317. Function TStrings.Equals(TheStrings: TStrings): Boolean;
  318. Var Runner,Nr : Longint;
  319. begin
  320. Result:=False;
  321. Nr:=Self.Count;
  322. if Nr<>TheStrings.Count then exit;
  323. For Runner:=0 to Nr-1 do
  324. If Strings[Runner]<>TheStrings[Runner] then exit;
  325. Result:=True;
  326. end;
  327. Procedure TStrings.Exchange(Index1, Index2: Integer);
  328. Var
  329. Obj : TObject;
  330. Str : String;
  331. begin
  332. Try
  333. beginUpdate;
  334. Obj:=Objects[Index1];
  335. Str:=Strings[Index1];
  336. Objects[Index1]:=Objects[Index2];
  337. Strings[Index1]:=Strings[Index2];
  338. Objects[Index2]:=Obj;
  339. Strings[Index2]:=Str;
  340. finally
  341. EndUpdate;
  342. end;
  343. end;
  344. Function TStrings.GetText: PChar;
  345. begin
  346. Result:=StrNew(Pchar(Self.Text));
  347. end;
  348. Function TStrings.IndexOf(const S: string): Integer;
  349. begin
  350. Result:=0;
  351. While (Result<Count) and (Strings[Result]<>S) do Result:=Result+1;
  352. if Result=Count then Result:=-1;
  353. end;
  354. Function TStrings.IndexOfName(const Name: string): Integer;
  355. Var len : longint;
  356. begin
  357. Result:=0;
  358. while (Result<Count) do
  359. begin
  360. len:=pos('=',Strings[Result])-1;
  361. if (len>0) and (Name=Copy(Strings[Result],1,Len)) then exit;
  362. inc(result);
  363. end;
  364. result:=-1;
  365. end;
  366. Function TStrings.IndexOfObject(AObject: TObject): Integer;
  367. begin
  368. Result:=0;
  369. While (Result<count) and (Objects[Result]<>AObject) do Result:=Result+1;
  370. If Result=Count then Result:=-1;
  371. end;
  372. Procedure TStrings.InsertObject(Index: Integer; const S: string;
  373. AObject: TObject);
  374. begin
  375. Insert (Index,S);
  376. Objects[Index]:=AObject;
  377. end;
  378. Procedure TStrings.LoadFromFile(const FileName: string);
  379. Var TheStream : TFileStream;
  380. begin
  381. TheStream:=TFileStream.Create(FileName,fmOpenRead);
  382. LoadFromStream(TheStream);
  383. TheStream.Free;
  384. end;
  385. Procedure TStrings.LoadFromStream(Stream: TStream);
  386. {
  387. Borlands method is no goed, since a pipe for
  388. Instance doesn't have a size.
  389. So we must do it the hard way.
  390. }
  391. Const
  392. BufSize = 1024;
  393. Var
  394. Buffer : Pointer;
  395. BytesRead,
  396. BufLen : Longint;
  397. begin
  398. // reread into a buffer
  399. try
  400. beginupdate;
  401. Buffer:=Nil;
  402. BufLen:=0;
  403. Repeat
  404. ReAllocMem(Buffer,BufLen+BufSize);
  405. BytesRead:=Stream.Read((Buffer+BufLen)^,BufSize);
  406. inc(BufLen,BufSize);
  407. Until BytesRead<>BufSize;
  408. // Null-terminate !!
  409. Pchar(Buffer)[BufLen-BufSize+BytesRead]:=#0;
  410. Text:=PChar(Buffer);
  411. FreeMem(Buffer);
  412. finally
  413. EndUpdate;
  414. end;
  415. end;
  416. Procedure TStrings.Move(CurIndex, NewIndex: Integer);
  417. Var
  418. Obj : TObject;
  419. Str : String;
  420. begin
  421. Obj:=Objects[CurIndex];
  422. Str:=Strings[CurIndex];
  423. Delete(Curindex);
  424. InsertObject(NewIndex,Str,Obj);
  425. end;
  426. Procedure TStrings.SaveToFile(const FileName: string);
  427. Var TheStream : TFileStream;
  428. begin
  429. TheStream:=TFileStream.Create(FileName,fmCreate);
  430. SaveToStream(TheStream);
  431. TheStream.Free;
  432. end;
  433. Procedure TStrings.SaveToStream(Stream: TStream);
  434. Var
  435. S : String;
  436. begin
  437. S:=Text;
  438. Stream.Write(Pointer(S)^,Length(S));
  439. end;
  440. Function GetNextLine (Var P : Pchar; Var S : String) : Boolean;
  441. Var PS : PChar;
  442. begin
  443. S:='';
  444. Result:=False;
  445. If P^=#0 then exit;
  446. PS:=P;
  447. While not (P^ in [#0,#10,#13]) do P:=P+1;
  448. SetLength (S,P-PS);
  449. System.Move (PS^,Pointer(S)^,P-PS);
  450. If P^=#13 then P:=P+1;
  451. If P^=#10 then
  452. P:=P+1; // Point to character after #10(#13)
  453. Result:=True;
  454. end;
  455. Procedure TStrings.SetText(TheText: PChar);
  456. Var S : String;
  457. begin
  458. Try
  459. beginUpdate;
  460. Clear;
  461. While GetNextLine (TheText,S) do
  462. Add(S);
  463. finally
  464. EndUpdate;
  465. end;
  466. end;
  467. {****************************************************************************}
  468. {* TStringList *}
  469. {****************************************************************************}
  470. Procedure TStringList.ExchangeItems(Index1, Index2: Integer);
  471. Var P1,P2 : Pointer;
  472. begin
  473. P1:=Pointer(Flist^[Index1].FString);
  474. P2:=Pointer(Flist^[Index1].FObject);
  475. Pointer(Flist^[Index1].Fstring):=Pointer(Flist^[Index2].Fstring);
  476. Pointer(Flist^[Index1].FObject):=Pointer(Flist^[Index2].FObject);
  477. Pointer(Flist^[Index2].Fstring):=P1;
  478. Pointer(Flist^[Index2].FObject):=P2;
  479. end;
  480. Procedure TStringList.Grow;
  481. Var Extra : Longint;
  482. begin
  483. If FCapacity>64 then
  484. Extra:=FCapacity Div 4
  485. Else If FCapacity>8 Then
  486. Extra:=16
  487. Else
  488. Extra:=4;
  489. SetCapacity(FCapacity+Extra);
  490. end;
  491. Procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare);
  492. Var I,J, Pivot : Longint;
  493. begin
  494. Repeat
  495. I:=L;
  496. J:=R;
  497. Pivot:=(L+R) div 2;
  498. Repeat
  499. While CompareFn(Self, I, Pivot)<0 do Inc(I);
  500. While CompareFn(Self, J, Pivot)>0 do Dec(J);
  501. If I<=J then
  502. begin
  503. ExchangeItems(I,J); // No check, indices are correct.
  504. if Pivot=I then
  505. Pivot:=J
  506. else if Pivot=J then
  507. Pivot := I;
  508. Inc(I);
  509. Dec(j);
  510. end;
  511. until I>J;
  512. If L<J then QuickSort(L,J, CompareFn);
  513. L:=I;
  514. Until I>=R;
  515. end;
  516. Procedure TStringList.InsertItem(Index: Integer; const S: string);
  517. begin
  518. Changing;
  519. If FCount=Fcapacity then Grow;
  520. If Index<FCount then
  521. System.Move (FList^[Index],FList^[Index+1],
  522. (FCount-Index)*SizeOf(TStringItem));
  523. Pointer(Flist^[Index].Fstring):=Nil; // Needed to initialize...
  524. Flist^[Index].FString:=S;
  525. Flist^[Index].Fobject:=Nil;
  526. Inc(FCount);
  527. Changed;
  528. end;
  529. Procedure TStringList.SetSorted(Value: Boolean);
  530. begin
  531. If FSorted<>Value then
  532. begin
  533. If Value then sort;
  534. FSorted:=VAlue
  535. end;
  536. end;
  537. Procedure TStringList.Changed;
  538. begin
  539. If (FUpdateCount=0) Then
  540. If Assigned(FOnChange) then
  541. FOnchange(Self);
  542. end;
  543. Procedure TStringList.Changing;
  544. begin
  545. If FUpdateCount=0 then
  546. if Assigned(FOnChanging) then
  547. FOnchanging(Self);
  548. end;
  549. Function TStringList.Get(Index: Integer): string;
  550. begin
  551. If (Index<0) or (INdex>=Fcount) then
  552. Error (SListIndexError,Index);
  553. Result:=Flist^[Index].FString;
  554. end;
  555. Function TStringList.GetCapacity: Integer;
  556. begin
  557. Result:=FCapacity;
  558. end;
  559. Function TStringList.GetCount: Integer;
  560. begin
  561. Result:=FCount;
  562. end;
  563. Function TStringList.GetObject(Index: Integer): TObject;
  564. begin
  565. If (Index<0) or (INdex>=Fcount) then
  566. Error (SListIndexError,Index);
  567. Result:=Flist^[Index].FObject;
  568. end;
  569. Procedure TStringList.Put(Index: Integer; const S: string);
  570. begin
  571. If Sorted then
  572. Error(SSortedListError,0);
  573. If (Index<0) or (INdex>=Fcount) then
  574. Error (SListIndexError,Index);
  575. Changing;
  576. Flist^[Index].FString:=S;
  577. Changed;
  578. end;
  579. Procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  580. begin
  581. If (Index<0) or (INdex>=Fcount) then
  582. Error (SListIndexError,Index);
  583. Changing;
  584. Flist^[Index].FObject:=AObject;
  585. Changed;
  586. end;
  587. Procedure TStringList.SetCapacity(NewCapacity: Integer);
  588. Var NewList : Pointer;
  589. MSize : Longint;
  590. begin
  591. If (NewCapacity<0) then
  592. Error (SListCapacityError,NewCapacity);
  593. If NewCapacity>FCapacity then
  594. begin
  595. GetMem (NewList,NewCapacity*SizeOf(TStringItem));
  596. If NewList=Nil then
  597. Error (SListCapacityError,NewCapacity);
  598. If Assigned(FList) then
  599. begin
  600. MSize:=FCapacity*Sizeof(TStringItem);
  601. System.Move (FList^,NewList^,MSize);
  602. FillWord (Pchar(NewList)[MSize],(NewCapacity-FCapacity)*WordRatio, 0);
  603. FreeMem (Flist,MSize);
  604. end;
  605. Flist:=NewList;
  606. FCapacity:=NewCapacity;
  607. end
  608. else if NewCapacity<FCapacity then
  609. begin
  610. if NewCapacity = 0 then
  611. begin
  612. FreeMem(FList);
  613. FList := nil;
  614. end else
  615. begin
  616. GetMem(NewList, NewCapacity * SizeOf(TStringItem));
  617. System.Move(FList^, NewList^, NewCapacity * SizeOf(TStringItem));
  618. FreeMem(FList);
  619. FList := NewList;
  620. end;
  621. FCapacity:=NewCapacity;
  622. end;
  623. end;
  624. Procedure TStringList.SetUpdateState(Updating: Boolean);
  625. begin
  626. If Updating then
  627. Changing
  628. else
  629. Changed
  630. end;
  631. destructor TStringList.Destroy;
  632. Var I : Longint;
  633. begin
  634. FOnChange:=Nil;
  635. FOnChanging:=Nil;
  636. // This will force a dereference. Can be done better...
  637. For I:=0 to FCount-1 do
  638. FList^[I].FString:='';
  639. FCount:=0;
  640. SetCapacity(0);
  641. Inherited destroy;
  642. end;
  643. Function TStringList.Add(const S: string): Integer;
  644. begin
  645. If Not Sorted then
  646. Result:=FCount
  647. else
  648. If Find (S,Result) then
  649. Case DUplicates of
  650. DupIgnore : Exit;
  651. DupError : Error(SDuplicateString,0)
  652. end;
  653. InsertItem (Result,S);
  654. end;
  655. Procedure TStringList.Clear;
  656. Var I : longint;
  657. begin
  658. For I:=0 to FCount-1 do
  659. Flist^[I].FString:='';
  660. FCount:=0;
  661. SetCapacity(0);
  662. end;
  663. Procedure TStringList.Delete(Index: Integer);
  664. begin
  665. If (Index<0) or (Index>=FCount) then
  666. Error(SlistINdexError,Index);
  667. Flist^[Index].FString:='';
  668. Dec(FCount);
  669. If Index<FCount then
  670. System.Move(Flist^[Index+1],
  671. Flist^[Index],
  672. (Fcount-Index)*SizeOf(TStringItem));
  673. end;
  674. Procedure TStringList.Exchange(Index1, Index2: Integer);
  675. begin
  676. If (Index1<0) or (Index1>=FCount) then
  677. Error(SListIndexError,Index1);
  678. If (Index2<0) or (Index2>=FCount) then
  679. Error(SListIndexError,Index2);
  680. Changing;
  681. ExchangeItems(Index1,Index2);
  682. changed;
  683. end;
  684. Function TStringList.Find(const S: string; var Index: Integer): Boolean;
  685. { Searches for the first string <= S, returns True if exact match,
  686. sets index to the index f the found string. }
  687. Var I,L,R,Temp : Longint;
  688. begin
  689. Result:=False;
  690. // Use binary search.
  691. L:=0;
  692. R:=FCount-1;
  693. While L<=R do
  694. begin
  695. I:=(L+R) div 2;
  696. Temp:=AnsiCompareText(FList^ [I].FString,S);
  697. If Temp<0 then
  698. L:=I+1
  699. else
  700. begin
  701. R:=I-1;
  702. If Temp=0 then
  703. begin
  704. Result:=True;
  705. If Duplicates<>DupAccept then L:=I;
  706. end;
  707. end;
  708. end;
  709. Index:=L;
  710. end;
  711. Function TStringList.IndexOf(const S: string): Integer;
  712. begin
  713. If Not Sorted then
  714. Result:=Inherited indexOf(S)
  715. else
  716. // faster using binary search...
  717. If Not Find (S,Result) then
  718. Result:=-1;
  719. end;
  720. Procedure TStringList.Insert(Index: Integer; const S: string);
  721. begin
  722. If Sorted then
  723. Error (SSortedListError,0)
  724. else
  725. If (Index<0) or (Index>FCount) then
  726. Error (SListIndexError,Index)
  727. else
  728. InsertItem (Index,S);
  729. end;
  730. Procedure TStringList.CustomSort(CompareFn: TStringListSortCompare);
  731. begin
  732. If Not Sorted and (FCount>1) then
  733. begin
  734. Changing;
  735. QuickSort(0,FCount-1, CompareFn);
  736. Changed;
  737. end;
  738. end;
  739. function StringListAnsiCompare(List: TStringList; Index1, Index: Integer): Integer;
  740. begin
  741. Result := AnsiCompareText(List.FList^[Index1].FString,
  742. List.FList^[Index].FString);
  743. end;
  744. Procedure TStringList.Sort;
  745. begin
  746. CustomSort(@StringListAnsiCompare);
  747. end;
  748. {
  749. $Log$
  750. Revision 1.10 2001-05-20 12:10:03 peter
  751. * fixed setcommatext
  752. Revision 1.9 2001/04/13 18:03:28 peter
  753. * commatext fixes
  754. Revision 1.8 2001/04/10 23:24:51 peter
  755. * merged fixes
  756. Revision 1.7 2001/02/23 22:24:08 michael
  757. + Fixed sorting of stringslist
  758. Revision 1.6 2000/12/03 22:35:09 sg
  759. * Applied patch by Markus Kaemmerer (merged):
  760. - Added support for TStringList.CustomSort
  761. Revision 1.5 2000/11/22 22:44:39 peter
  762. * fixed commatext (merged)
  763. Revision 1.4 2000/11/17 13:39:49 sg
  764. * Extended Error methods so that exceptions are raised from the caller's
  765. address instead of the Error method
  766. Revision 1.3 2000/11/13 15:46:55 marco
  767. * Unix renamefest for defines.
  768. Revision 1.2 2000/07/13 11:33:01 michael
  769. + removed logs
  770. }