inifile
At the time of Win3.0 it became standard to have settings in inifiles.
The following unit implements them.
{
IniFile - creates and reads and updates an inifile
--------------------------------------------------
The inifile is an editable textfile. It is
line oriented.
The structure of an ini file is as follows :
There are regions marked with square brackets as :
[region]
Each region may has several subitems with parameters
and comments as :
[region]
subitem1=xxxxx ;comment
subitem2=xxxxx ;comment
..
A comment is defined by a semicolon :
There are also comments allowed on a single line :
; comment
Due to a definition 'DescriptorSize' in this unit,
The maximum size of all items is currently restriced to
32 bytes. These are
-region names
-line comments
-subitem names
-subitem parameters
-subitem comments
--------------------------------------------------
The internal structure :
The given file is read/written to/from a tree structure.
The usual sequence is :
VAR k:IniFileTyp;
< init >
k.init(filename);
IF (k.DetectFile) THEN k.ReadFile
ELSE < build file with 'k.Append' with default values >
< get parameters >
parameter:=k.GetParameter(region,subitem);
< set parameters >
IF NOT k.SetParameter(region,subitem,parameter) THEN Error
< add new subitems >
k.Append(region,subitem,parameter,comment);
< end >
< if changed > k.WriteFile;
k.Done;
--------------------------------------------------
Created :9/mar/94
Last Update :
Is updated version of :
}
UNIT IniFile;
INTERFACE
USES OPRoot,OPString;
CONST DescriptorSize=32;
TYPE
Descriptor=STRING[DescriptorSize];
LineNodePtr=^LineNode;
LineNode=OBJECT(SingleListNode)
Desc:Descriptor;
Line:INTEGER;
CONSTRUCTOR Init(D:Descriptor;L:INTEGER);
DESTRUCTOR Done;VIRTUAL;
END;
SubItemNodePtr=^SubItemNode;
SubItemNode=OBJECT(LineNode)
Para:Descriptor;
Cmt:Descriptor;
CONSTRUCTOR Init(D,P,C:Descriptor;L:INTEGER);
DESTRUCTOR Done;VIRTUAL;
END;
RegionNodePtr=^RegionNode;
RegionNode=OBJECT(LineNode)
SubItem:SingleList;
CONSTRUCTOR Init(D:Descriptor;L:INTEGER);
PROCEDURE AddSubItem(D,P,C:Descriptor;L:INTEGER);
FUNCTION GetSubItemName(i:INTEGER):Descriptor;
FUNCTION GetHighestLine:INTEGER;
FUNCTION GetMaxLineSize:BYTE; { keyword+'='+para }
DESTRUCTOR Done;VIRTUAL;
END;
IniFilePtr=^IniFileTyp;
IniFileTyp=OBJECT
Header:SingleList;
Regions:SingleList;
Filename:Descriptor;
CONSTRUCTOR Init(F:Descriptor);
DESTRUCTOR Done;
FUNCTION DetectFile:BOOLEAN;
PROCEDURE ReadFile;
PROCEDURE WriteFile;
FUNCTION GetParameter(r,s:Descriptor):Descriptor;
FUNCTION SetParameter(r,s,d:Descriptor):BOOLEAN;
FUNCTION GetSubItemName(i:INTEGER;r:Descriptor):Descriptor;
PROCEDURE Append(r,s,d,c:Descriptor);
{ internal stuff }
FUNCTION FindRegion(r:Descriptor):RegionNodePtr;
FUNCTION FindSubItem(r:RegionNodePtr;s:Descriptor):SubItemNodePtr;
PROCEDURE IncLinesHigher(x:INTEGER);
END;
IMPLEMENTATION
{------------ LineNode ---------------------------------}
CONSTRUCTOR LineNode.Init(D:Descriptor;L:INTEGER);
BEGIN
SingleListNode.Init;
Desc:=D;
Line:=L;
END;
DESTRUCTOR LineNode.Done;
BEGIN
SingleListNode.Done;
END;
{-------------- SubItemNode ----------------------------}
CONSTRUCTOR SubItemNode.Init(D,P,C:Descriptor;L:INTEGER);
BEGIN
LineNode.Init(D,L);
Para:=P;
Cmt:=C;
END;
DESTRUCTOR SubItemNode.Done;
BEGIN
LineNode.Done;
END;
{------------- RegionNode -----------------------------}
CONSTRUCTOR RegionNode.Init(D:Descriptor;L:INTEGER);
BEGIN
LineNode.Init(D,L);
SubItem.Init;
END;
PROCEDURE RegionNode.AddSubItem(D,P,C:Descriptor;L:INTEGER);
VAR q:SubItemNodePtr;
BEGIN
q:=New(SubItemNodePtr,Init(D,P,C,L));
SubItem.Append(q);
END;
FUNCTION RegionNode.GetSubItemName(i:INTEGER):Descriptor;
VAR q:SubItemNodePtr;
j:INTEGER;
BEGIN
q:=SubItemNodePtr(SubItem.Head);j:=1;
WHILE (jNIL) DO q:=SubItemNodePtr(SubItem.Next(q));
IF (q<>NIL) THEN GetSubItemName:=q^.Desc
ELSE GetSubItemName:='';
END;
DESTRUCTOR RegionNode.Done;
BEGIN
SubItem.Done;
LineNode.Done;
END;
FUNCTION RegionNode.GetHighestLine:INTEGER;
VAR z:INTEGER;
s:SubItemNodePtr;
BEGIN
z:=0;
s:=SubItemNodePtr(SubItem.Head);
WHILE (s<>NIL) DO
BEGIN
IF (s^.Line>z) THEN z:=s^.Line;
s:=SubItemNodePtr(SubItem.Next(s));
END;
GetHighestLine:=z;
END;
FUNCTION RegionNode.GetMaxLineSize:BYTE;
VAR z,x:BYTE;
s:SubItemNodePtr;
BEGIN
z:=0;
s:=SubItemNodePtr(SubItem.Head);
WHILE (s<>NIL) DO
BEGIN
x:=length(s^.Desc)+length(s^.Para)+1;
IF (x>z) THEN z:=x;
s:=SubItemNodePtr(SubItem.Next(s));
END;
GetMaxLineSize:=z;
END;
{------------- IniFileTyp -----------------------------}
CONSTRUCTOR IniFileTyp.Init(F:Descriptor);
BEGIN
Header.Init;
Regions.Init;
Filename:=F;
END;
DESTRUCTOR IniFileTyp.Done;
BEGIN
Header.Done;
Regions.Done;
END;
FUNCTION IniFileTyp.DetectFile:BOOLEAN;
VAR F:FILE;
BEGIN
Assign(f,Filename);
{$i-}
Reset(f);
{$I+}
IF (IOResult=0) THEN
BEGIN
DetectFile:=TRUE;
Close(f);
END
ELSE DetectFile:=FALSE;
END;
PROCEDURE IniFileTyp.ReadFile;
VAR F:TEXT;
s:STRING;
d,e,g:Descriptor;
l:LineNodePtr;
r:RegionNodePtr;
i:SubItemNodePtr;
linenr:INTEGER;
z,u:BYTE;
BEGIN
Assign(f,Filename);
Reset(f);
linenr:=0;r:=NIL;
WHILE (Not EOF(f)) DO
BEGIN
ReadLn(f,s);
inc(linenr);
IF (s='') THEN
BEGIN
d:='';
l:=New(LineNodePtr,Init(d,LineNr));
Header.Append(l);
END;
IF (s<>'')AND(s[1]=';') THEN
BEGIN
d:=Copy(s,1,DescriptorSize);
l:=New(LineNodePtr,Init(d,LineNr));
Header.Append(l);
END;
IF (s<>'')AND(s[1]<>';') THEN
BEGIN
IF (s[1]='[') THEN { new region }
BEGIN
z:=Pos(']',s);
d:=Copy(s,2,z-2);
r:=New(RegionNodePtr,Init(D,linenr));
Regions.Append(r);
END { new region }
ELSE
BEGIN { new subitem }
z:=Pos('=',s);
d:=Copy(s,1,z-1);
u:=pos(';',s);
g:='';
IF (u=0) THEN e:=Copy(s,z+1,DescriptorSize)
ELSE
BEGIN
e:=Copy(s,z+1,u-z-1);
g:=Copy(s,u+1,DescriptorSize);
END;
e:=Trim(e);
i:=New(SubItemNodePtr,Init(d,e,g,linenr));
IF (r<>NIL) THEN
BEGIN
r^.Subitem.Append(i);
END
END; { new subitem }
END; { s<>'')AND(s[1]<>';' }
END; { Not EOF(f) }
Close(f);
END;
PROCEDURE IniFileTyp.WriteFile;
VAR f:TEXT;
s:STRING;
d,e,g:Descriptor;
l:LineNodePtr;
r:RegionNodePtr;
i:SubItemNodePtr;
linenr,kz:INTEGER;
z,x:BYTE;
quit:BOOLEAN;
BEGIN
Assign(f,FileName);
Rewrite(f);
{ get longest line }
r:=RegionNodePtr(Regions.Head);
z:=0;
WHILE (r<>NIL) DO
BEGIN
x:=r^.GetMaxLineSize;
IF (x>z) THEN z:=x;
r:=RegionNodePtr(Regions.Next(r));
END;
lineNr:=1;
l:=LineNodePtr(Header.Head);
r:=RegionNodePtr(Regions.Head);
IF (r<>NIL) THEN i:=SubItemNodePtr(r^.SubItem.Head)
ELSE i:=NIL;
{ IF (l<>NIL) THEN kz:=l^.line ELSE kz:=0;}
{ quit:=FALSE;}
REPEAT
IF (l<>NIL)AND(l^.line=lineNr) THEN { insert commentline }
BEGIN
IF (l^.desc='')THEN Writeln(f)
ELSE Writeln(f,l^.desc);
l:=LineNodePtr(Header.Next(l));
IF (l<>NIL) THEN kz:=l^.line ELSE kz:=0;
END;
IF (r<>NIL)AND(r^.line=linenr) THEN
BEGIN
Writeln(f,'[',r^.desc,']');
IF (i=NIL) THEN
BEGIN
r:=RegionNodePtr(Regions.Next(r));
IF (r=NIL) THEN i:=NIL
ELSE i:=SubItemNodePtr(r^.SubItem.Head);
END;
END;
IF (i<>NIL)AND(i^.line=linenr) THEN
BEGIN
s:=i^.desc+'='+i^.para;
IF (i^.cmt<>'') THEN
BEGIN
s:=pad(s,z+4);
s:=s+';'+i^.cmt;
END;
Writeln(f,s);
i:=SubItemNodePtr(r^.SubItem.Next(i));
IF (i=NIL) THEN
BEGIN
r:=RegionNodePtr(Regions.Next(r));
IF (r<>NIL) THEN i:=SubItemNodePtr(r^.SubItem.Head);
END;
END;
Inc(LineNr);
UNTIL (r=NIL)AND(i=NIL)AND(l=NIL);
Close(f);
END;
FUNCTION IniFileTyp.FindRegion(r:Descriptor):RegionNodePtr;
VAR p:RegionNodePtr;
BEGIN
p:=RegionNodePtr(Regions.Head);
WHILE (p<>NIL)AND(p^.Desc<>r)DO p:=RegionNodePtr(Regions.Next(p));
FindRegion:=p;
END;
FUNCTION IniFileTyp.FindSubItem(r:RegionNodePtr;s:Descriptor):SubItemNodePtr;
VAR p:SubItemNodePtr;
BEGIN
p:=SubItemNodePtr(r^.SubItem.Head);
WHILE (p<>NIL)AND(p^.Desc<>s)DO p:=SubItemNodePtr(r^.SubItem.Next(p));
FindSubItem:=p;
END;
PROCEDURE IniFileTyp.IncLinesHigher(x:INTEGER);
VAR l:LineNodePtr;
r:RegionNodePtr;
s:SubItemNodePtr;
BEGIN
l:=LineNodePtr(Header.Head);
WHILE (l<>NIL) DO
BEGIN
IF (l^.Line>=x) THEN inc(l^.line);
l:=LineNodePtr(Header.Next(l));
END;
r:=RegionNodePtr(Regions.Head);
WHILE (r<>NIL) DO
BEGIN
IF (r^.Line>=x) THEN inc(r^.Line);
s:=SubItemNodePtr(r^.SubItem.Head);
WHILE (s<>NIL) DO
BEGIN
IF (s^.Line>=x) THEN inc(s^.Line);
s:=SubItemNodePtr(r^.SubItem.Next(s));
END;
r:=RegionNodePtr(Regions.Next(r));
END;
END;
FUNCTION IniFileTyp.GetParameter(r,s:Descriptor):Descriptor;
VAR p:RegionNodePtr;
q:SubItemNodePtr;
d:Descriptor;
BEGIN
d:='';
p:=FindRegion(r);
IF (p<>NIL) THEN
BEGIN
q:=FindSubItem(p,s);
IF (q<>NIL) THEN d:=q^.para;
END;
GetParameter:=d;
END;
FUNCTION IniFileTyp.SetParameter(r,s,d:Descriptor):BOOLEAN;
VAR p:RegionNodePtr;
q:SubItemNodePtr;
ok:BOOLEAN;
BEGIN
ok:=FALSE;
p:=FindRegion(r);
IF (p<>NIL) THEN
BEGIN
q:=FindSubItem(p,s);
IF (q<>NIL) THEN
BEGIN
q^.para:=d;
ok:=TRUE;
END;
END;
SetParameter:=ok;
END;
FUNCTION IniFileTyp.GetSubItemName(i:INTEGER;r:Descriptor):Descriptor;
VAR p,pa:RegionNodePtr;
q:SubItemNodePtr;
z:INTEGER;
BEGIN
p:=FindRegion(r);
IF (p=NIL) THEN GetSubItemName:=''
ELSE GetSubItemName:=p^.GetSubItemName(i);
END;
PROCEDURE IniFileTyp.Append(r,s,d,c:Descriptor);
VAR p,pa:RegionNodePtr;
q:SubItemNodePtr;
z:INTEGER;
BEGIN
p:=FindRegion(r);
IF (p=NIL) THEN
BEGIN
p:=RegionNodePtr(Regions.Head);pa:=p;
WHILE (pa<>NIL) DO
BEGIN
pa:=RegionNodePtr(Regions.Next(p));
IF (pa<>NIL) THEN p:=pa;
END;
z:=0;
IF (p<>NIL) THEN z:=p^.GetHighestLine;
IncLinesHigher(z+1);
p:=New(RegionNodePtr,Init(r,z+1));
Regions.Append(p);
END;
q:=FindSubItem(p,s);
IF (q=NIL) THEN
BEGIN
z:=p^.GetHighestLine;
IF (z=0) THEN z:=p^.line;
IncLinesHigher(z+1);
q:=New(SubItemNodePtr,Init(s,d,c,z+1));
p^.SubItem.Append(q);
END;
END;
BEGIN { autoinit of this unit}
END. { unit }
a sample app
PROGRAM inifiletest;
USES IniFile;
VAR
k:IniFileTyp;
BEGIN
k.Init('TEST.INI');
IF (k.DetectFile) THEN
BEGIN
k.ReadFile;
END;
{ K.Append('keyboard','mist','1','');}
IF k.SetParameter('keyboard','language.dll','English') THEN ;
K.WriteFile;
k.done;
END.
home
last updated: 29.nov.99
Copyright (99,2000) Ing.Büro R.Tschaggelar