inifiles.pp 21 KB

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