inifiles.pp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788
  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. procedure Clear;
  64. property Items[Index: integer]: TIniFileKey read GetItem; default;
  65. end;
  66. TIniFileSection = class
  67. FName: string;
  68. FKeyList: TIniFileKeyList;
  69. public
  70. constructor Create(AName: string);
  71. destructor Destroy; override;
  72. property Name: string read FName;
  73. property KeyList: TIniFileKeyList read FKeyList;
  74. end;
  75. TIniFileSectionList = class(TList)
  76. private
  77. function GetItem(Index: integer): TIniFileSection;
  78. function SectionByName(AName: string): TIniFileSection;
  79. public
  80. procedure Clear;
  81. property Items[Index: integer]: TIniFileSection read GetItem; default;
  82. end;
  83. TCustomIniFile = class
  84. FFileName: string;
  85. FSectionList: TIniFileSectionList;
  86. FEscapeLineFeeds: boolean;
  87. public
  88. constructor Create(const AFileName: string);
  89. destructor Destroy; override;
  90. function SectionExists(const Section: string): Boolean; virtual;
  91. function ReadString(const Section, Ident, Default: string): string; virtual; abstract;
  92. procedure WriteString(const Section, Ident, Value: String); virtual; abstract;
  93. function ReadInteger(const Section, Ident: string; Default: Longint): Longint; virtual;
  94. procedure WriteInteger(const Section, Ident: string; Value: Longint); virtual;
  95. function ReadBool(const Section, Ident: string; Default: Boolean): Boolean; virtual;
  96. procedure WriteBool(const Section, Ident: string; Value: Boolean); virtual;
  97. function ReadDate(const Section, Ident: string; Default: TDateTime): TDateTime; virtual;
  98. function ReadDateTime(const Section, Ident: string; Default: TDateTime): TDateTime; virtual;
  99. function ReadFloat(const Section, Ident: string; Default: Double): Double; virtual;
  100. function ReadTime(const Section, Ident: string; Default: TDateTime): TDateTime; virtual;
  101. procedure WriteDate(const Section, Ident: string; Value: TDateTime); virtual;
  102. procedure WriteDateTime(const Section, Ident: string; Value: TDateTime); virtual;
  103. procedure WriteFloat(const Section, Ident: string; Value: Double); virtual;
  104. procedure WriteTime(const Section, Ident: string; Value: TDateTime); virtual;
  105. procedure ReadSection(const Section: string; Strings: TStrings); virtual; abstract;
  106. procedure ReadSections(Strings: TStrings); virtual; abstract;
  107. procedure ReadSectionValues(const Section: string; Strings: TStrings); virtual; abstract;
  108. procedure EraseSection(const Section: string); virtual; abstract;
  109. procedure DeleteKey(const Section, Ident: String); virtual; abstract;
  110. procedure UpdateFile; virtual; abstract;
  111. function ValueExists(const Section, Ident: string): Boolean; virtual;
  112. property FileName: string read FFileName;
  113. property EscapeLineFeeds: boolean read FEscapeLineFeeds write FEscapeLineFeeds;
  114. end;
  115. TIniFile = class(TCustomIniFile)
  116. FStream: TStream;
  117. private
  118. procedure FillSectionList(AStrings: TStrings);
  119. public
  120. constructor Create(const AFileName: string);
  121. constructor Create(AStream: TStream);
  122. function ReadString(const Section, Ident, Default: string): string; override;
  123. procedure WriteString(const Section, Ident, Value: String); override;
  124. procedure ReadSection(const Section: string; Strings: TStrings); override;
  125. procedure ReadSectionRaw(const Section: string; Strings: TStrings);
  126. procedure ReadSections(Strings: TStrings); override;
  127. procedure ReadSectionValues(const Section: string; Strings: TStrings); override;
  128. procedure EraseSection(const Section: string); override;
  129. procedure DeleteKey(const Section, Ident: String); override;
  130. procedure UpdateFile; override;
  131. property Stream: TStream read FStream;
  132. end;
  133. TMemIniFile = class(TIniFile)
  134. public
  135. procedure Clear;
  136. procedure GetStrings(List: TStrings);
  137. procedure Rename(const AFileName: string; Reload: Boolean);
  138. procedure SetStrings(List: TStrings);
  139. end;
  140. implementation
  141. const
  142. Brackets : array[0..1] of Char = ('[', ']');
  143. Separator : Char = '=';
  144. Comment : Char = ';';
  145. LF_Escape : Char = '\';
  146. function CharToBool(AChar: char): boolean;
  147. begin
  148. Result := (Achar = '1');
  149. end;
  150. function BoolToChar(ABool: boolean): char;
  151. begin
  152. if ABool then
  153. Result := '1'
  154. else
  155. Result := '0';
  156. end;
  157. function IsComment(AString: string): boolean;
  158. begin
  159. Result := False;
  160. if AString > '' then
  161. Result := (Copy(AString, 1, 1) = Comment);
  162. end;
  163. { TIniFileKey }
  164. constructor TIniFileKey.Create(AIdent, AValue: string);
  165. begin
  166. FIdent := AIdent;
  167. FValue := AValue;
  168. end;
  169. { TIniFileKeyList }
  170. function TIniFileKeyList.GetItem(Index: integer): TIniFileKey;
  171. begin
  172. Result := nil;
  173. if (Index >= 0) and (Index < Count) then
  174. Result := TIniFileKey(inherited Items[Index]);
  175. end;
  176. function TIniFileKeyList.KeyByName(AName: string): TIniFileKey;
  177. var
  178. i: integer;
  179. begin
  180. Result := nil;
  181. if (AName > '') and not IsComment(AName) then
  182. for i := 0 to Count-1 do
  183. if CompareText(Items[i].Ident, AName) = 0 then begin
  184. Result := Items[i];
  185. Break;
  186. end;
  187. end;
  188. procedure TIniFileKeyList.Clear;
  189. var
  190. i: integer;
  191. begin
  192. for i := Count-1 downto 0 do
  193. Items[i].Free;
  194. inherited Clear;
  195. end;
  196. { TIniFileSection }
  197. constructor TIniFileSection.Create(AName: string);
  198. begin
  199. FName := AName;
  200. FKeyList := TIniFileKeyList.Create;
  201. end;
  202. destructor TIniFileSection.Destroy;
  203. begin
  204. FKeyList.Free;
  205. end;
  206. { TIniFileSectionList }
  207. function TIniFileSectionList.GetItem(Index: integer): TIniFileSection;
  208. begin
  209. Result := nil;
  210. if (Index >= 0) and (Index < Count) then
  211. Result := TIniFileSection(inherited Items[Index]);
  212. end;
  213. function TIniFileSectionList.SectionByName(AName: string): TIniFileSection;
  214. var
  215. i: integer;
  216. begin
  217. Result := nil;
  218. if (AName > '') and not IsComment(AName) then
  219. for i := 0 to Count-1 do
  220. if CompareText(Items[i].Name, AName) = 0 then begin
  221. Result := Items[i];
  222. Break;
  223. end;
  224. end;
  225. procedure TIniFileSectionList.Clear;
  226. var
  227. i: integer;
  228. begin
  229. for i := Count-1 downto 0 do
  230. Items[i].Free;
  231. inherited Clear;
  232. end;
  233. { TCustomIniFile }
  234. constructor TCustomIniFile.Create(const AFileName: string);
  235. begin
  236. FFileName := AFileName;
  237. FSectionList := TIniFileSectionList.Create;
  238. FEscapeLineFeeds := False;
  239. end;
  240. destructor TCustomIniFile.Destroy;
  241. begin
  242. FSectionList.Free;
  243. inherited Destroy;
  244. end;
  245. function TCustomIniFile.SectionExists(const Section: string): Boolean;
  246. begin
  247. Result := (FSectionList.SectionByName(Section) <> nil);
  248. end;
  249. function TCustomIniFile.ReadInteger(const Section, Ident: string; Default: Longint): Longint;
  250. var
  251. s: string;
  252. begin
  253. Result := Default;
  254. s := ReadString(Section, Ident, '');
  255. if s > '' then try
  256. // convert hex string
  257. if Pos('0X', UpperCase(s)) = 1 then
  258. s := '$' + Copy(s, 3, Length(s) - 2);
  259. Result := StrToInt(s);
  260. except
  261. on EConvertError do
  262. else raise;
  263. end;
  264. end;
  265. procedure TCustomIniFile.WriteInteger(const Section, Ident: string; Value: Longint);
  266. begin
  267. WriteString(Section, Ident, IntToStr(Value));
  268. end;
  269. function TCustomIniFile.ReadBool(const Section, Ident: string; Default: Boolean): Boolean;
  270. var
  271. s: string;
  272. begin
  273. Result := Default;
  274. s := ReadString(Section, Ident, '');
  275. if s > '' then
  276. Result := CharToBool(s[1]);
  277. end;
  278. procedure TCustomIniFile.WriteBool(const Section, Ident: string; Value: Boolean);
  279. begin
  280. WriteString(Section, Ident, BoolToChar(Value));
  281. end;
  282. function TCustomIniFile.ReadDate(const Section, Ident: string; Default: TDateTime): TDateTime;
  283. var
  284. s: string;
  285. begin
  286. Result := Default;
  287. s := ReadString(Section, Ident, '');
  288. if s > '' then try
  289. Result := StrToDate(s);
  290. except
  291. on EConvertError do
  292. else raise;
  293. end;
  294. end;
  295. function TCustomIniFile.ReadDateTime(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 := StrToDateTime(s);
  303. except
  304. on EConvertError do
  305. else raise;
  306. end;
  307. end;
  308. function TCustomIniFile.ReadFloat(const Section, Ident: string; Default: Double): Double;
  309. var
  310. s: string;
  311. begin
  312. Result := Default;
  313. s := ReadString(Section, Ident, '');
  314. if s > '' then try
  315. Result := StrToFloat(s);
  316. except
  317. on EConvertError do
  318. else raise;
  319. end;
  320. end;
  321. function TCustomIniFile.ReadTime(const Section, Ident: string; Default: TDateTime): TDateTime;
  322. var
  323. s: string;
  324. begin
  325. Result := Default;
  326. s := ReadString(Section, Ident, '');
  327. if s > '' then try
  328. Result := StrToTime(s);
  329. except
  330. on EConvertError do
  331. else raise;
  332. end;
  333. end;
  334. procedure TCustomIniFile.WriteDate(const Section, Ident: string; Value: TDateTime);
  335. begin
  336. WriteString(Section, Ident, DateToStr(Value));
  337. end;
  338. procedure TCustomIniFile.WriteDateTime(const Section, Ident: string; Value: TDateTime);
  339. begin
  340. WriteString(Section, Ident, DateTimeToStr(Value));
  341. end;
  342. procedure TCustomIniFile.WriteFloat(const Section, Ident: string; Value: Double);
  343. begin
  344. WriteString(Section, Ident, FloatToStr(Value));
  345. end;
  346. procedure TCustomIniFile.WriteTime(const Section, Ident: string; Value: TDateTime);
  347. begin
  348. WriteString(Section, Ident, TimeToStr(Value));
  349. end;
  350. function TCustomIniFile.ValueExists(const Section, Ident: string): Boolean;
  351. var
  352. oSection: TIniFileSection;
  353. begin
  354. Result := False;
  355. oSection := FSectionList.SectionByName(Section);
  356. if oSection <> nil then
  357. Result := (oSection.KeyList.KeyByName(Ident) <> nil);
  358. end;
  359. { TIniFile }
  360. constructor TIniFile.Create(const AFileName: string);
  361. var
  362. slLines: TStringList;
  363. begin
  364. inherited Create(AFileName);
  365. FStream := nil;
  366. slLines := TStringList.Create;
  367. try
  368. if FileExists(FFileName) then begin
  369. // read the ini file values
  370. slLines.LoadFromFile(FFileName);
  371. FillSectionList(slLines);
  372. end else
  373. // create a new ini file
  374. slLines.SaveToFile(FFileName);
  375. finally
  376. slLines.Free;
  377. end;
  378. end;
  379. constructor TIniFile.Create(AStream: TStream);
  380. var
  381. slLines: TStringList;
  382. begin
  383. inherited Create('');
  384. FStream := AStream;
  385. slLines := TStringList.Create;
  386. try
  387. // read the ini file values
  388. slLines.LoadFromStream(FStream);
  389. FillSectionList(slLines);
  390. finally
  391. slLines.Free;
  392. end;
  393. end;
  394. procedure TIniFile.FillSectionList(AStrings: TStrings);
  395. var
  396. i,j: integer;
  397. sLine, sIdent, sValue: string;
  398. oSection: TIniFileSection;
  399. procedure RemoveBackslashes;
  400. var
  401. i: integer;
  402. s: string;
  403. bAppendNextLine, bAppended: boolean;
  404. begin
  405. AStrings.BeginUpdate;
  406. try
  407. i := 0;
  408. bAppendNextLine := False;
  409. while i < AStrings.Count do begin
  410. s := AStrings[i];
  411. bAppended := False;
  412. if bAppendNextLine then begin
  413. // add line to previous line
  414. AStrings[i-1] := AStrings[i-1] + Trim(s);
  415. AStrings.Delete(i);
  416. s := AStrings[i-1];
  417. bAppended := True;
  418. end;
  419. bAppendNextLine := (Copy(s, Length(s), 1) = LF_Escape);
  420. if bAppendNextLine then
  421. // remove backslash
  422. AStrings[i] := Copy(s, 1, Length(s) - 1);
  423. if not bAppended then
  424. Inc(i);
  425. end;
  426. finally
  427. AStrings.EndUpdate;
  428. end;
  429. end;
  430. begin
  431. oSection := nil;
  432. FSectionList.Clear;
  433. if FEscapeLineFeeds then
  434. RemoveBackslashes;
  435. for i := 0 to AStrings.Count-1 do begin
  436. sLine := Trim(AStrings[i]);
  437. if sLine > '' then
  438. begin
  439. if IsComment(sLine) and (oSection = nil) then begin
  440. // comment at the beginning of the ini file
  441. oSection := TIniFileSection.Create(sLine);
  442. FSectionList.Add(oSection);
  443. end;
  444. if (Copy(sLine, 1, 1) = Brackets[0]) and (Copy(sLine, length(sLine), 1) = Brackets[1]) then begin
  445. // regular section
  446. oSection := TIniFileSection.Create(Copy(sLine, 2, Length(sLine) - 2));
  447. FSectionList.Add(oSection);
  448. end else if oSection <> nil then begin
  449. if IsComment(sLine) then begin
  450. // comment within a section
  451. sIdent := sLine;
  452. sValue := '';
  453. end else begin
  454. // regular key
  455. j:=Pos(Separator, sLine);
  456. if j=0 then
  457. begin
  458. sIdent:='';
  459. sValue:=sLine
  460. end
  461. else
  462. begin
  463. sIdent:=Trim(Copy(sLine, 1, j - 1));
  464. sValue:=Trim(Copy(sLine, j + 1, Length(sLine) - j));
  465. end;
  466. end;
  467. oSection.KeyList.Add(TIniFileKey.Create(sIdent, sValue));
  468. end;
  469. end;
  470. end;
  471. end;
  472. function TIniFile.ReadString(const Section, Ident, Default: string): string;
  473. var
  474. oSection: TIniFileSection;
  475. oKey: TIniFileKey;
  476. begin
  477. Result := Default;
  478. oSection := FSectionList.SectionByName(Section);
  479. if oSection <> nil then begin
  480. oKey := oSection.KeyList.KeyByName(Ident);
  481. if oKey <> nil then
  482. Result := oKey.Value;
  483. end;
  484. end;
  485. procedure TIniFile.WriteString(const Section, Ident, Value: String);
  486. var
  487. oSection: TIniFileSection;
  488. oKey: TIniFileKey;
  489. begin
  490. if (Section > '') and (Ident > '') then begin
  491. // update or add key
  492. oSection := FSectionList.SectionByName(Section);
  493. if (Value > '') then begin
  494. if oSection = nil then begin
  495. oSection := TIniFileSection.Create(Section);
  496. FSectionList.Add(oSection);
  497. end;
  498. with oSection.KeyList do begin
  499. oKey := KeyByName(Ident);
  500. if oKey <> nil then
  501. oKey.Value := Value
  502. else
  503. oSection.KeyList.Add(TIniFileKey.Create(Ident, Value));
  504. end;
  505. end else if oSection <> nil then begin
  506. // remove key
  507. oKey := oSection.KeyList.KeyByName(Ident);
  508. if oKey <> nil then begin
  509. oSection.KeyList.Remove(oKey);
  510. end;
  511. end;
  512. UpdateFile;
  513. end;
  514. end;
  515. procedure TIniFile.ReadSection(const Section: string; Strings: TStrings);
  516. var
  517. oSection: TIniFileSection;
  518. i: integer;
  519. begin
  520. Strings.BeginUpdate;
  521. try
  522. Strings.Clear;
  523. oSection := FSectionList.SectionByName(Section);
  524. if oSection <> nil then with oSection.KeyList do
  525. for i := 0 to Count-1 do
  526. if not IsComment(Items[i].Ident) then
  527. Strings.Add(Items[i].Ident);
  528. finally
  529. Strings.EndUpdate;
  530. end;
  531. end;
  532. procedure TIniFile.ReadSectionRaw(const Section: string; Strings: TStrings);
  533. var
  534. oSection: TIniFileSection;
  535. i: integer;
  536. begin
  537. Strings.BeginUpdate;
  538. try
  539. Strings.Clear;
  540. oSection := FSectionList.SectionByName(Section);
  541. if oSection <> nil then with oSection.KeyList do
  542. for i := 0 to Count-1 do
  543. if not IsComment(Items[i].Ident) then
  544. begin
  545. if Items[i].Ident<>'' then
  546. Strings.Add(Items[i].Ident + Separator +Items[i].Value)
  547. else
  548. Strings.Add(Items[i].Value);
  549. end;
  550. finally
  551. Strings.EndUpdate;
  552. end;
  553. end;
  554. procedure TIniFile.ReadSections(Strings: TStrings);
  555. var
  556. i: integer;
  557. begin
  558. Strings.BeginUpdate;
  559. try
  560. Strings.Clear;
  561. for i := 0 to FSectionList.Count-1 do
  562. if not IsComment(FSectionList[i].Name) then
  563. Strings.Add(FSectionList[i].Name);
  564. finally
  565. Strings.EndUpdate;
  566. end;
  567. end;
  568. procedure TIniFile.ReadSectionValues(const Section: string; Strings: TStrings);
  569. var
  570. oSection: TIniFileSection;
  571. s: string;
  572. i: integer;
  573. begin
  574. Strings.BeginUpdate;
  575. try
  576. Strings.Clear;
  577. oSection := FSectionList.SectionByName(Section);
  578. if oSection <> nil then with oSection.KeyList do
  579. for i := 0 to Count-1 do begin
  580. s := Items[i].Value;
  581. if s > '' then
  582. Strings.Add(s);
  583. end;
  584. finally
  585. Strings.EndUpdate;
  586. end;
  587. end;
  588. procedure TIniFile.EraseSection(const Section: string);
  589. var
  590. oSection: TIniFileSection;
  591. begin
  592. oSection := FSectionList.SectionByName(Section);
  593. if oSection <> nil then begin
  594. oSection.Free;
  595. UpdateFile;
  596. end;
  597. end;
  598. procedure TIniFile.DeleteKey(const Section, Ident: String);
  599. var
  600. oSection: TIniFileSection;
  601. oKey: TIniFileKey;
  602. begin
  603. oSection := FSectionList.SectionByName(Section);
  604. if oSection <> nil then begin
  605. oKey := oSection.KeyList.KeyByName(Ident);
  606. if oKey <> nil then begin
  607. oKey.Free;
  608. UpdateFile;
  609. end;
  610. end;
  611. end;
  612. procedure TIniFile.UpdateFile;
  613. var
  614. slLines: TStringList;
  615. i, j: integer;
  616. begin
  617. slLines := TStringList.Create;
  618. try
  619. for i := 0 to FSectionList.Count-1 do
  620. with FSectionList[i] do begin
  621. if IsComment(Name) then
  622. // comment
  623. slLines.Add(Name)
  624. else
  625. // regular section
  626. slLines.Add(Brackets[0] + Name + Brackets[1]);
  627. for j := 0 to KeyList.Count-1 do
  628. if IsComment(KeyList[j].Ident) then
  629. // comment
  630. slLines.Add(KeyList[j].Ident)
  631. else
  632. // regular key
  633. slLines.Add(KeyList[j].Ident + Separator + KeyList[j].Value);
  634. if (i < FSectionList.Count-1) and not IsComment(Name) then
  635. slLines.Add('');
  636. end;
  637. if FFileName > '' then
  638. slLines.SaveToFile(FFileName)
  639. else if FStream <> nil then
  640. slLines.SaveToStream(FStream);
  641. FillSectionList(slLines);
  642. finally
  643. slLines.Free;
  644. end;
  645. end;
  646. { TMemIniFile }
  647. procedure TMemIniFile.Clear;
  648. begin
  649. FSectionList.Clear;
  650. end;
  651. procedure TMemIniFile.GetStrings(List: TStrings);
  652. var
  653. i, j: integer;
  654. oSection: TIniFileSection;
  655. begin
  656. List.BeginUpdate;
  657. try
  658. for i := 0 to FSectionList.Count-1 do begin
  659. oSection := FSectionList[i];
  660. with oSection do begin
  661. if IsComment(Name) then
  662. List.Add(Name)
  663. else
  664. List.Add(Brackets[0] + Name + Brackets[1]);
  665. for j := 0 to KeyList.Count-1 do begin
  666. if IsComment(KeyList[j].Ident) then
  667. List.Add(KeyList[j].Ident)
  668. else
  669. List.Add(KeyList[j].Ident + Separator + KeyList[j].Value);
  670. end;
  671. end;
  672. if i < FSectionList.Count-1 then
  673. List.Add('');
  674. end;
  675. finally
  676. List.EndUpdate;
  677. end;
  678. end;
  679. procedure TMemIniFile.Rename(const AFileName: string; Reload: Boolean);
  680. var
  681. slLines: TStringList;
  682. begin
  683. FFileName := AFileName;
  684. FStream := nil;
  685. if Reload then begin
  686. slLines := TStringList.Create;
  687. try
  688. slLines.LoadFromFile(FFileName);
  689. FillSectionList(slLines);
  690. finally
  691. slLines.Free;
  692. end;
  693. end;
  694. end;
  695. procedure TMemIniFile.SetStrings(List: TStrings);
  696. begin
  697. FillSectionList(List);
  698. end;
  699. end.
  700. {
  701. $Log$
  702. Revision 1.3 2000-11-26 22:43:02 michael
  703. + Merged fix from fixes branch
  704. Revision 1.1.2.1 2000/11/26 22:41:26 michael
  705. + Fix for addition of empty ident/value by Jean-Pierre Planas
  706. Revision 1.2 2000/07/13 11:32:59 michael
  707. + removed logs
  708. Revision 1.1 2000/07/13 06:31:30 michael
  709. + Initial import
  710. }