wini.pas 12 KB

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