wini.pas 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  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,255));
  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.8 1999-03-08 14:58:21 peter
  422. + prompt with dialogs for tools
  423. Revision 1.7 1999/03/05 17:53:03 pierre
  424. + saving and opening of open files on exit
  425. Revision 1.6 1999/03/01 15:42:15 peter
  426. + Added dummy entries for functions not yet implemented
  427. * MenuBar didn't update itself automatically on command-set changes
  428. * Fixed Debugging/Profiling options dialog
  429. * TCodeEditor converts spaces to tabs at save only if efUseTabChars is
  430. set
  431. * efBackSpaceUnindents works correctly
  432. + 'Messages' window implemented
  433. + Added '$CAP MSG()' and '$CAP EDIT' to available tool-macros
  434. + Added TP message-filter support (for ex. you can call GREP thru
  435. GREP2MSG and view the result in the messages window - just like in TP)
  436. * A 'var' was missing from the param-list of THelpFacility.TopicSearch,
  437. so topic search didn't work...
  438. * In FPHELP.PAS there were still context-variables defined as word instead
  439. of THelpCtx
  440. * StdStatusKeys() was missing from the statusdef for help windows
  441. + Topic-title for index-table can be specified when adding a HTML-files
  442. Revision 1.5 1999/02/22 02:15:26 peter
  443. + default extension for save in the editor
  444. + Separate Text to Find for the grep dialog
  445. * fixed redir crash with tp7
  446. Revision 1.4 1999/02/10 09:14:57 pierre
  447. * Value was not disposed before overwrite in TINIEntry.SetValue
  448. Revision 1.3 1999/01/21 11:54:33 peter
  449. + tools menu
  450. + speedsearch in symbolbrowser
  451. * working run command
  452. Revision 1.2 1998/12/28 15:47:58 peter
  453. + Added user screen support, display & window
  454. + Implemented Editor,Mouse Options dialog
  455. + Added location of .INI and .CFG file
  456. + Option (INI) file managment implemented (see bottom of Options Menu)
  457. + Switches updated
  458. + Run program
  459. Revision 1.1 1998/12/22 10:39:57 peter
  460. + options are now written/read
  461. + find and replace routines
  462. }