wini.pas 13 KB

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