wini.pas 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536
  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(const ALine: string);
  19. function GetText: string;
  20. function GetTag: string;
  21. function GetComment: string;
  22. function GetValue: string;
  23. procedure SetValue(const 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(const AName: string);
  36. function GetName: string;
  37. function AddEntry(const S: string): PINIEntry;
  38. function SearchEntry(Tag: string): PINIEntry; virtual;
  39. procedure DeleteEntry(Tag: string);
  40. procedure ForEachEntry(EnumProc: pointer); virtual;
  41. destructor Done; virtual;
  42. private
  43. Name : PString;
  44. Entries : PCollection;
  45. end;
  46. PINIFile = ^TINIFile;
  47. TINIFile = object(TObject)
  48. MakeNullEntries: boolean;
  49. constructor Init(const AFileName: string);
  50. function Read: boolean; virtual;
  51. function Update: boolean; virtual;
  52. function IsModified: boolean; virtual;
  53. function SearchSection(Section: string): PINISection; virtual;
  54. function SearchEntry(const Section, Tag: string): PINIEntry; virtual;
  55. procedure ForEachSection(EnumProc: pointer); virtual;
  56. procedure ForEachEntry(const Section: string; EnumProc: pointer); virtual;
  57. function GetEntry(const Section, Tag, Default: string): string; virtual;
  58. procedure SetEntry(const Section, Tag, Value: string); virtual;
  59. function GetIntEntry(const Section, Tag: string; Default: longint): longint; virtual;
  60. procedure SetIntEntry(const Section, Tag: string; Value: longint); virtual;
  61. procedure DeleteSection(const Section: string); virtual;
  62. procedure DeleteEntry(const Section, Tag: string);
  63. destructor Done; virtual;
  64. private
  65. { ReadOnly: boolean;}
  66. Sections: PCollection;
  67. FileName: PString;
  68. end;
  69. const MainSectionName : string[40] = 'MainSection';
  70. CommentChar : char = ';';
  71. implementation
  72. uses
  73. CallSpec,
  74. WUtils;
  75. constructor TINIEntry.Init(const ALine: string);
  76. begin
  77. inherited Init;
  78. Text:=NewStr(ALine);
  79. Split;
  80. end;
  81. function TINIEntry.GetText: string;
  82. var S,CoS: string;
  83. begin
  84. if Text=nil then
  85. begin
  86. CoS:=GetComment;
  87. S:=GetTag+'='+GetValue;
  88. if Trim(S)='=' then S:=CoS else
  89. if CoS<>'' then S:=S+' '+CommentChar+' '+CoS;
  90. end
  91. else S:=Text^;
  92. GetText:=S;
  93. end;
  94. function TINIEntry.GetTag: string;
  95. begin
  96. GetTag:=GetStr(Tag);
  97. end;
  98. function TINIEntry.GetComment: string;
  99. begin
  100. GetComment:=GetStr(Comment);
  101. end;
  102. function TINIEntry.GetValue: string;
  103. begin
  104. GetValue:=GetStr(Value);
  105. end;
  106. procedure TINIEntry.SetValue(const S: string);
  107. begin
  108. if GetValue<>S then
  109. begin
  110. if Text<>nil then DisposeStr(Text); Text:=nil;
  111. if Value<>nil then DisposeStr(Value);
  112. Value:=NewStr(S);
  113. Modified:=true;
  114. end;
  115. end;
  116. procedure TINIEntry.Split;
  117. var S,ValueS: string;
  118. P,P2: byte;
  119. C: char;
  120. InString: boolean;
  121. begin
  122. S:=GetText;
  123. P:=Pos('=',S); P2:=Pos(CommentChar,S);
  124. if (P2<>0) and (P2<P) then P:=0;
  125. if P<>0 then
  126. begin
  127. Tag:=NewStr(copy(S,1,P-1));
  128. P2:=P+1; InString:=false; ValueS:='';
  129. while (P2<=length(S)) do
  130. begin
  131. C:=S[P2];
  132. if C='"' then InString:=not InString else
  133. if (C=CommentChar) and (InString=false) then Break else
  134. ValueS:=ValueS+C;
  135. Inc(P2);
  136. end;
  137. Value:=NewStr(Trim(ValueS));
  138. Comment:=NewStr(copy(S,P2+1,High(S)));
  139. end else
  140. begin
  141. Tag:=nil;
  142. Value:=nil;
  143. Comment:=NewStr(S);
  144. end;
  145. end;
  146. destructor TINIEntry.Done;
  147. begin
  148. inherited Done;
  149. if Text<>nil then DisposeStr(Text);
  150. if Tag<>nil then DisposeStr(Tag);
  151. if Value<>nil then DisposeStr(Value);
  152. if Comment<>nil then DisposeStr(Comment);
  153. end;
  154. constructor TINISection.Init(const AName: string);
  155. begin
  156. inherited Init;
  157. Name:=NewStr(AName);
  158. New(Entries, Init(50,500));
  159. end;
  160. function TINISection.GetName: string;
  161. begin
  162. GetName:=GetStr(Name);
  163. end;
  164. function TINISection.AddEntry(const S: string): PINIEntry;
  165. var E: PINIEntry;
  166. begin
  167. New(E, Init(S));
  168. Entries^.Insert(E);
  169. AddEntry:=E;
  170. end;
  171. procedure TINIFile.ForEachSection(EnumProc: pointer);
  172. var I: Sw_integer;
  173. S: PINISection;
  174. begin
  175. for I:=0 to Sections^.Count-1 do
  176. begin
  177. S:=Sections^.At(I);
  178. CallPointerLocal(EnumProc,PreviousFramePointer,S);
  179. end;
  180. end;
  181. procedure TINISection.ForEachEntry(EnumProc: pointer);
  182. var I: integer;
  183. E: PINIEntry;
  184. begin
  185. for I:=0 to Entries^.Count-1 do
  186. begin
  187. E:=Entries^.At(I);
  188. CallPointerLocal(EnumProc,PreviousFramePointer,E);
  189. end;
  190. end;
  191. function TINISection.SearchEntry(Tag: string): PINIEntry;
  192. function MatchingEntry(E: PINIEntry): boolean; {$ifndef FPC}far;{$endif}
  193. begin
  194. MatchingEntry:=UpcaseStr(E^.GetTag)=Tag;
  195. end;
  196. begin
  197. Tag:=UpcaseStr(Tag);
  198. SearchEntry:=Entries^.FirstThat(@MatchingEntry);
  199. end;
  200. procedure TINISection.DeleteEntry(Tag: string);
  201. var
  202. P : PIniEntry;
  203. begin
  204. P:=SearchEntry(Tag);
  205. if assigned(P) then
  206. Entries^.Free(P);
  207. end;
  208. destructor TINISection.Done;
  209. begin
  210. inherited Done;
  211. if Name<>nil then DisposeStr(Name);
  212. Dispose(Entries, Done);
  213. end;
  214. constructor TINIFile.Init(const AFileName: string);
  215. begin
  216. inherited Init;
  217. FileName:=NewStr(AFileName);
  218. New(Sections, Init(50,50));
  219. Read;
  220. end;
  221. function TINIFile.Read: boolean;
  222. var f: text;
  223. OK: boolean;
  224. S,TS: string;
  225. P: PINISection;
  226. I: integer;
  227. begin
  228. New(P, Init(MainSectionName));
  229. Sections^.Insert(P);
  230. Assign(f,FileName^);
  231. {$I-}
  232. Reset(f);
  233. OK:=EatIO=0;
  234. while OK and (Eof(f)=false) do
  235. begin
  236. readln(f,S);
  237. TS:=Trim(S);
  238. OK:=EatIO=0;
  239. if OK then
  240. if TS<>'' then
  241. if copy(TS,1,1)='[' then
  242. begin
  243. I:=Pos(']',TS); if I=0 then I:=length(TS)+1;
  244. New(P, Init(copy(TS,2,I-2)));
  245. Sections^.Insert(P);
  246. end else
  247. begin
  248. P^.AddEntry(S);
  249. end;
  250. end;
  251. Close(f);
  252. EatIO;
  253. {$I+}
  254. Read:=true;
  255. end;
  256. function TINIFile.IsModified: boolean;
  257. function SectionModified(P: PINISection): boolean; {$ifndef FPC}far;{$endif}
  258. function EntryModified(E: PINIEntry): boolean; {$ifndef FPC}far;{$endif}
  259. begin
  260. EntryModified:=E^.Modified;
  261. end;
  262. begin
  263. SectionModified:=(P^.Entries^.FirstThat(@EntryModified)<>nil);
  264. end;
  265. begin
  266. IsModified:=(Sections^.FirstThat(@SectionModified)<>nil);
  267. end;
  268. function TINIFile.Update: boolean;
  269. var f: text;
  270. OK: boolean;
  271. P: PINISection;
  272. E: PINIEntry;
  273. I,J: integer;
  274. begin
  275. Assign(f,FileName^);
  276. {$I-}
  277. Rewrite(f);
  278. OK:=EatIO=0;
  279. if OK then
  280. for I:=0 to Sections^.Count-1 do
  281. begin
  282. P:=Sections^.At(I);
  283. if I<>0 then writeln(f,'['+P^.GetName+']');
  284. for J:=0 to P^.Entries^.Count-1 do
  285. begin
  286. E:=P^.Entries^.At(J);
  287. writeln(f,E^.GetText);
  288. OK:=EatIO=0;
  289. if OK=false then Break;
  290. end;
  291. if OK and ((I>0) or (P^.Entries^.Count>0)) and (I<Sections^.Count-1) then
  292. writeln(f,'');
  293. OK:=OK and (EatIO=0);
  294. if OK=false then Break;
  295. end;
  296. Close(f);
  297. EatIO;
  298. {$I+}
  299. if OK then
  300. for I:=0 to Sections^.Count-1 do
  301. begin
  302. P:=Sections^.At(I);
  303. for J:=0 to P^.Entries^.Count-1 do
  304. begin
  305. E:=P^.Entries^.At(J);
  306. E^.Modified:=false;
  307. end;
  308. end;
  309. Update:=OK;
  310. end;
  311. function TINIFile.SearchSection(Section: string): PINISection;
  312. function MatchingSection(P: PINISection): boolean; {$ifndef FPC}far;{$endif}
  313. var SN: string;
  314. M: boolean;
  315. begin
  316. SN:=UpcaseStr(P^.GetName);
  317. M:=SN=Section;
  318. MatchingSection:=M;
  319. end;
  320. begin
  321. Section:=UpcaseStr(Section);
  322. SearchSection:=Sections^.FirstThat(@MatchingSection);
  323. end;
  324. function TINIFile.SearchEntry(const Section, Tag: string): PINIEntry;
  325. var P: PINISection;
  326. E: PINIEntry;
  327. begin
  328. P:=SearchSection(Section);
  329. if P=nil then E:=nil else
  330. E:=P^.SearchEntry(Tag);
  331. SearchEntry:=E;
  332. end;
  333. procedure TINIFile.ForEachEntry(const Section: string; EnumProc: pointer);
  334. var P: PINISection;
  335. E: PINIEntry;
  336. I: integer;
  337. begin
  338. P:=SearchSection(Section);
  339. if P<>nil then
  340. for I:=0 to P^.Entries^.Count-1 do
  341. begin
  342. E:=P^.Entries^.At(I);
  343. {$ifdef FPC}
  344. CallPointerMethodLocal(EnumProc,CurrentFramePointer,@Self,E);
  345. {$else}
  346. asm
  347. push E.word[2]
  348. push E.word[0]
  349. push word ptr [bp]
  350. call EnumProc
  351. end;
  352. {$endif}
  353. end;
  354. end;
  355. function TINIFile.GetEntry(const Section, Tag, Default: string): string;
  356. var E: PINIEntry;
  357. S: string;
  358. begin
  359. E:=SearchEntry(Section,Tag);
  360. if E=nil then S:=Default else
  361. S:=E^.GetValue;
  362. GetEntry:=S;
  363. end;
  364. procedure TINIFile.SetEntry(const Section, Tag, Value: string);
  365. var E: PINIEntry;
  366. P: PINISection;
  367. begin
  368. E:=SearchEntry(Section,Tag);
  369. if E=nil then
  370. if (MakeNullEntries=true) or (Value<>'') then
  371. begin
  372. P:=SearchSection(Section);
  373. if P=nil then
  374. begin
  375. New(P, Init(Section));
  376. Sections^.Insert(P);
  377. end;
  378. E:=P^.AddEntry(Tag+'='+Value);
  379. E^.Modified:=true;
  380. end;
  381. if E<>nil then
  382. E^.SetValue(Value);
  383. end;
  384. function TINIFile.GetIntEntry(const Section, Tag: string; Default: longint): longint;
  385. var L: longint;
  386. begin
  387. L:=StrToInt(GetEntry(Section,Tag,IntToStr(Default)));
  388. if LastStrToIntResult<>0 then L:=Default;
  389. GetIntEntry:=L;
  390. end;
  391. procedure TINIFile.SetIntEntry(const Section, Tag: string; Value: longint);
  392. begin
  393. SetEntry(Section,Tag,IntToStr(Value));
  394. end;
  395. procedure TINIFile.DeleteSection(const Section: string);
  396. var P: PINISection;
  397. begin
  398. P:=SearchSection(Section);
  399. if P<>nil then
  400. Sections^.Free(P);
  401. end;
  402. procedure TINIFile.DeleteEntry(const Section, Tag: string);
  403. var P: PINISection;
  404. begin
  405. P:=SearchSection(Section);
  406. if P<>nil then
  407. P^.DeleteEntry(Tag);
  408. end;
  409. destructor TINIFile.Done;
  410. begin
  411. if IsModified then
  412. Update;
  413. inherited Done;
  414. if FileName<>nil then
  415. DisposeStr(FileName);
  416. Dispose(Sections, Done);
  417. end;
  418. END.
  419. {
  420. $Log$
  421. Revision 1.10 2000-06-22 09:07:15 pierre
  422. * Gabor changes: see fixes.txt
  423. Revision 1.9 2000/04/18 11:42:39 pierre
  424. lot of Gabor changes : see fixes.txt
  425. Revision 1.8 1999/03/08 14:58:21 peter
  426. + prompt with dialogs for tools
  427. Revision 1.7 1999/03/05 17:53:03 pierre
  428. + saving and opening of open files on exit
  429. Revision 1.6 1999/03/01 15:42:15 peter
  430. + Added dummy entries for functions not yet implemented
  431. * MenuBar didn't update itself automatically on command-set changes
  432. * Fixed Debugging/Profiling options dialog
  433. * TCodeEditor converts spaces to tabs at save only if efUseTabChars is
  434. set
  435. * efBackSpaceUnindents works correctly
  436. + 'Messages' window implemented
  437. + Added '$CAP MSG()' and '$CAP EDIT' to available tool-macros
  438. + Added TP message-filter support (for ex. you can call GREP thru
  439. GREP2MSG and view the result in the messages window - just like in TP)
  440. * A 'var' was missing from the param-list of THelpFacility.TopicSearch,
  441. so topic search didn't work...
  442. * In FPHELP.PAS there were still context-variables defined as word instead
  443. of THelpCtx
  444. * StdStatusKeys() was missing from the statusdef for help windows
  445. + Topic-title for index-table can be specified when adding a HTML-files
  446. Revision 1.5 1999/02/22 02:15:26 peter
  447. + default extension for save in the editor
  448. + Separate Text to Find for the grep dialog
  449. * fixed redir crash with tp7
  450. Revision 1.4 1999/02/10 09:14:57 pierre
  451. * Value was not disposed before overwrite in TINIEntry.SetValue
  452. Revision 1.3 1999/01/21 11:54:33 peter
  453. + tools menu
  454. + speedsearch in symbolbrowser
  455. * working run command
  456. Revision 1.2 1998/12/28 15:47:58 peter
  457. + Added user screen support, display & window
  458. + Implemented Editor,Mouse Options dialog
  459. + Added location of .INI and .CFG file
  460. + Option (INI) file managment implemented (see bottom of Options Menu)
  461. + Switches updated
  462. + Run program
  463. Revision 1.1 1998/12/22 10:39:57 peter
  464. + options are now written/read
  465. + find and replace routines
  466. }