wini.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. {
  2. $Id$
  3. This file is part of the Free Pascal Integrated Development Environment
  4. Copyright (c) 1998 by B‚rczi G bor
  5. Reading and writing .INI files
  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. unit WINI;
  13. interface
  14. uses Objects;
  15. type
  16. PINIEntry = ^TINIEntry;
  17. TINIEntry = object(TObject)
  18. constructor Init(ALine: string);
  19. function GetText: string;
  20. function GetTag: string;
  21. function GetComment: string;
  22. function GetValue: string;
  23. procedure SetValue(S: string);
  24. destructor Done; virtual;
  25. private
  26. Tag : PString;
  27. Value : PString;
  28. Comment : PString;
  29. Text : PString;
  30. Modified : boolean;
  31. procedure Split;
  32. end;
  33. PINISection = ^TINISection;
  34. TINISection = object(TObject)
  35. constructor Init(AName: string);
  36. function GetName: string;
  37. function AddEntry(S: string): PINIEntry;
  38. function SearchEntry(Tag: string): PINIEntry; virtual;
  39. procedure ForEachEntry(EnumProc: pointer); virtual;
  40. destructor Done; virtual;
  41. private
  42. Name : PString;
  43. Entries : PCollection;
  44. end;
  45. PINIFile = ^TINIFile;
  46. TINIFile = object(TObject)
  47. MakeNullEntries: boolean;
  48. constructor Init(AFileName: string);
  49. function Read: boolean; virtual;
  50. function Update: boolean; virtual;
  51. function IsModified: boolean; virtual;
  52. function SearchSection(Section: string): PINISection; virtual;
  53. function SearchEntry(Section, Tag: string): PINIEntry; virtual;
  54. procedure ForEachEntry(Section: string; EnumProc: pointer); virtual;
  55. function GetEntry(Section, Tag, Default: string): string; virtual;
  56. procedure SetEntry(Section, Tag, Value: string); virtual;
  57. function GetIntEntry(Section, Tag: string; Default: longint): longint; virtual;
  58. procedure SetIntEntry(Section, Tag: string; Value: longint); virtual;
  59. procedure DeleteSection(Section: string); virtual;
  60. destructor Done; virtual;
  61. private
  62. ReadOnly: boolean;
  63. Sections: PCollection;
  64. FileName: PString;
  65. end;
  66. const MainSectionName : string[40] = 'MainSection';
  67. CommentChar : char = ';';
  68. implementation
  69. {$ifdef FPC}uses callspec;{$endif}
  70. const LastStrToIntResult : integer = 0;
  71. function IntToStr(L: longint): string;
  72. var S: string;
  73. begin
  74. Str(L,S);
  75. IntToStr:=S;
  76. end;
  77. function StrToInt(S: string): longint;
  78. var L: longint;
  79. C: integer;
  80. begin
  81. Val(S,L,C); if C<>0 then L:=-1;
  82. LastStrToIntResult:=C;
  83. StrToInt:=L;
  84. end;
  85. function UpcaseStr(S: string): string;
  86. var I: integer;
  87. begin
  88. for I:=1 to length(S) do
  89. S[I]:=Upcase(S[I]);
  90. UpcaseStr:=S;
  91. end;
  92. function LTrim(S: string): string;
  93. begin
  94. while copy(S,1,1)=' ' do Delete(S,1,1);
  95. LTrim:=S;
  96. end;
  97. function RTrim(S: string): string;
  98. begin
  99. while copy(S,length(S),1)=' ' do Delete(S,length(S),1);
  100. RTrim:=S;
  101. end;
  102. function Trim(S: string): string;
  103. begin
  104. Trim:=RTrim(LTrim(S));
  105. end;
  106. function GetStr(P: PString): string;
  107. begin
  108. if P=nil then GetStr:='' else GetStr:=P^;
  109. end;
  110. function EatIO: integer;
  111. begin
  112. EatIO:=IOResult;
  113. end;
  114. constructor TINIEntry.Init(ALine: string);
  115. begin
  116. inherited Init;
  117. Text:=NewStr(ALine);
  118. Split;
  119. end;
  120. function TINIEntry.GetText: string;
  121. var S,CoS: string;
  122. begin
  123. if Text=nil then
  124. begin
  125. CoS:=GetComment;
  126. S:=GetTag+'='+GetValue;
  127. if Trim(S)='=' then S:=CoS else
  128. if CoS<>'' then S:=S+' '+CommentChar+' '+CoS;
  129. end
  130. else S:=Text^;
  131. GetText:=S;
  132. end;
  133. function TINIEntry.GetTag: string;
  134. begin
  135. GetTag:=GetStr(Tag);
  136. end;
  137. function TINIEntry.GetComment: string;
  138. begin
  139. GetComment:=GetStr(Comment);
  140. end;
  141. function TINIEntry.GetValue: string;
  142. begin
  143. GetValue:=GetStr(Value);
  144. end;
  145. procedure TINIEntry.SetValue(S: string);
  146. begin
  147. if GetValue<>S then
  148. begin
  149. if Text<>nil then DisposeStr(Text); Text:=nil;
  150. if Value<>nil then DisposeStr(Value);
  151. Value:=NewStr(S);
  152. Modified:=true;
  153. end;
  154. end;
  155. procedure TINIEntry.Split;
  156. var S,ValueS: string;
  157. P,P2: byte;
  158. C: char;
  159. InString: boolean;
  160. begin
  161. S:=GetText;
  162. P:=Pos('=',S); P2:=Pos(CommentChar,S);
  163. if (P2<>0) and (P2<P) then P:=0;
  164. if P<>0 then
  165. begin
  166. Tag:=NewStr(copy(S,1,P-1));
  167. P2:=P+1; InString:=false; ValueS:='';
  168. while (P2<=length(S)) do
  169. begin
  170. C:=S[P2];
  171. if C='"' then InString:=not InString else
  172. if (C=CommentChar) and (InString=false) then Break else
  173. ValueS:=ValueS+C;
  174. Inc(P2);
  175. end;
  176. Value:=NewStr(Trim(ValueS));
  177. Comment:=NewStr(copy(S,P2+1,255));
  178. end else
  179. begin
  180. Tag:=nil;
  181. Value:=nil;
  182. Comment:=NewStr(S);
  183. end;
  184. end;
  185. destructor TINIEntry.Done;
  186. begin
  187. inherited Done;
  188. if Text<>nil then DisposeStr(Text);
  189. if Tag<>nil then DisposeStr(Tag);
  190. if Value<>nil then DisposeStr(Value);
  191. if Comment<>nil then DisposeStr(Comment);
  192. end;
  193. constructor TINISection.Init(AName: string);
  194. begin
  195. inherited Init;
  196. Name:=NewStr(AName);
  197. New(Entries, Init(50,500));
  198. end;
  199. function TINISection.GetName: string;
  200. begin
  201. GetName:=GetStr(Name);
  202. end;
  203. function TINISection.AddEntry(S: string): PINIEntry;
  204. var E: PINIEntry;
  205. begin
  206. New(E, Init(S));
  207. Entries^.Insert(E);
  208. AddEntry:=E;
  209. end;
  210. procedure TINISection.ForEachEntry(EnumProc: pointer);
  211. var I: integer;
  212. E: PINIEntry;
  213. begin
  214. for I:=0 to Entries^.Count-1 do
  215. begin
  216. E:=Entries^.At(I);
  217. {$ifdef FPC}
  218. CallPointerMethodLocal(EnumProc,CurrentFramePointer,@Self,E);
  219. {$else}
  220. asm
  221. push E.word[2]
  222. push E.word[0]
  223. push word ptr [bp]
  224. call EnumProc
  225. end;
  226. {$endif}
  227. end;
  228. end;
  229. function TINISection.SearchEntry(Tag: string): PINIEntry;
  230. function MatchingEntry(E: PINIEntry): boolean; {$ifndef FPC}far;{$endif}
  231. begin
  232. MatchingEntry:=UpcaseStr(E^.GetTag)=Tag;
  233. end;
  234. begin
  235. Tag:=UpcaseStr(Tag);
  236. SearchEntry:=Entries^.FirstThat(@MatchingEntry);
  237. end;
  238. destructor TINISection.Done;
  239. begin
  240. inherited Done;
  241. if Name<>nil then DisposeStr(Name);
  242. Dispose(Entries, Done);
  243. end;
  244. constructor TINIFile.Init(AFileName: string);
  245. begin
  246. inherited Init;
  247. FileName:=NewStr(AFileName);
  248. New(Sections, Init(50,50));
  249. Read;
  250. end;
  251. function TINIFile.Read: boolean;
  252. var f: text;
  253. OK: boolean;
  254. S,TS: string;
  255. P: PINISection;
  256. I: integer;
  257. begin
  258. New(P, Init(MainSectionName));
  259. Sections^.Insert(P);
  260. Assign(f,FileName^);
  261. {$I-}
  262. Reset(f);
  263. OK:=EatIO=0;
  264. while OK and (Eof(f)=false) do
  265. begin
  266. readln(f,S);
  267. TS:=Trim(S);
  268. OK:=EatIO=0;
  269. if OK then
  270. if TS<>'' then
  271. if copy(TS,1,1)='[' then
  272. begin
  273. I:=Pos(']',TS); if I=0 then I:=length(TS)+1;
  274. New(P, Init(copy(TS,2,I-2)));
  275. Sections^.Insert(P);
  276. end else
  277. begin
  278. P^.AddEntry(S);
  279. end;
  280. end;
  281. Close(f);
  282. EatIO;
  283. {$I+}
  284. Read:=true;
  285. end;
  286. function TINIFile.IsModified: boolean;
  287. function SectionModified(P: PINISection): boolean; {$ifndef FPC}far;{$endif}
  288. function EntryModified(E: PINIEntry): boolean; {$ifndef FPC}far;{$endif}
  289. begin
  290. EntryModified:=E^.Modified;
  291. end;
  292. begin
  293. SectionModified:=(P^.Entries^.FirstThat(@EntryModified)<>nil);
  294. end;
  295. begin
  296. IsModified:=(Sections^.FirstThat(@SectionModified)<>nil);
  297. end;
  298. function TINIFile.Update: boolean;
  299. var f: text;
  300. OK: boolean;
  301. P: PINISection;
  302. E: PINIEntry;
  303. I,J: integer;
  304. begin
  305. Assign(f,FileName^);
  306. {$I-}
  307. Rewrite(f);
  308. OK:=EatIO=0;
  309. if OK then
  310. for I:=0 to Sections^.Count-1 do
  311. begin
  312. P:=Sections^.At(I);
  313. if I<>0 then writeln(f,'['+P^.GetName+']');
  314. for J:=0 to P^.Entries^.Count-1 do
  315. begin
  316. E:=P^.Entries^.At(J);
  317. writeln(f,E^.GetText);
  318. OK:=EatIO=0;
  319. if OK=false then Break;
  320. end;
  321. if OK and ((I>0) or (P^.Entries^.Count>0)) and (I<Sections^.Count-1) then
  322. writeln(f,'');
  323. OK:=OK and (EatIO=0);
  324. if OK=false then Break;
  325. end;
  326. Close(f);
  327. EatIO;
  328. {$I+}
  329. if OK then
  330. for I:=0 to Sections^.Count-1 do
  331. begin
  332. P:=Sections^.At(I);
  333. for J:=0 to P^.Entries^.Count-1 do
  334. begin
  335. E:=P^.Entries^.At(J);
  336. E^.Modified:=false;
  337. end;
  338. end;
  339. Update:=OK;
  340. end;
  341. function TINIFile.SearchSection(Section: string): PINISection;
  342. function MatchingSection(P: PINISection): boolean; {$ifndef FPC}far;{$endif}
  343. var SN: string;
  344. M: boolean;
  345. begin
  346. SN:=UpcaseStr(P^.GetName);
  347. M:=SN=Section;
  348. MatchingSection:=M;
  349. end;
  350. begin
  351. Section:=UpcaseStr(Section);
  352. SearchSection:=Sections^.FirstThat(@MatchingSection);
  353. end;
  354. function TINIFile.SearchEntry(Section, Tag: string): PINIEntry;
  355. var P: PINISection;
  356. E: PINIEntry;
  357. begin
  358. P:=SearchSection(Section);
  359. if P=nil then E:=nil else
  360. E:=P^.SearchEntry(Tag);
  361. SearchEntry:=E;
  362. end;
  363. procedure TINIFile.ForEachEntry(Section: string; EnumProc: pointer);
  364. var P: PINISection;
  365. E: PINIEntry;
  366. I: integer;
  367. begin
  368. P:=SearchSection(Section);
  369. if P<>nil then
  370. for I:=0 to P^.Entries^.Count-1 do
  371. begin
  372. E:=P^.Entries^.At(I);
  373. {$ifdef FPC}
  374. CallPointerMethodLocal(EnumProc,CurrentFramePointer,@Self,E);
  375. {$else}
  376. asm
  377. push E.word[2]
  378. push E.word[0]
  379. push word ptr [bp]
  380. call EnumProc
  381. end;
  382. {$endif}
  383. end;
  384. end;
  385. function TINIFile.GetEntry(Section, Tag, Default: string): string;
  386. var E: PINIEntry;
  387. S: string;
  388. begin
  389. E:=SearchEntry(Section,Tag);
  390. if E=nil then S:=Default else
  391. S:=E^.GetValue;
  392. GetEntry:=S;
  393. end;
  394. procedure TINIFile.SetEntry(Section, Tag, Value: string);
  395. var E: PINIEntry;
  396. P: PINISection;
  397. begin
  398. E:=SearchEntry(Section,Tag);
  399. if E=nil then
  400. if (MakeNullEntries=true) or (Value<>'') then
  401. begin
  402. P:=SearchSection(Section);
  403. if P=nil then
  404. begin
  405. New(P, Init(Section));
  406. Sections^.Insert(P);
  407. end;
  408. E:=P^.AddEntry(Tag+'='+Value);
  409. E^.Modified:=true;
  410. end;
  411. if E<>nil then
  412. E^.SetValue(Value);
  413. end;
  414. function TINIFile.GetIntEntry(Section, Tag: string; Default: longint): longint;
  415. var L: longint;
  416. begin
  417. L:=StrToInt(GetEntry(Section,Tag,IntToStr(Default)));
  418. if LastStrToIntResult<>0 then L:=Default;
  419. GetIntEntry:=L;
  420. end;
  421. procedure TINIFile.SetIntEntry(Section, Tag: string; Value: longint);
  422. begin
  423. SetEntry(Section,Tag,IntToStr(Value));
  424. end;
  425. procedure TINIFile.DeleteSection(Section: string);
  426. var P: PINISection;
  427. begin
  428. P:=SearchSection(Section);
  429. if P<>nil then
  430. Sections^.Free(P);
  431. end;
  432. destructor TINIFile.Done;
  433. begin
  434. if IsModified then
  435. Update;
  436. inherited Done;
  437. if FileName<>nil then
  438. DisposeStr(FileName);
  439. Dispose(Sections, Done);
  440. end;
  441. END.
  442. {
  443. $Log$
  444. Revision 1.4 1999-02-10 09:14:57 pierre
  445. * Value was not disposed before overwrite in TINIEntry.SetValue
  446. Revision 1.3 1999/01/21 11:54:33 peter
  447. + tools menu
  448. + speedsearch in symbolbrowser
  449. * working run command
  450. Revision 1.2 1998/12/28 15:47:58 peter
  451. + Added user screen support, display & window
  452. + Implemented Editor,Mouse Options dialog
  453. + Added location of .INI and .CFG file
  454. + Option (INI) file managment implemented (see bottom of Options Menu)
  455. + Switches updated
  456. + Run program
  457. Revision 1.1 1998/12/22 10:39:57 peter
  458. + options are now written/read
  459. + find and replace routines
  460. }