]>
git.saurik.com Git - apt.git/blob - apt-pkg/contrib/configuration.cc
82418f9c25de1b1e4e3551346fd4244cc79f18c2
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: configuration.cc,v 1.7 1998/10/20 02:39:26 jgg Exp $
4 /* ######################################################################
8 This class provides a configuration file and command line parser
9 for a tree-oriented configuration environment. All runtime configuration
12 ##################################################################### */
14 // Include files /*{{{*/
16 #pragma implementation "apt-pkg/configuration.h"
18 #include <apt-pkg/configuration.h>
19 #include <apt-pkg/error.h>
26 Configuration
*_config
= new Configuration
;
28 // Configuration::Configuration - Constructor /*{{{*/
29 // ---------------------------------------------------------------------
31 Configuration::Configuration()
36 // Configuration::Lookup - Lookup a single item /*{{{*/
37 // ---------------------------------------------------------------------
38 /* This will lookup a single item by name below another item. It is a
39 helper function for the main lookup function */
40 Configuration::Item
*Configuration::Lookup(Item
*Head
,const char *S
,
41 unsigned long Len
,bool Create
)
44 Item
*I
= Head
->Child
;
45 Item
**Last
= &Head
->Child
;
46 for (; I
!= 0; Last
= &I
->Next
, I
= I
->Next
)
47 if ((Res
= stringcasecmp(I
->Tag
.begin(),I
->Tag
.end(),S
,S
+ Len
)) == 0)
56 I
->Tag
= string(S
,Len
);
63 // Configuration::Lookup - Lookup a fully scoped item /*{{{*/
64 // ---------------------------------------------------------------------
65 /* This performs a fully scoped lookup of a given name, possibly creating
67 Configuration::Item
*Configuration::Lookup(const char *Name
,bool Create
)
69 const char *Start
= Name
;
70 const char *End
= Start
+ strlen(Name
);
71 const char *TagEnd
= Name
;
73 for (; End
- TagEnd
> 2; TagEnd
++)
75 if (TagEnd
[0] == ':' && TagEnd
[1] == ':')
77 Itm
= Lookup(Itm
,Start
,TagEnd
- Start
,Create
);
80 TagEnd
= Start
= TagEnd
+ 2;
84 Itm
= Lookup(Itm
,Start
,End
- Start
,Create
);
88 // Configuration::Find - Find a value /*{{{*/
89 // ---------------------------------------------------------------------
91 string
Configuration::Find(const char *Name
,const char *Default
)
93 Item
*Itm
= Lookup(Name
,false);
94 if (Itm
== 0 || Itm
->Value
.empty() == true)
105 // Configuration::FindFile - Find a Filename /*{{{*/
106 // ---------------------------------------------------------------------
107 /* Directories are stored as the base dir in the Parent node and the
108 sub directory in sub nodes with the final node being the end filename
110 string
Configuration::FindFile(const char *Name
,const char *Default
)
112 Item
*Itm
= Lookup(Name
,false);
113 if (Itm
== 0 || Itm
->Value
.empty() == true)
122 if (Itm
->Value
[0] == '/' || Itm
->Parent
== 0)
125 // ./ is also considered absolute as is anything with ~ in it
126 if (Itm
->Value
[0] != 0 &&
127 ((Itm
->Value
[0] == '.' && Itm
->Value
[1] == '/') ||
128 (Itm
->Value
[0] == '~' && Itm
->Value
[1] == '/')))
131 if (Itm
->Parent
->Value
.end()[-1] == '/')
132 return Itm
->Parent
->Value
+ Itm
->Value
;
134 return Itm
->Parent
->Value
+ '/' + Itm
->Value
;
137 // Configuration::FindDir - Find a directory name /*{{{*/
138 // ---------------------------------------------------------------------
139 /* This is like findfile execept the result is terminated in a / */
140 string
Configuration::FindDir(const char *Name
,const char *Default
)
142 string Res
= FindFile(Name
,Default
);
143 if (Res
.end()[-1] != '/')
148 // Configuration::FindI - Find an integer value /*{{{*/
149 // ---------------------------------------------------------------------
151 int Configuration::FindI(const char *Name
,int Default
)
153 Item
*Itm
= Lookup(Name
,false);
154 if (Itm
== 0 || Itm
->Value
.empty() == true)
158 int Res
= strtol(Itm
->Value
.c_str(),&End
,0);
159 if (End
== Itm
->Value
.c_str())
165 // Configuration::FindB - Find a boolean type /*{{{*/
166 // ---------------------------------------------------------------------
168 bool Configuration::FindB(const char *Name
,bool Default
)
170 Item
*Itm
= Lookup(Name
,false);
171 if (Itm
== 0 || Itm
->Value
.empty() == true)
174 return StringToBool(Itm
->Value
,Default
);
177 // Configuration::Set - Set a value /*{{{*/
178 // ---------------------------------------------------------------------
180 void Configuration::Set(const char *Name
,string Value
)
182 Item
*Itm
= Lookup(Name
,true);
188 // Configuration::Set - Set an integer value /*{{{*/
189 // ---------------------------------------------------------------------
191 void Configuration::Set(const char *Name
,int Value
)
193 Item
*Itm
= Lookup(Name
,true);
197 snprintf(S
,sizeof(S
),"%i",Value
);
201 // Configuration::Exists - Returns true if the Name exists /*{{{*/
202 // ---------------------------------------------------------------------
204 bool Configuration::Exists(const char *Name
)
206 Item
*Itm
= Lookup(Name
,false);
213 // ReadConfigFile - Read a configuration file /*{{{*/
214 // ---------------------------------------------------------------------
215 /* The configuration format is very much like the named.conf format
216 used in bind8, in fact this routine can parse most named.conf files. */
217 bool ReadConfigFile(Configuration
&Conf
,string FName
)
219 // Open the stream for reading
220 ifstream
F(FName
.c_str(),ios::in
| ios::nocreate
);
222 return _error
->Errno("ifstream::ifstream","Opening configuration file %s",FName
.c_str());
231 bool InComment
= false;
232 while (F
.eof() == false)
234 F
.getline(Buffer
,sizeof(Buffer
));
236 _strtabexpand(Buffer
,sizeof(Buffer
));
239 // Multi line comment
240 if (InComment
== true)
242 for (const char *I
= Buffer
; *I
!= 0; I
++)
244 if (*I
== '*' && I
[1] == '/')
246 memmove(Buffer
,I
+2,strlen(I
+2) + 1);
251 if (InComment
== true)
255 // Discard single line comments
256 for (char *I
= Buffer
; *I
!= 0; I
++)
258 if (*I
== '/' && I
[1] == '/')
265 // Look for multi line comments
266 for (char *I
= Buffer
; *I
!= 0; I
++)
268 if (*I
== '/' && I
[1] == '*')
271 for (char *J
= Buffer
; *J
!= 0; J
++)
273 if (*J
== '*' && J
[1] == '/')
275 memmove(I
,J
+2,strlen(J
+2) + 1);
281 if (InComment
== true)
293 // We now have a valid line fragment
294 for (char *I
= Buffer
; *I
!= 0;)
296 if (*I
== '{' || *I
== ';' || *I
== '}')
298 // Put the last fragement into the buffer
299 char *Start
= Buffer
;
301 for (; Start
!= I
&& isspace(*Start
) != 0; Start
++);
302 for (; Stop
!= Start
&& isspace(Stop
[-1]) != 0; Stop
--);
303 if (LineBuffer
.empty() == false && Stop
- Start
!= 0)
305 LineBuffer
+= string(Start
,Stop
- Start
);
307 // Remove the fragment
309 memmove(Buffer
,I
+ 1,strlen(I
+ 1) + 1);
315 string::size_type Pos
= ParentTag
.rfind("::");
316 if (Pos
== string::npos
)
317 ParentTag
= string();
319 ParentTag
= string(ParentTag
,0,Pos
);
323 if (TermChar
== '{' && LineBuffer
.empty() == true)
324 return _error
->Error("Syntax error %s:%u: Block starts with no name.",FName
.c_str(),CurLine
);
326 if (LineBuffer
.empty() == true)
330 string::size_type Pos
= LineBuffer
.find(' ');
331 if (Pos
== string::npos
)
334 Pos
= LineBuffer
.length();
336 return _error
->Error("Syntax error %s:%u: Tag with no value",FName
.c_str(),CurLine
);
339 string Tag
= string(LineBuffer
,0,Pos
);
344 if (ParentTag
.empty() == true)
347 ParentTag
+= string("::") + Tag
;
351 // We dont have a value to set
352 if (Pos
== LineBuffer
.length())
354 LineBuffer
= string();
358 // Parse off the word
360 if (ParseCWord(LineBuffer
.c_str()+Pos
,Word
) == false)
361 return _error
->Error("Syntax error %s:%u: Malformed value",FName
.c_str(),CurLine
);
363 // Generate the item name
365 if (ParentTag
.empty() == true)
369 if (Tag
.empty() == true)
372 Item
= ParentTag
+ "::" + Tag
;
375 // Set the item in the configuration class
379 LineBuffer
= string();
385 // Store the fragment
386 const char *Stripd
= _strstrip(Buffer
);
387 if (*Stripd
!= 0 && LineBuffer
.empty() == false)
389 LineBuffer
+= Stripd
;