inifiles.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. {
  2. $Id$
  3. This file is part of the Free Component Library (FCL)
  4. Copyright (c) 1999-2000 by Michael A. Hess
  5. adapted from code by Stephan Schneider
  6. This program is distributed in the hope that it will be useful,
  7. but WITHOUT ANY WARRANTY; without even the implied warranty of
  8. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  9. **********************************************************************}
  10. unit IniFiles;
  11. {$mode objfpc}
  12. {$H+}
  13. interface
  14. uses Classes;
  15. type
  16. { TIniFile class }
  17. TIniFile = class(TObject)
  18. private
  19. FFileName : string;
  20. FStream : TStream;
  21. FFileBuffer : TStringList;
  22. function GetName(const line : string) : string;
  23. function GetValue(const line, name : string) : string;
  24. function IsComment(const line : string) : boolean;
  25. function IsSection(const line : string) : boolean;
  26. function GetSectionIndex(const section : string) : integer;
  27. protected
  28. procedure SetFileName(const fn:string);
  29. procedure SetStream(s:TStream);
  30. procedure LoadFromFile;
  31. procedure SaveToFile;
  32. procedure LoadFromStream;
  33. procedure SaveToStream;
  34. public
  35. constructor Create(const theFileName : string);
  36. constructor Create(s:TStream);
  37. destructor Destroy; override;
  38. procedure DeleteKey(const section, ident : string);
  39. procedure EraseSection(const section : string);
  40. function ReadBool(const section, ident : string; defaultValue : boolean) : boolean;
  41. function ReadInteger(const section, ident : string; defaultValue : longint) : longint;
  42. procedure ReadSection(const section : string; strings : TStrings);
  43. procedure ReadSections(strings : TStrings);
  44. procedure ReadSectionValues(const section : string; strings : TStrings);
  45. procedure ReadSectionRaw(const section : string; strings : TStrings);
  46. function ReadString(const section, ident, defaultValue : string) : string;
  47. procedure WriteBool(const section, ident : string; value : boolean);
  48. procedure WriteInteger(const section, ident : string; value : longint);
  49. procedure WriteString(const section, ident, value : string);
  50. property FileName : String read FFileName;
  51. end;
  52. implementation
  53. uses SysUtils;
  54. const
  55. brackets : array[0..1] of Char = ('[', ']');
  56. separator : Char = '=';
  57. comment : Char = ';';
  58. { TIniFile }
  59. constructor TIniFile.Create(const theFileName : string);
  60. begin
  61. FFileName := theFileName;
  62. FStream:=nil;
  63. FFileBuffer := TStringList.Create;
  64. if FileExists(fileName) then
  65. LoadFromFile;
  66. end;
  67. constructor TIniFile.Create(s:TStream);
  68. begin
  69. FFileName := '';
  70. FStream:=s;
  71. FFileBuffer := TStringList.Create;
  72. LoadFromStream;
  73. end;
  74. destructor TIniFile.Destroy;
  75. begin
  76. FFileBuffer.Free;
  77. end;
  78. function TIniFile.GetName(const line : string) : string;
  79. var
  80. index,index2 : integer;
  81. begin
  82. Result := '';
  83. index := Pos(separator, line);
  84. if index <> 0 then
  85. begin
  86. index2:=Pos(comment, line);
  87. if (index2=0) or (index2>index) then
  88. result := Trim(Copy(line, 1, index - 1));
  89. end;
  90. end;
  91. function TIniFile.GetValue(const line, name : string) : string;
  92. var
  93. index1,index2,index3 : integer;
  94. begin
  95. result := '';
  96. if (line <> '') and (name <> '') then
  97. begin
  98. index1 := Pos(name, line);
  99. index2 := Pos(separator, line);
  100. index3 := Pos(comment, line);
  101. if index3=0 then
  102. index3:=MaxInt;
  103. if (index1 <> 0) and (index2 <> 0) and (index2 > index1) then
  104. result := Trim(Copy(line, index2 + 1, index3));
  105. end;
  106. end;
  107. function TIniFile.IsSection(const line : string) : boolean;
  108. var
  109. str : string;
  110. begin
  111. result := False;
  112. if line <> '' then
  113. begin
  114. str := Trim(line);
  115. if (str[1] = brackets[0]) and (str[Length(str)] = brackets[1]) then
  116. result := True;
  117. end;
  118. end;
  119. function TIniFile.IsComment(const line : string) : boolean;
  120. var
  121. str : string;
  122. begin
  123. result := False;
  124. if line <> '' then
  125. begin
  126. str := Trim(line);
  127. result := (str[1]=comment);
  128. end;
  129. end;
  130. function TIniFile.GetSectionIndex(const section : string) : integer;
  131. begin
  132. result := FFileBuffer.IndexOf(brackets[0] + section + brackets[1]);
  133. end;
  134. { Load/Save }
  135. procedure TIniFile.SetFileName(const fn:string);
  136. begin
  137. FFileName:=fn;
  138. end;
  139. procedure TIniFile.SetStream(s:TStream);
  140. begin
  141. FStream:=s;
  142. end;
  143. procedure TIniFile.LoadFromFile;
  144. begin
  145. if FFileName<>'' then
  146. FFileBuffer.LoadFromFile(FFileName);
  147. end;
  148. procedure TIniFile.SaveToFile;
  149. begin
  150. if FFileName<>'' then
  151. FFileBuffer.SaveToFile(FFileName);
  152. end;
  153. procedure TIniFile.LoadFromStream;
  154. begin
  155. if assigned(FStream) then
  156. FFileBuffer.LoadFromStream(FStream);
  157. end;
  158. procedure TIniFile.SaveToStream;
  159. begin
  160. if assigned(FStream) then
  161. FFileBuffer.SaveToStream(FStream);
  162. end;
  163. { Read all Names of one Section }
  164. procedure TIniFile.ReadSection(const section : string; strings : TStrings);
  165. var
  166. index : integer;
  167. name : string;
  168. begin
  169. strings.BeginUpdate;
  170. try
  171. strings.Clear;
  172. if FFileBuffer.Count > 0 then
  173. begin
  174. index := GetSectionIndex(section);
  175. if index <> -1 then
  176. begin
  177. Inc(index);
  178. while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) do
  179. begin
  180. name := GetName(FFileBuffer[index]);
  181. if name <> '' then
  182. strings.Add(name);
  183. Inc(index);
  184. end;
  185. end;
  186. end;
  187. finally
  188. strings.EndUpdate;
  189. end;
  190. end;
  191. { Read all Sections of the Ini-File }
  192. procedure TIniFile.ReadSections(strings : TStrings);
  193. var
  194. index : integer;
  195. section : string;
  196. begin
  197. strings.BeginUpdate;
  198. try
  199. strings.Clear;
  200. if FFileBuffer.Count > 0 then
  201. begin
  202. index := 0;
  203. while (index < FFileBuffer.Count) do
  204. begin
  205. if IsSection(FFileBuffer[index]) then
  206. begin
  207. section := Trim(FFileBuffer[index]);
  208. Delete(section, 1, 1);
  209. Delete(section, Length(section), 1);
  210. strings.Add(Trim(section));
  211. end;
  212. Inc(index);
  213. end;
  214. end;
  215. finally
  216. strings.EndUpdate;
  217. end;
  218. end;
  219. { Reads a String-Value of "ident" in one "section".
  220. The result is "defaultValue" if
  221. o section doesn't exists
  222. o ident doesn't exists
  223. o ident doesn't have any assigned value }
  224. function TIniFile.ReadString(const section, ident, defaultValue : string) : string;
  225. var
  226. index : integer;
  227. value : string;
  228. begin
  229. result := defaultValue;
  230. if FFileBuffer.Count > 0 then
  231. begin
  232. index := GetSectionIndex(section);
  233. if index <> -1 then
  234. begin
  235. Inc(index);
  236. while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) do
  237. begin
  238. if GetName(FFileBuffer[index]) = ident then
  239. begin
  240. value := GetValue(FFileBuffer[index], ident);
  241. if value <> '' then
  242. begin
  243. result := value;
  244. if (result[length(result)]='\') then
  245. begin
  246. inc(index);
  247. while (index < FFileBuffer.Count) and (result[length(result)]='\') do
  248. begin
  249. result:=Copy(result,1,length(result)-1)+Trim(FFileBuffer[index]);
  250. inc(index);
  251. end;
  252. end;
  253. end;
  254. break;
  255. end;
  256. Inc(index);
  257. end;
  258. end;
  259. end;
  260. end;
  261. { Reads an Integer-Value of Ident in one Section }
  262. function TIniFile.ReadInteger(const section, ident : string; defaultValue : longint) : longint;
  263. var
  264. intStr : string;
  265. begin
  266. intStr := ReadString(section, ident, '');
  267. { convert a Hex-Value }
  268. if (Length(intStr) > 2) and (intStr[1] = '0') and ((intStr[2] = 'X') or (intStr[2] = 'x')) then
  269. intStr := '$' + Copy(intStr, 3, Maxint);
  270. result := StrToIntDef(intStr, defaultValue);
  271. end;
  272. { Reads a Bool-Value of Ident in one Section }
  273. function TIniFile.ReadBool(const section, ident : string; defaultValue : boolean) : boolean;
  274. begin
  275. result := ReadInteger(section, ident, Ord(defaultValue)) <> 0;
  276. end;
  277. { Reads all Names + Values of one Section }
  278. procedure TIniFile.ReadSectionValues(const section : string; strings : TStrings);
  279. var
  280. name : string;
  281. value : string;
  282. index : integer;
  283. begin
  284. strings.BeginUpdate;
  285. try
  286. strings.Clear;
  287. if FFileBuffer.Count > 0 then
  288. begin
  289. index := GetSectionIndex(section);
  290. if index <> -1 then
  291. begin
  292. Inc(index);
  293. while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) do
  294. begin
  295. name := GetName(FFileBuffer[index]);
  296. if name <> '' then
  297. begin
  298. value := GetValue(FFileBuffer[index], name);
  299. strings.Add(name + separator + value);
  300. end;
  301. Inc(index);
  302. end;
  303. end;
  304. end;
  305. finally
  306. strings.EndUpdate;
  307. end;
  308. end;
  309. procedure TIniFile.ReadSectionRaw(const section : string; strings : TStrings);
  310. var
  311. eols,index : integer;
  312. begin
  313. strings.BeginUpdate;
  314. try
  315. eols:=0;
  316. strings.Clear;
  317. if FFileBuffer.Count > 0 then
  318. begin
  319. index := GetSectionIndex(section);
  320. if index <> -1 then
  321. begin
  322. Inc(index);
  323. while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) do
  324. begin
  325. { Skip empty lines at the end of the section }
  326. if FFileBuffer[index]='' then
  327. inc(eols)
  328. else
  329. begin
  330. while eols>0 do
  331. begin
  332. Strings.Add('');
  333. dec(eols);
  334. end;
  335. if not IsComment(FFileBuffer[index]) then
  336. strings.Add(FFileBuffer[index]);
  337. end;
  338. Inc(index);
  339. end;
  340. end;
  341. end;
  342. finally
  343. strings.EndUpdate;
  344. end;
  345. end;
  346. { Writes a String-Value for Ident in one Section.
  347. Note: If Section and/or Ident don't exist, they will be placed in the Ini-File }
  348. procedure TIniFile.WriteString(const section, ident, value : string);
  349. var
  350. index : integer;
  351. begin
  352. index := GetSectionIndex(section);
  353. { Section exists }
  354. if index <> -1 then
  355. begin
  356. Inc(index);
  357. while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) and
  358. (GetName(FFileBuffer[index]) <> ident) do
  359. Inc(index);
  360. if (index >= FFileBuffer.Count) or IsSection(FFileBuffer[index]) then
  361. begin { End of File or ident doesn't exists in the section }
  362. if ident <> '' then
  363. FFileBuffer.Insert(index, ident + separator + value);
  364. end
  365. else if ident <> '' then { Ident does exists in the section }
  366. FFileBuffer[index] := ident + separator + value;
  367. end
  368. else { section doesn't exists, so add new [section] with ident=value }
  369. begin
  370. FFileBuffer.Add('');
  371. FFileBuffer.Add(brackets[0] + section + brackets[1]);
  372. if ident <> '' then
  373. FFileBuffer.Add(ident + separator + value);
  374. end;
  375. SaveToFile;
  376. end;
  377. { Writes an Integer-Value for Ident in one Section }
  378. procedure TIniFile.WriteInteger(const section, ident : string; value : longint);
  379. begin
  380. WriteString(section, ident, IntToStr(value));
  381. end;
  382. { Writes a Bool-Value for Ident in one Section }
  383. procedure TIniFile.WriteBool(const section, ident : string; value : boolean);
  384. const
  385. values: array[boolean] of string = ('0', '1');
  386. begin
  387. WriteString(section, ident, values[Value]);
  388. end;
  389. { Deletes the value of ident in one section.
  390. Note: Only if section and ident exist, the value of ident will be set to NULL }
  391. procedure TIniFile.DeleteKey(const section, ident : string);
  392. var
  393. index : integer;
  394. begin
  395. index := GetSectionIndex(section);
  396. if index <> -1 then
  397. begin
  398. Inc(index);
  399. while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) and
  400. (GetName(FFileBuffer[index]) <> ident) do
  401. Inc(index);
  402. if not (index >= FFileBuffer.Count) and not IsSection(FFileBuffer[index]) then
  403. begin { Ident does exists }
  404. FFileBuffer.Delete(index);
  405. SaveToFile;
  406. end;
  407. end;
  408. end;
  409. { Erases the whole Section from an Ini-File }
  410. procedure TIniFile.EraseSection(const section : string);
  411. var
  412. index : integer;
  413. begin
  414. index := GetSectionIndex(section);
  415. if index <> -1 then
  416. begin
  417. FFileBuffer.Delete(index); { Delete Section-Header }
  418. while (index < FFileBuffer.Count) and not IsSection(FFileBuffer[index]) do
  419. FFileBuffer.Delete(index); { Delete Section-Items }
  420. if index > 0 then FFileBuffer.Insert(index, '');
  421. SaveToFile;
  422. end;
  423. end;
  424. end.
  425. {
  426. $Log$
  427. Revision 1.8 2000-01-07 01:24:33 peter
  428. * updated copyright to 2000
  429. Revision 1.7 2000/01/06 01:20:33 peter
  430. * moved out of packages/ back to topdir
  431. Revision 1.1 2000/01/03 19:33:07 peter
  432. * moved to packages dir
  433. Revision 1.5 1999/11/23 09:50:51 peter
  434. * load/save stream support
  435. Revision 1.4 1999/11/08 15:01:38 peter
  436. * fpcmake support
  437. Revision 1.3 1999/11/02 23:58:37 peter
  438. * comment support
  439. * readsectionraw method
  440. Revision 1.2 1999/04/29 16:21:54 michael
  441. + Default mode Hugestrings
  442. Revision 1.1 1999/04/08 15:44:10 michael
  443. + Donated by Michael A. Hess
  444. Initial Release 1999/04/07 MAH
  445. }