inifiles.pp 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. {
  2. $Id$
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 Erik WachtMeester.
  5. File which provides TIniFile and friends.
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. {* Original disclaimer:
  13. * FCL inifiles.pp rewrite by Erik Wachtmeester ([email protected])
  14. *
  15. * Proposed replacement for inifiles.pp v 1.8
  16. *
  17. * This version is Borland Delphi 5 compatible, implementing the classes
  18. * TCustomIniFile, TIniFile and TMemIniFile, with all the public
  19. * properties and methods that Delphi 5 implements.
  20. *
  21. * (inifiles.pp v 1.8 only implements TIniFile with some properties and
  22. * methods missing, and some functionality added)
  23. *
  24. * In order to stay compatible with v 1.8, I added:
  25. * - TIniFile can be created and loaded from, and saved to a stream.
  26. * - ReadSectionRaw method (although it doesn't add empty lines to the
  27. * TStrings recipient like v 1.8, since empty lines aren't stored in
  28. * the SectionList object structure)
  29. * - ReadInteger supports '0x' type hex formats
  30. * - Comment support (this isn't standard in ini files)
  31. * - EscapeLineFeeds property
  32. *
  33. * Since the SectionList object structure is very different from the
  34. * way Delphi 5 accesses ini files (Delphi mostly uses Windows calls
  35. * like GetPrivateProfileString, etc.) it's completely platform
  36. * independant, and probably faster.
  37. * The only drawback is memory consumption: all sections, keys and
  38. * values are kept in memory. But same goes for inifiles.pp v 1.8
  39. * (the FFileBuffer member) and for Delphi's TMemIniFile.
  40. * Anyway, Windows restricts ini files to 64K max, so this shouldn't be
  41. * too much of a problem.
  42. *
  43. *}
  44. unit IniFiles;
  45. {$mode objfpc}
  46. {$H+}
  47. interface
  48. uses classes, sysutils;
  49. type
  50. TIniFileKey = class
  51. FIdent: string;
  52. FValue: string;
  53. public
  54. constructor Create(AIdent, AValue: string);
  55. property Ident: string read FIdent write FIdent;
  56. property Value: string read FValue write FValue;
  57. end;
  58. TIniFileKeyList = class(TList)
  59. private
  60. function GetItem(Index: integer): TIniFileKey;
  61. function KeyByName(AName: string): TIniFileKey;
  62. public
  63. destructor Destroy; override;
  64. procedure Clear;
  65. override;
  66. property Items[Index: integer]: TIniFileKey read GetItem; default;
  67. end;
  68. TIniFileSection = class
  69. FName: string;
  70. FKeyList: TIniFileKeyList;
  71. public
  72. constructor Create(AName: string);
  73. destructor Destroy; override;
  74. property Name: string read FName;
  75. property KeyList: TIniFileKeyList read FKeyList;
  76. end;
  77. TIniFileSectionList = class(TList)
  78. private
  79. function GetItem(Index: integer): TIniFileSection;
  80. function SectionByName(AName: string): TIniFileSection;
  81. public
  82. destructor Destroy; override;
  83. procedure Clear;override;
  84. property Items[Index: integer]: TIniFileSection read GetItem; default;
  85. end;
  86. TCustomIniFile = class
  87. FFileName: string;
  88. FSectionList: TIniFileSectionList;
  89. FEscapeLineFeeds: boolean;
  90. public
  91. constructor Create(const AFileName: string);
  92. destructor Destroy; override;
  93. function SectionExists(const Section: string): Boolean; virtual;
  94. function ReadString(const Section, Ident, Default: string): string; virtual; abstract;
  95. procedure WriteString(const Section, Ident, Value: String); virtual; abstract;
  96. function ReadInteger(const Section, Ident: string; Default: Longint): Longint; virtual;
  97. procedure WriteInteger(const Section, Ident: string; Value: Longint); virtual;
  98. function ReadBool(const Section, Ident: string; Default: Boolean): Boolean; virtual;
  99. procedure WriteBool(const Section, Ident: string; Value: Boolean); virtual;
  100. function ReadDate(const Section, Ident: string; Default: TDateTime): TDateTime; virtual;
  101. function ReadDateTime(const Section, Ident: string; Default: TDateTime): TDateTime; virtual;
  102. function ReadFloat(const Section, Ident: string; Default: Double): Double; virtual;
  103. function ReadTime(const Section, Ident: string; Default: TDateTime): TDateTime; virtual;
  104. procedure WriteDate(const Section, Ident: string; Value: TDateTime); virtual;
  105. procedure WriteDateTime(const Section, Ident: string; Value: TDateTime); virtual;
  106. procedure WriteFloat(const Section, Ident: string; Value: Double); virtual;
  107. procedure WriteTime(const Section, Ident: string; Value: TDateTime); virtual;
  108. procedure ReadSection(const Section: string; Strings: TStrings); virtual; abstract;
  109. procedure ReadSections(Strings: TStrings); virtual; abstract;
  110. procedure ReadSectionValues(const Section: string; Strings: TStrings); virtual; abstract;
  111. procedure EraseSection(const Section: string); virtual; abstract;
  112. procedure DeleteKey(const Section, Ident: String); virtual; abstract;
  113. procedure UpdateFile; virtual; abstract;
  114. function ValueExists(const Section, Ident: string): Boolean; virtual;
  115. property FileName: string read FFileName;
  116. property EscapeLineFeeds: boolean read FEscapeLineFeeds write FEscapeLineFeeds;
  117. end;
  118. TIniFile = class(TCustomIniFile)
  119. FStream: TStream;
  120. private
  121. procedure FillSectionList(AStrings: TStrings);
  122. public
  123. constructor Create(const AFileName: string);
  124. constructor Create(AStream: TStream);
  125. function ReadString(const Section, Ident, Default: string): string; override;
  126. procedure WriteString(const Section, Ident, Value: String); override;
  127. procedure ReadSection(const Section: string; Strings: TStrings); override;
  128. procedure ReadSectionRaw(const Section: string; Strings: TStrings);
  129. procedure ReadSections(Strings: TStrings); override;
  130. procedure ReadSectionValues(const Section: string; Strings: TStrings); override;
  131. procedure EraseSection(const Section: string); override;
  132. procedure DeleteKey(const Section, Ident: String); override;
  133. procedure UpdateFile; override;
  134. property Stream: TStream read FStream;
  135. end;
  136. TMemIniFile = class(TIniFile)
  137. public
  138. procedure Clear;
  139. procedure GetStrings(List: TStrings);
  140. procedure Rename(const AFileName: string; Reload: Boolean);
  141. procedure SetStrings(List: TStrings);
  142. end;
  143. implementation
  144. const
  145. Brackets : array[0..1] of Char = ('[', ']');
  146. Separator : Char = '=';
  147. Comment : Char = ';';
  148. LF_Escape : Char = '\';
  149. function CharToBool(AChar: char): boolean;
  150. begin
  151. Result := (Achar = '1');
  152. end;
  153. function BoolToChar(ABool: boolean): char;
  154. begin
  155. if ABool then
  156. Result := '1'
  157. else
  158. Result := '0';
  159. end;
  160. function IsComment(AString: string): boolean;
  161. begin
  162. Result := False;
  163. if AString > '' then
  164. Result := (Copy(AString, 1, 1) = Comment);
  165. end;
  166. { TIniFileKey }
  167. constructor TIniFileKey.Create(AIdent, AValue: string);
  168. begin
  169. FIdent := AIdent;
  170. FValue := AValue;
  171. end;
  172. { TIniFileKeyList }
  173. function TIniFileKeyList.GetItem(Index: integer): TIniFileKey;
  174. begin
  175. Result := nil;
  176. if (Index >= 0) and (Index < Count) then
  177. Result := TIniFileKey(inherited Items[Index]);
  178. end;
  179. function TIniFileKeyList.KeyByName(AName: string): TIniFileKey;
  180. var
  181. i: integer;
  182. begin
  183. Result := nil;
  184. if (AName > '') and not IsComment(AName) then
  185. for i := 0 to Count-1 do
  186. if CompareText(Items[i].Ident, AName) = 0 then begin
  187. Result := Items[i];
  188. Break;
  189. end;
  190. end;
  191. destructor TIniFileKeyList.Destroy;
  192. begin
  193. Clear;
  194. inherited Destroy;
  195. end;
  196. procedure TIniFileKeyList.Clear;
  197. var
  198. i: integer;
  199. begin
  200. for i := Count-1 downto 0 do
  201. Items[i].Free;
  202. inherited Clear;
  203. end;
  204. { TIniFileSection }
  205. constructor TIniFileSection.Create(AName: string);
  206. begin
  207. FName := AName;
  208. FKeyList := TIniFileKeyList.Create;
  209. end;
  210. destructor TIniFileSection.Destroy;
  211. begin
  212. FKeyList.Free;
  213. end;
  214. { TIniFileSectionList }
  215. function TIniFileSectionList.GetItem(Index: integer): TIniFileSection;
  216. begin
  217. Result := nil;
  218. if (Index >= 0) and (Index < Count) then
  219. Result := TIniFileSection(inherited Items[Index]);
  220. end;
  221. function TIniFileSectionList.SectionByName(AName: string): TIniFileSection;
  222. var
  223. i: integer;
  224. begin
  225. Result := nil;
  226. if (AName > '') and not IsComment(AName) then
  227. for i := 0 to Count-1 do
  228. if CompareText(Items[i].Name, AName) = 0 then begin
  229. Result := Items[i];
  230. Break;
  231. end;
  232. end;
  233. destructor TIniFileSectionList.Destroy;
  234. begin
  235. Clear;
  236. inherited Destroy;
  237. end;
  238. procedure TIniFileSectionList.Clear;
  239. var
  240. i: integer;
  241. begin
  242. for i := Count-1 downto 0 do
  243. Items[i].Free;
  244. inherited Clear;
  245. end;
  246. { TCustomIniFile }
  247. constructor TCustomIniFile.Create(const AFileName: string);
  248. begin
  249. FFileName := AFileName;
  250. FSectionList := TIniFileSectionList.Create;
  251. FEscapeLineFeeds := False;
  252. end;
  253. destructor TCustomIniFile.Destroy;
  254. begin
  255. FSectionList.Free;
  256. inherited Destroy;
  257. end;
  258. function TCustomIniFile.SectionExists(const Section: string): Boolean;
  259. begin
  260. Result := (FSectionList.SectionByName(Section) <> nil);
  261. end;
  262. function TCustomIniFile.ReadInteger(const Section, Ident: string; Default: Longint): Longint;
  263. var
  264. s: string;
  265. begin
  266. Result := Default;
  267. s := ReadString(Section, Ident, '');
  268. if s > '' then try
  269. // convert hex string
  270. if Pos('0X', UpperCase(s)) = 1 then
  271. s := '$' + Copy(s, 3, Length(s) - 2);
  272. Result := StrToInt(s);
  273. except
  274. on EConvertError do
  275. else raise;
  276. end;
  277. end;
  278. procedure TCustomIniFile.WriteInteger(const Section, Ident: string; Value: Longint);
  279. begin
  280. WriteString(Section, Ident, IntToStr(Value));
  281. end;
  282. function TCustomIniFile.ReadBool(const Section, Ident: string; Default: Boolean): Boolean;
  283. var
  284. s: string;
  285. begin
  286. Result := Default;
  287. s := ReadString(Section, Ident, '');
  288. if s > '' then
  289. Result := CharToBool(s[1]);
  290. end;
  291. procedure TCustomIniFile.WriteBool(const Section, Ident: string; Value: Boolean);
  292. begin
  293. WriteString(Section, Ident, BoolToChar(Value));
  294. end;
  295. function TCustomIniFile.ReadDate(const Section, Ident: string; Default: TDateTime): TDateTime;
  296. var
  297. s: string;
  298. begin
  299. Result := Default;
  300. s := ReadString(Section, Ident, '');
  301. if s > '' then try
  302. Result := StrToDate(s);
  303. except
  304. on EConvertError do
  305. else raise;
  306. end;
  307. end;
  308. function TCustomIniFile.ReadDateTime(const Section, Ident: string; Default: TDateTime): TDateTime;
  309. var
  310. s: string;
  311. begin
  312. Result := Default;
  313. s := ReadString(Section, Ident, '');
  314. if s > '' then try
  315. Result := StrToDateTime(s);
  316. except
  317. on EConvertError do
  318. else raise;
  319. end;
  320. end;
  321. function TCustomIniFile.ReadFloat(const Section, Ident: string; Default: Double): Double;
  322. var
  323. s: string;
  324. begin
  325. Result := Default;
  326. s := ReadString(Section, Ident, '');
  327. if s > '' then try
  328. Result := StrToFloat(s);
  329. except
  330. on EConvertError do
  331. else raise;
  332. end;
  333. end;
  334. function TCustomIniFile.ReadTime(const Section, Ident: string; Default: TDateTime): TDateTime;
  335. var
  336. s: string;
  337. begin
  338. Result := Default;
  339. s := ReadString(Section, Ident, '');
  340. if s > '' then try
  341. Result := StrToTime(s);
  342. except
  343. on EConvertError do
  344. else raise;
  345. end;
  346. end;
  347. procedure TCustomIniFile.WriteDate(const Section, Ident: string; Value: TDateTime);
  348. begin
  349. WriteString(Section, Ident, DateToStr(Value));
  350. end;
  351. procedure TCustomIniFile.WriteDateTime(const Section, Ident: string; Value: TDateTime);
  352. begin
  353. WriteString(Section, Ident, DateTimeToStr(Value));
  354. end;
  355. procedure TCustomIniFile.WriteFloat(const Section, Ident: string; Value: Double);
  356. begin
  357. WriteString(Section, Ident, FloatToStr(Value));
  358. end;
  359. procedure TCustomIniFile.WriteTime(const Section, Ident: string; Value: TDateTime);
  360. begin
  361. WriteString(Section, Ident, TimeToStr(Value));
  362. end;
  363. function TCustomIniFile.ValueExists(const Section, Ident: string): Boolean;
  364. var
  365. oSection: TIniFileSection;
  366. begin
  367. Result := False;
  368. oSection := FSectionList.SectionByName(Section);
  369. if oSection <> nil then
  370. Result := (oSection.KeyList.KeyByName(Ident) <> nil);
  371. end;
  372. { TIniFile }
  373. constructor TIniFile.Create(const AFileName: string);
  374. var
  375. slLines: TStringList;
  376. begin
  377. inherited Create(AFileName);
  378. FStream := nil;
  379. slLines := TStringList.Create;
  380. try
  381. if FileExists(FFileName) then begin
  382. // read the ini file values
  383. slLines.LoadFromFile(FFileName);
  384. FillSectionList(slLines);
  385. end else
  386. // create a new ini file
  387. slLines.SaveToFile(FFileName);
  388. finally
  389. slLines.Free;
  390. end;
  391. end;
  392. constructor TIniFile.Create(AStream: TStream);
  393. var
  394. slLines: TStringList;
  395. begin
  396. inherited Create('');
  397. FStream := AStream;
  398. slLines := TStringList.Create;
  399. try
  400. // read the ini file values
  401. slLines.LoadFromStream(FStream);
  402. FillSectionList(slLines);
  403. finally
  404. slLines.Free;
  405. end;
  406. end;
  407. procedure TIniFile.FillSectionList(AStrings: TStrings);
  408. var
  409. i,j: integer;
  410. sLine, sIdent, sValue: string;
  411. oSection: TIniFileSection;
  412. procedure RemoveBackslashes;
  413. var
  414. i: integer;
  415. s: string;
  416. bAppendNextLine, bAppended: boolean;
  417. begin
  418. AStrings.BeginUpdate;
  419. try
  420. i := 0;
  421. bAppendNextLine := False;
  422. while i < AStrings.Count do begin
  423. s := AStrings[i];
  424. bAppended := False;
  425. if bAppendNextLine then begin
  426. // add line to previous line
  427. AStrings[i-1] := AStrings[i-1] + Trim(s);
  428. AStrings.Delete(i);
  429. s := AStrings[i-1];
  430. bAppended := True;
  431. end;
  432. bAppendNextLine := (Copy(s, Length(s), 1) = LF_Escape);
  433. if bAppendNextLine then
  434. // remove backslash
  435. AStrings[i] := Copy(s, 1, Length(s) - 1);
  436. if not bAppended then
  437. Inc(i);
  438. end;
  439. finally
  440. AStrings.EndUpdate;
  441. end;
  442. end;
  443. begin
  444. oSection := nil;
  445. FSectionList.Clear;
  446. if FEscapeLineFeeds then
  447. RemoveBackslashes;
  448. for i := 0 to AStrings.Count-1 do begin
  449. sLine := Trim(AStrings[i]);
  450. if sLine > '' then
  451. begin
  452. if IsComment(sLine) and (oSection = nil) then begin
  453. // comment at the beginning of the ini file
  454. oSection := TIniFileSection.Create(sLine);
  455. FSectionList.Add(oSection);
  456. end;
  457. if (Copy(sLine, 1, 1) = Brackets[0]) and (Copy(sLine, length(sLine), 1) = Brackets[1]) then begin
  458. // regular section
  459. oSection := TIniFileSection.Create(Copy(sLine, 2, Length(sLine) - 2));
  460. FSectionList.Add(oSection);
  461. end else if oSection <> nil then begin
  462. if IsComment(sLine) then begin
  463. // comment within a section
  464. sIdent := sLine;
  465. sValue := '';
  466. end else begin
  467. // regular key
  468. j:=Pos(Separator, sLine);
  469. if j=0 then
  470. begin
  471. sIdent:='';
  472. sValue:=sLine
  473. end
  474. else
  475. begin
  476. sIdent:=Trim(Copy(sLine, 1, j - 1));
  477. sValue:=Trim(Copy(sLine, j + 1, Length(sLine) - j));
  478. end;
  479. end;
  480. oSection.KeyList.Add(TIniFileKey.Create(sIdent, sValue));
  481. end;
  482. end;
  483. end;
  484. end;
  485. function TIniFile.ReadString(const Section, Ident, Default: string): string;
  486. var
  487. oSection: TIniFileSection;
  488. oKey: TIniFileKey;
  489. begin
  490. Result := Default;
  491. oSection := FSectionList.SectionByName(Section);
  492. if oSection <> nil then begin
  493. oKey := oSection.KeyList.KeyByName(Ident);
  494. if oKey <> nil then
  495. Result := oKey.Value;
  496. end;
  497. end;
  498. procedure TIniFile.WriteString(const Section, Ident, Value: String);
  499. var
  500. oSection: TIniFileSection;
  501. oKey: TIniFileKey;
  502. begin
  503. if (Section > '') and (Ident > '') then begin
  504. // update or add key
  505. oSection := FSectionList.SectionByName(Section);
  506. if (Value > '') then begin
  507. if oSection = nil then begin
  508. oSection := TIniFileSection.Create(Section);
  509. FSectionList.Add(oSection);
  510. end;
  511. with oSection.KeyList do begin
  512. oKey := KeyByName(Ident);
  513. if oKey <> nil then
  514. oKey.Value := Value
  515. else
  516. oSection.KeyList.Add(TIniFileKey.Create(Ident, Value));
  517. end;
  518. end else if oSection <> nil then begin
  519. // remove key
  520. oKey := oSection.KeyList.KeyByName(Ident);
  521. if oKey <> nil then begin
  522. oSection.KeyList.Remove(oKey);
  523. end;
  524. end;
  525. UpdateFile;
  526. end;
  527. end;
  528. procedure TIniFile.ReadSection(const Section: string; Strings: TStrings);
  529. var
  530. oSection: TIniFileSection;
  531. i: integer;
  532. begin
  533. Strings.BeginUpdate;
  534. try
  535. Strings.Clear;
  536. oSection := FSectionList.SectionByName(Section);
  537. if oSection <> nil then with oSection.KeyList do
  538. for i := 0 to Count-1 do
  539. if not IsComment(Items[i].Ident) then
  540. Strings.Add(Items[i].Ident);
  541. finally
  542. Strings.EndUpdate;
  543. end;
  544. end;
  545. procedure TIniFile.ReadSectionRaw(const Section: string; Strings: TStrings);
  546. var
  547. oSection: TIniFileSection;
  548. i: integer;
  549. begin
  550. Strings.BeginUpdate;
  551. try
  552. Strings.Clear;
  553. oSection := FSectionList.SectionByName(Section);
  554. if oSection <> nil then with oSection.KeyList do
  555. for i := 0 to Count-1 do
  556. if not IsComment(Items[i].Ident) then
  557. begin
  558. if Items[i].Ident<>'' then
  559. Strings.Add(Items[i].Ident + Separator +Items[i].Value)
  560. else
  561. Strings.Add(Items[i].Value);
  562. end;
  563. finally
  564. Strings.EndUpdate;
  565. end;
  566. end;
  567. procedure TIniFile.ReadSections(Strings: TStrings);
  568. var
  569. i: integer;
  570. begin
  571. Strings.BeginUpdate;
  572. try
  573. Strings.Clear;
  574. for i := 0 to FSectionList.Count-1 do
  575. if not IsComment(FSectionList[i].Name) then
  576. Strings.Add(FSectionList[i].Name);
  577. finally
  578. Strings.EndUpdate;
  579. end;
  580. end;
  581. procedure TIniFile.ReadSectionValues(const Section: string; Strings: TStrings);
  582. var
  583. oSection: TIniFileSection;
  584. s: string;
  585. i: integer;
  586. begin
  587. Strings.BeginUpdate;
  588. try
  589. Strings.Clear;
  590. oSection := FSectionList.SectionByName(Section);
  591. if oSection <> nil then with oSection.KeyList do
  592. for i := 0 to Count-1 do begin
  593. s := Items[i].Value;
  594. if s > '' then
  595. Strings.Add(s);
  596. end;
  597. finally
  598. Strings.EndUpdate;
  599. end;
  600. end;
  601. procedure TIniFile.EraseSection(const Section: string);
  602. var
  603. oSection: TIniFileSection;
  604. begin
  605. oSection := FSectionList.SectionByName(Section);
  606. if oSection <> nil then begin
  607. oSection.Free;
  608. UpdateFile;
  609. end;
  610. end;
  611. procedure TIniFile.DeleteKey(const Section, Ident: String);
  612. var
  613. oSection: TIniFileSection;
  614. oKey: TIniFileKey;
  615. begin
  616. oSection := FSectionList.SectionByName(Section);
  617. if oSection <> nil then begin
  618. oKey := oSection.KeyList.KeyByName(Ident);
  619. if oKey <> nil then begin
  620. oKey.Free;
  621. UpdateFile;
  622. end;
  623. end;
  624. end;
  625. procedure TIniFile.UpdateFile;
  626. var
  627. slLines: TStringList;
  628. i, j: integer;
  629. begin
  630. slLines := TStringList.Create;
  631. try
  632. for i := 0 to FSectionList.Count-1 do
  633. with FSectionList[i] do begin
  634. if IsComment(Name) then
  635. // comment
  636. slLines.Add(Name)
  637. else
  638. // regular section
  639. slLines.Add(Brackets[0] + Name + Brackets[1]);
  640. for j := 0 to KeyList.Count-1 do
  641. if IsComment(KeyList[j].Ident) then
  642. // comment
  643. slLines.Add(KeyList[j].Ident)
  644. else
  645. // regular key
  646. slLines.Add(KeyList[j].Ident + Separator + KeyList[j].Value);
  647. if (i < FSectionList.Count-1) and not IsComment(Name) then
  648. slLines.Add('');
  649. end;
  650. if FFileName > '' then
  651. slLines.SaveToFile(FFileName)
  652. else if FStream <> nil then
  653. slLines.SaveToStream(FStream);
  654. FillSectionList(slLines);
  655. finally
  656. slLines.Free;
  657. end;
  658. end;
  659. { TMemIniFile }
  660. procedure TMemIniFile.Clear;
  661. begin
  662. FSectionList.Clear;
  663. end;
  664. procedure TMemIniFile.GetStrings(List: TStrings);
  665. var
  666. i, j: integer;
  667. oSection: TIniFileSection;
  668. begin
  669. List.BeginUpdate;
  670. try
  671. for i := 0 to FSectionList.Count-1 do begin
  672. oSection := FSectionList[i];
  673. with oSection do begin
  674. if IsComment(Name) then
  675. List.Add(Name)
  676. else
  677. List.Add(Brackets[0] + Name + Brackets[1]);
  678. for j := 0 to KeyList.Count-1 do begin
  679. if IsComment(KeyList[j].Ident) then
  680. List.Add(KeyList[j].Ident)
  681. else
  682. List.Add(KeyList[j].Ident + Separator + KeyList[j].Value);
  683. end;
  684. end;
  685. if i < FSectionList.Count-1 then
  686. List.Add('');
  687. end;
  688. finally
  689. List.EndUpdate;
  690. end;
  691. end;
  692. procedure TMemIniFile.Rename(const AFileName: string; Reload: Boolean);
  693. var
  694. slLines: TStringList;
  695. begin
  696. FFileName := AFileName;
  697. FStream := nil;
  698. if Reload then begin
  699. slLines := TStringList.Create;
  700. try
  701. slLines.LoadFromFile(FFileName);
  702. FillSectionList(slLines);
  703. finally
  704. slLines.Free;
  705. end;
  706. end;
  707. end;
  708. procedure TMemIniFile.SetStrings(List: TStrings);
  709. begin
  710. FillSectionList(List);
  711. end;
  712. end.
  713. {
  714. $Log$
  715. Revision 1.6 2002-09-07 15:15:24 peter
  716. * old logs removed and tabs fixed
  717. Revision 1.5 2002/08/13 06:51:06 michael
  718. + Fixed memory leak reported by A. Chuchko (bug report 2079)
  719. Revision 1.4 2002/06/13 17:28:41 michael
  720. + Destructor was not freeing all memory. This is now fixed.
  721. }