stringl.inc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962
  1. {
  2. $Id$
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1998 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 I,J : Longint;
  19. begin
  20. I:=0;
  21. J:=0;
  22. Result:=S;
  23. While I<Length(S) do
  24. begin
  25. I:=I+1;
  26. J:=J+1;
  27. if S[i]=Quote then
  28. begin
  29. System.Insert(Result,Quote,J);
  30. J:=J+1;
  31. end;
  32. end;
  33. Result:=Quote+Result+Quote;
  34. end;
  35. function TStrings.GetCommaText: string;
  36. Var I : Longint;
  37. begin
  38. result:='';
  39. For i:=0 to count-1 do
  40. begin
  41. Result:=Result+QuoteString (Strings[I],'"');
  42. if I<Count-1 then Result:=Result+',';
  43. end;
  44. If Length(Result)=0 then Result:='""';
  45. end;
  46. function TStrings.GetName(Index: Integer): string;
  47. Var L : longint;
  48. begin
  49. Result:=Strings[Index];
  50. L:=Pos('=',Result);
  51. If L<>0 then
  52. Result:=Copy(Result,1,L-1)
  53. else
  54. Result:='';
  55. end;
  56. Function TStrings.GetValue(const Name: string): string;
  57. Var L : longint;
  58. begin
  59. Result:='';
  60. L:=IndexOfName(Name);
  61. If L<>-1 then
  62. begin
  63. Result:=Strings[L];
  64. L:=Pos('=',Result);
  65. System.Delete (Result,1,L);
  66. end;
  67. end;
  68. Procedure TStrings.ReadData(Reader: TReader);
  69. begin
  70. end;
  71. Function GetQuotedString (Var P : Pchar) : AnsiString;
  72. Var P1,L : Pchar;
  73. begin
  74. Result:='';
  75. P1:=P+1;
  76. While P1^<>#0 do
  77. begin
  78. If (P1^='"') and (P1[1]<>'"') then
  79. break;
  80. P1:=P1+1;
  81. If P1^='"' then P1:=P1+1;
  82. end;
  83. // P1 points to last quote, or to #0;
  84. P:=P+1;
  85. If P1-P>0 then
  86. begin
  87. SetLength(Result,(P1-P));
  88. L:=Pointer(Result);
  89. Move (P^,L^,P1-P);
  90. P:=P1+1;
  91. end;
  92. end;
  93. Function GetNextQuotedChar (P : PChar; Var S : String): Boolean;
  94. Var PS,L : PChar;
  95. begin
  96. Result:=False;
  97. If P^=#0 then exit;
  98. S:='';
  99. While (p^<>#0) and (byte(p^)<=byte(' ')) do P:=P+1;
  100. PS:=P;
  101. If P^='"' then
  102. S:=GetQuotedString(P)
  103. else
  104. begin
  105. While (p^>' ') and (P^<>',') do P:=P+1;
  106. Setlength (S,P-PS);
  107. L:=Pointer(S);
  108. Move (PS^,L,P-PS);
  109. end;
  110. Result:=True;
  111. end;
  112. Procedure TStrings.SetCommaText(const Value: string);
  113. Var P : Pointer;
  114. S : String;
  115. begin
  116. Self.Clear;
  117. P:=Pointer(Value);
  118. While GetNextQuotedChar (P,S) do Add (S);
  119. end;
  120. Procedure TStrings.SetStringsAdapter(const Value: IStringsAdapter);
  121. begin
  122. end;
  123. Procedure TStrings.SetValue(const Name, Value: string);
  124. Var L : longint;
  125. begin
  126. L:=IndexOfName(Name);
  127. if L=-1 then
  128. Add (Name+'='+Value)
  129. else
  130. Strings[L]:=Name+'='+value;
  131. end;
  132. Procedure TStrings.WriteData(Writer: TWriter);
  133. begin
  134. end;
  135. Procedure TStrings.DefineProperties(Filer: TFiler);
  136. begin
  137. end;
  138. Procedure TStrings.Error(const Msg: string; Data: Integer);
  139. begin
  140. //!! Need to get correct address !!
  141. Raise EStringListError.CreateFmt(Msg,[Data]);
  142. end;
  143. Function TStrings.GetCapacity: Integer;
  144. begin
  145. Result:=Count;
  146. end;
  147. Function TStrings.GetObject(Index: Integer): TObject;
  148. begin
  149. Result:=Nil;
  150. end;
  151. Function TStrings.GetTextStr: string;
  152. Const
  153. {$ifdef linux}
  154. NewLineSize=1;
  155. {$else}
  156. NewLineSize=2;
  157. {$endif}
  158. Var P : Pchar;
  159. I,L : Longint;
  160. S : String;
  161. begin
  162. // Determine needed place
  163. L:=0;
  164. For I:=0 to count-1 do
  165. begin
  166. L:=L+Length(Strings[I])+NewLineSize;
  167. Writeln ('length needed : ',l);
  168. end;
  169. Setlength(Result,L);
  170. P:=Pointer(Result);
  171. For i:=0 To count-1 do
  172. begin
  173. S:=Strings[I];
  174. L:=Length(S);
  175. if L<>0 then
  176. System.Move(Pointer(S)^,P^,L);
  177. P:=P+L;
  178. {$ifndef linux}
  179. p[0]:=#13;
  180. p[1]:=#10;
  181. {$else}
  182. p[0]:=#10;
  183. {$endif}
  184. P:=P+NewLineSize;
  185. end;
  186. end;
  187. Procedure TStrings.Put(Index: Integer; const S: string);
  188. Var Obj : TObject;
  189. begin
  190. Obj:=Objects[Index];
  191. Delete(Index);
  192. InsertObject(Index,S,Obj);
  193. end;
  194. Procedure TStrings.PutObject(Index: Integer; AObject: TObject);
  195. begin
  196. // Empty.
  197. end;
  198. Procedure TStrings.SetCapacity(NewCapacity: Integer);
  199. begin
  200. // Empty.
  201. end;
  202. Procedure TStrings.SetTextStr(const Value: string);
  203. begin
  204. SetText(PChar(Value));
  205. end;
  206. Procedure TStrings.SetUpdateState(Updating: Boolean);
  207. begin
  208. end;
  209. destructor TSTrings.Destroy;
  210. begin
  211. inherited destroy;
  212. end;
  213. Function TStrings.Add(const S: string): Integer;
  214. begin
  215. Result:=Count;
  216. Insert (Count,S);
  217. end;
  218. Function TStrings.AddObject(const S: string; AObject: TObject): Integer;
  219. begin
  220. Result:=Add(S);
  221. Objects[result]:=AObject;
  222. end;
  223. Procedure TStrings.Append(const S: string);
  224. begin
  225. Add (S);
  226. end;
  227. Procedure TStrings.AddStrings(TheStrings: TStrings);
  228. Var Runner : longint;
  229. begin
  230. For Runner:=0 to TheStrings.Count-1 do
  231. self.AddObject (Thestrings[Runner],TheStrings.Objects[Runner]);
  232. end;
  233. Procedure TStrings.Assign(Source: TPersistent);
  234. begin
  235. If Source is TStrings then
  236. begin
  237. clear;
  238. AddStrings(TStrings(Source));
  239. exit;
  240. end;
  241. Inherited Assign(Source);
  242. end;
  243. Procedure TStrings.BeginUpdate;
  244. begin
  245. end;
  246. Procedure TStrings.EndUpdate;
  247. begin
  248. end;
  249. Function TStrings.Equals(TheStrings: TStrings): Boolean;
  250. Var Runner,Nr : Longint;
  251. begin
  252. Result:=False;
  253. Nr:=Self.Count;
  254. if Nr<>TheStrings.Count then exit;
  255. For Runner:=0 to Nr-1 do
  256. If Strings[Runner]<>TheStrings[Runner] then exit;
  257. Result:=True;
  258. end;
  259. Procedure TStrings.Exchange(Index1, Index2: Integer);
  260. Var
  261. Obj : TObject;
  262. Str : String;
  263. begin
  264. Obj:=Objects[Index1];
  265. Str:=Strings[Index1];
  266. Objects[Index1]:=Objects[Index2];
  267. Strings[Index1]:=Strings[Index2];
  268. Objects[Index2]:=Obj;
  269. Strings[Index2]:=Str;
  270. end;
  271. Function TStrings.GetText: PChar;
  272. begin
  273. Result:=StrNew(Pchar(Self.Text));
  274. end;
  275. Function TStrings.IndexOf(const S: string): Integer;
  276. begin
  277. Result:=0;
  278. While (Result<Count) and (Strings[Result]<>S) do Result:=Result+1;
  279. if Result=Count then Result:=-1;
  280. end;
  281. Function TStrings.IndexOfName(const Name: string): Integer;
  282. Var len : longint;
  283. begin
  284. Result:=0;
  285. while (Result<Count) do
  286. begin
  287. len:=pos('=',Strings[Result])-1;
  288. if (len>0) and (Name=Copy(Strings[Result],1,Len)) then exit;
  289. inc(result);
  290. end;
  291. result:=-1;
  292. end;
  293. Function TStrings.IndexOfObject(AObject: TObject): Integer;
  294. begin
  295. Result:=0;
  296. While (Result<count) and (Objects[Result]<>AObject) do Result:=Result+1;
  297. If Result=Count then Result:=-1;
  298. end;
  299. Procedure TStrings.InsertObject(Index: Integer; const S: string;
  300. AObject: TObject);
  301. begin
  302. Insert (Index,S);
  303. Objects[Index]:=AObject;
  304. end;
  305. Procedure TStrings.LoadFromFile(const FileName: string);
  306. Var TheStream : TFileStream;
  307. begin
  308. TheStream:=TFileStream.Create(FileName,fmOpenRead);
  309. LoadFromStream(TheStream);
  310. TheStream.Free;
  311. end;
  312. Procedure TStrings.LoadFromStream(Stream: TStream);
  313. {
  314. Borlands method is no goed, since a pipe for
  315. Instance doesn't have a size.
  316. So we must do it the hard way.
  317. }
  318. Const BufSize = 1024;
  319. Procedure ReallocMem (Var B : Pointer; OldSize :longint);
  320. Var NewB : Pointer;
  321. begin
  322. GetMem(NewB,OldSIze+BufSize);
  323. If OldSize>0 then // assume that if size=0, B also Nil
  324. begin
  325. System.Move (B^,NewB^,OldSize);
  326. FreeMem (B,OldSize);
  327. end;
  328. B:=NewB;
  329. end;
  330. Var Buffer : Pointer;
  331. BytesRead,BufLen : Longint;
  332. begin
  333. Buffer:=Nil;
  334. BufLen:=0;
  335. Repeat
  336. ReAllocMem(Buffer,BufLen);
  337. BytesRead:=Stream.Read((Buffer+BufLen)^,BufSize);
  338. BufLen:=BufLen+BufSize;
  339. Until BytesRead<>BufSize;
  340. // Null-terminate !!
  341. Pchar(Buffer)[BufLen-BufSize+BytesRead]:=#0;
  342. Text:=PChar(Buffer);
  343. FreeMem (Buffer,BufLen);
  344. end;
  345. Procedure TStrings.Move(CurIndex, NewIndex: Integer);
  346. Var Obj : TObject;
  347. Str : String;
  348. begin
  349. Obj:=Objects[CurIndex];
  350. Str:=Strings[CurIndex];
  351. Delete(Curindex);
  352. InsertObject(NewIndex,Str,Obj);
  353. end;
  354. Procedure TStrings.SaveToFile(const FileName: string);
  355. Var TheStream : TFileStream;
  356. begin
  357. TheStream:=TFileStream.Create(FileName,fmCreate);
  358. SaveToStream(TheStream);
  359. TheStream.Free;
  360. end;
  361. Procedure TStrings.SaveToStream(Stream: TStream);
  362. VAr S : String;
  363. begin
  364. S:=Text;
  365. Stream.Write(Pointer(S)^,Length(S));
  366. end;
  367. Function GetNextLine (Var P : Pchar; Var S : String) : Boolean;
  368. Var PS : PChar;
  369. begin
  370. S:='';
  371. Result:=False;
  372. If P^=#0 then exit;
  373. PS:=P;
  374. While not (P^ in [#0,#10,#13]) do P:=P+1;
  375. SetLength (S,P-PS);
  376. System.Move (PS^,Pointer(S)^,P-PS);
  377. If P^=#13 then P:=P+1;
  378. If P^<>#0 then
  379. P:=P+1; // Point to character after #10(#13)
  380. Result:=True;
  381. end;
  382. Procedure TStrings.SetText(TheText: PChar);
  383. Var S : String;
  384. begin
  385. Clear;
  386. While GetNextLine (TheText,S) do
  387. Add(S);
  388. end;
  389. {****************************************************************************}
  390. {* TStringList *}
  391. {****************************************************************************}
  392. Procedure TStringList.ExchangeItems(Index1, Index2: Integer);
  393. Var P1,P2 : Pointer;
  394. begin
  395. P1:=Pointer(Flist^[Index1].FString);
  396. P2:=Pointer(Flist^[Index1].FObject);
  397. Pointer(Flist^[Index1].Fstring):=Pointer(Flist^[Index2].Fstring);
  398. Pointer(Flist^[Index1].FObject):=Pointer(Flist^[Index2].FObject);
  399. Pointer(Flist^[Index2].Fstring):=P1;
  400. Pointer(Flist^[Index2].FObject):=P2;
  401. end;
  402. Procedure TStringList.Grow;
  403. Var Extra : Longint;
  404. begin
  405. If FCapacity>64 then
  406. Extra:=FCapacity Div 4
  407. Else If FCapacity>8 Then
  408. Extra:=16
  409. Else
  410. Extra:=4;
  411. SetCapacity(FCapacity+Extra);
  412. end;
  413. Procedure TStringList.QuickSort(L, R: Integer);
  414. Var I,J : Longint;
  415. Pivot : String;
  416. begin
  417. Repeat;
  418. I:=L;
  419. J:=R;
  420. Pivot:=Flist^[(L+R) div 2].FString;
  421. Repeat
  422. While AnsiCompareText(Flist^[I].Fstring,Pivot)<0 do Inc(I);
  423. While AnsiCompareText(Flist^[J].Fstring,Pivot)>0 do Dec(J);
  424. If I<=J then
  425. begin
  426. ExchangeItems(I,J); // No check, indices are correct.
  427. Inc(I);
  428. Dec(j);
  429. end;
  430. until I>J;
  431. If L<J then QuickSort(L,J);
  432. L:=I;
  433. Until I>=R;
  434. end;
  435. Procedure TStringList.InsertItem(Index: Integer; const S: string);
  436. begin
  437. Changing;
  438. If FCount=Fcapacity then Grow;
  439. If Index<FCount then
  440. System.Move (FList^[Index],FList^[Index+1],
  441. (FCount-Index)*SizeOf(TStringItem));
  442. Pointer(Flist^[Index].Fstring):=Nil; // Needed to initialize...
  443. Flist^[Index].FString:=S;
  444. Flist^[Index].Fobject:=Nil;
  445. Inc(FCount);
  446. Changed;
  447. end;
  448. Procedure TStringList.SetSorted(Value: Boolean);
  449. begin
  450. If FSorted<>Value then
  451. begin
  452. If Value then sort;
  453. FSorted:=VAlue
  454. end;
  455. end;
  456. Procedure TStringList.Changed;
  457. begin
  458. If (FUpdateCount=0) Then
  459. If Assigned(FOnChange) then
  460. FOnchange(Self);
  461. end;
  462. Procedure TStringList.Changing;
  463. begin
  464. If FUpdateCount=0 then
  465. if Assigned(FOnChanging) then
  466. FOnchanging(Self);
  467. end;
  468. Function TStringList.Get(Index: Integer): string;
  469. begin
  470. If (Index<0) or (INdex>=Fcount) then
  471. Error (SListIndexError,Index);
  472. Result:=Flist^[Index].FString;
  473. end;
  474. Function TStringList.GetCapacity: Integer;
  475. begin
  476. Result:=FCapacity;
  477. end;
  478. Function TStringList.GetCount: Integer;
  479. begin
  480. Result:=FCount;
  481. end;
  482. Function TStringList.GetObject(Index: Integer): TObject;
  483. begin
  484. If (Index<0) or (INdex>=Fcount) then
  485. Error (SListIndexError,Index);
  486. Result:=Flist^[Index].FObject;
  487. end;
  488. Procedure TStringList.Put(Index: Integer; const S: string);
  489. begin
  490. If Sorted then
  491. Error(SSortedListError,0);
  492. If (Index<0) or (INdex>=Fcount) then
  493. Error (SListIndexError,Index);
  494. Changing;
  495. Flist^[Index].FString:=S;
  496. Changed;
  497. end;
  498. Procedure TStringList.PutObject(Index: Integer; AObject: TObject);
  499. begin
  500. If (Index<0) or (INdex>=Fcount) then
  501. Error (SListIndexError,Index);
  502. Changing;
  503. Flist^[Index].FObject:=AObject;
  504. Changed;
  505. end;
  506. Procedure TStringList.SetCapacity(NewCapacity: Integer);
  507. Var NewList : Pointer;
  508. MSize : Longint;
  509. begin
  510. If (NewCapacity<0) then
  511. Error (SListCapacityError,NewCapacity);
  512. If NewCapacity>FCapacity then
  513. begin
  514. GetMem (NewList,NewCapacity*SizeOf(TStringItem));
  515. If NewList=Nil then
  516. Error (SListCapacityError,NewCapacity);
  517. If Assigned(FList) then
  518. begin
  519. MSize:=FCapacity*Sizeof(TStringItem);
  520. System.Move (FList^,NewList^,MSize);
  521. FillWord (Pchar(NewList)[MSize],(NewCapacity-FCapacity)*WordRatio, 0);
  522. FreeMem (Flist,MSize);
  523. end;
  524. Flist:=NewList;
  525. FCapacity:=NewCapacity;
  526. end
  527. else if NewCapacity<FCapacity then
  528. begin
  529. NewList:=Flist+NewCapacity*SizeOf(TStringItem);
  530. FreeMem (NewList, (FCapacity-NewCapacity)*SizeOf(TStringItem));
  531. FCapacity:=NewCapacity;
  532. end;
  533. end;
  534. Procedure TStringList.SetUpdateState(Updating: Boolean);
  535. begin
  536. If Updating then
  537. Changing
  538. else
  539. Changed
  540. end;
  541. destructor TStringList.Destroy;
  542. Var I : Longint;
  543. begin
  544. FOnChange:=Nil;
  545. FOnChanging:=Nil;
  546. // This will force a dereference. Can be done better...
  547. For I:=0 to FCount-1 do
  548. FList^[I].FString:='';
  549. FCount:=0;
  550. SetCapacity(0);
  551. Inherited destroy;
  552. end;
  553. Function TStringList.Add(const S: string): Integer;
  554. begin
  555. If Not Sorted then
  556. Result:=FCount
  557. else
  558. If Find (S,Result) then
  559. Case DUplicates of
  560. DupIgnore : Exit;
  561. DupError : Error(SDuplicateString,0)
  562. end;
  563. InsertItem (Result,S);
  564. end;
  565. Procedure TStringList.Clear;
  566. Var I : longint;
  567. begin
  568. For I:=0 to FCount-1 do
  569. Flist^[I].FString:='';
  570. FCount:=0;
  571. SetCapacity(0);
  572. end;
  573. Procedure TStringList.Delete(Index: Integer);
  574. begin
  575. If (Index<0) or (Index>=FCount) then
  576. Error(SlistINdexError,Index);
  577. Flist^[Index].FString:='';
  578. Dec(FCount);
  579. If Index<FCount then
  580. System.Move(Flist^[Index+1],
  581. Flist^[Index],
  582. (Fcount-Index)*SizeOf(TStringItem));
  583. end;
  584. Procedure TStringList.Exchange(Index1, Index2: Integer);
  585. begin
  586. If (Index1<0) or (Index1>=FCount) then
  587. Error(SListIndexError,Index1);
  588. If (Index2<0) or (Index2>=FCount) then
  589. Error(SListIndexError,Index1);
  590. Changing;
  591. ExchangeItems(Index1,Index2);
  592. changed;
  593. end;
  594. Function TStringList.Find(const S: string; var Index: Integer): Boolean;
  595. { Searches for the first string <= S, returns True if exact match,
  596. sets index to the index f the found string. }
  597. Var I,L,R,Temp : Longint;
  598. begin
  599. Result:=False;
  600. // Use binary search.
  601. L:=0;
  602. R:=FCount-1;
  603. While L<=R do
  604. begin
  605. I:=(L+R) div 2;
  606. Temp:=AnsiCompareText(FList^ [I].FString,S);
  607. If Temp<0 then
  608. L:=I+1
  609. else
  610. begin
  611. R:=I-1;
  612. If Temp=0 then
  613. begin
  614. Result:=True;
  615. If Duplicates<>DupAccept then L:=I;
  616. end;
  617. end;
  618. end;
  619. Index:=L;
  620. end;
  621. Function TStringList.IndexOf(const S: string): Integer;
  622. begin
  623. If Not Sorted then
  624. Result:=Inherited indexOf(S)
  625. else
  626. // faster using binary search...
  627. If Not Find (S,Result) then
  628. Result:=-1;
  629. end;
  630. Procedure TStringList.Insert(Index: Integer; const S: string);
  631. begin
  632. If Sorted then
  633. Error (SSortedListError,0)
  634. else
  635. If (Index<0) or (Index>FCount) then
  636. Error (SListIndexError,Index)
  637. else
  638. InsertItem (Index,S);
  639. end;
  640. Procedure TStringList.Sort;
  641. begin
  642. If Not Sorted and (FCount>1) then
  643. begin
  644. Changing;
  645. QuickSOrt(0,FCount-1);
  646. Changed;
  647. end;
  648. end;
  649. {
  650. $Log$
  651. Revision 1.4 1999-05-26 13:22:23 michael
  652. + Fixed insertitem
  653. Revision 1.3 1999/04/27 07:46:18 michael
  654. * Fixed bug that caused error in loadfromstream when last line in stream has not CRLF pair
  655. Revision 1.2 1999/04/15 07:51:45 michael
  656. + Bugfix in strings.Loadfromstream
  657. Revision 1.1 1999/04/13 08:52:28 michael
  658. + Moved strings.inc to stringl.inc, to avoid conflict with strings unit
  659. Revision 1.15 1999/04/08 10:18:56 peter
  660. * makefile updates
  661. }