]>
git.saurik.com Git - apt.git/blob - apt-pkg/contrib/configuration.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: configuration.cc,v 1.9 1998/10/30 07:53:42 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
)
72 const char *Start
= Name
;
73 const char *End
= Start
+ strlen(Name
);
74 const char *TagEnd
= Name
;
76 for (; End
- TagEnd
> 2; TagEnd
++)
78 if (TagEnd
[0] == ':' && TagEnd
[1] == ':')
80 Itm
= Lookup(Itm
,Start
,TagEnd
- Start
,Create
);
83 TagEnd
= Start
= TagEnd
+ 2;
87 Itm
= Lookup(Itm
,Start
,End
- Start
,Create
);
91 // Configuration::Find - Find a value /*{{{*/
92 // ---------------------------------------------------------------------
94 string
Configuration::Find(const char *Name
,const char *Default
)
96 Item
*Itm
= Lookup(Name
,false);
97 if (Itm
== 0 || Itm
->Value
.empty() == true)
108 // Configuration::FindFile - Find a Filename /*{{{*/
109 // ---------------------------------------------------------------------
110 /* Directories are stored as the base dir in the Parent node and the
111 sub directory in sub nodes with the final node being the end filename
113 string
Configuration::FindFile(const char *Name
,const char *Default
)
115 Item
*Itm
= Lookup(Name
,false);
116 if (Itm
== 0 || Itm
->Value
.empty() == true)
125 if (Itm
->Value
[0] == '/' || Itm
->Parent
== 0)
128 // ./ is also considered absolute as is anything with ~ in it
129 if (Itm
->Value
[0] != 0 &&
130 ((Itm
->Value
[0] == '.' && Itm
->Value
[1] == '/') ||
131 (Itm
->Value
[0] == '~' && Itm
->Value
[1] == '/')))
134 if (Itm
->Parent
->Value
.end()[-1] == '/')
135 return Itm
->Parent
->Value
+ Itm
->Value
;
137 return Itm
->Parent
->Value
+ '/' + Itm
->Value
;
140 // Configuration::FindDir - Find a directory name /*{{{*/
141 // ---------------------------------------------------------------------
142 /* This is like findfile execept the result is terminated in a / */
143 string
Configuration::FindDir(const char *Name
,const char *Default
)
145 string Res
= FindFile(Name
,Default
);
146 if (Res
.end()[-1] != '/')
151 // Configuration::FindI - Find an integer value /*{{{*/
152 // ---------------------------------------------------------------------
154 int Configuration::FindI(const char *Name
,int Default
)
156 Item
*Itm
= Lookup(Name
,false);
157 if (Itm
== 0 || Itm
->Value
.empty() == true)
161 int Res
= strtol(Itm
->Value
.c_str(),&End
,0);
162 if (End
== Itm
->Value
.c_str())
168 // Configuration::FindB - Find a boolean type /*{{{*/
169 // ---------------------------------------------------------------------
171 bool Configuration::FindB(const char *Name
,bool Default
)
173 Item
*Itm
= Lookup(Name
,false);
174 if (Itm
== 0 || Itm
->Value
.empty() == true)
177 return StringToBool(Itm
->Value
,Default
);
180 // Configuration::Set - Set a value /*{{{*/
181 // ---------------------------------------------------------------------
183 void Configuration::Set(const char *Name
,string Value
)
185 Item
*Itm
= Lookup(Name
,true);
191 // Configuration::Set - Set an integer value /*{{{*/
192 // ---------------------------------------------------------------------
194 void Configuration::Set(const char *Name
,int Value
)
196 Item
*Itm
= Lookup(Name
,true);
200 snprintf(S
,sizeof(S
),"%i",Value
);
204 // Configuration::Exists - Returns true if the Name exists /*{{{*/
205 // ---------------------------------------------------------------------
207 bool Configuration::Exists(const char *Name
)
209 Item
*Itm
= Lookup(Name
,false);
215 // Configuration::Dump - Dump the config /*{{{*/
216 // ---------------------------------------------------------------------
217 /* Dump the entire configuration space */
218 void Configuration::Dump()
220 /* Write out all of the configuration directives by walking the
221 configuration tree */
222 const Configuration::Item
*Top
= _config
->Tree(0);
225 clog
<< Top
->FullTag() << " \"" << Top
->Value
<< "\";" << endl
;
233 while (Top
!= 0 && Top
->Next
== 0)
241 // Configuration::Item::FullTag - Return the fully scoped tag /*{{{*/
242 // ---------------------------------------------------------------------
244 string
Configuration::Item::FullTag() const
246 if (Parent
== 0 || Parent
->Parent
== 0)
248 return Parent
->FullTag() + "::" + Tag
;
252 // ReadConfigFile - Read a configuration file /*{{{*/
253 // ---------------------------------------------------------------------
254 /* The configuration format is very much like the named.conf format
255 used in bind8, in fact this routine can parse most named.conf files. */
256 bool ReadConfigFile(Configuration
&Conf
,string FName
)
258 // Open the stream for reading
259 ifstream
F(FName
.c_str(),ios::in
| ios::nocreate
);
261 return _error
->Errno("ifstream::ifstream","Opening configuration file %s",FName
.c_str());
270 bool InComment
= false;
271 while (F
.eof() == false)
273 F
.getline(Buffer
,sizeof(Buffer
));
275 _strtabexpand(Buffer
,sizeof(Buffer
));
278 // Multi line comment
279 if (InComment
== true)
281 for (const char *I
= Buffer
; *I
!= 0; I
++)
283 if (*I
== '*' && I
[1] == '/')
285 memmove(Buffer
,I
+2,strlen(I
+2) + 1);
290 if (InComment
== true)
294 // Discard single line comments
295 for (char *I
= Buffer
; *I
!= 0; I
++)
297 if (*I
== '/' && I
[1] == '/')
304 // Look for multi line comments
305 for (char *I
= Buffer
; *I
!= 0; I
++)
307 if (*I
== '/' && I
[1] == '*')
310 for (char *J
= Buffer
; *J
!= 0; J
++)
312 if (*J
== '*' && J
[1] == '/')
314 memmove(I
,J
+2,strlen(J
+2) + 1);
320 if (InComment
== true)
332 // We now have a valid line fragment
333 for (char *I
= Buffer
; *I
!= 0;)
335 if (*I
== '{' || *I
== ';' || *I
== '}')
337 // Put the last fragement into the buffer
338 char *Start
= Buffer
;
340 for (; Start
!= I
&& isspace(*Start
) != 0; Start
++);
341 for (; Stop
!= Start
&& isspace(Stop
[-1]) != 0; Stop
--);
342 if (LineBuffer
.empty() == false && Stop
- Start
!= 0)
344 LineBuffer
+= string(Start
,Stop
- Start
);
346 // Remove the fragment
348 memmove(Buffer
,I
+ 1,strlen(I
+ 1) + 1);
354 string::size_type Pos
= ParentTag
.rfind("::");
355 if (Pos
== string::npos
)
356 ParentTag
= string();
358 ParentTag
= string(ParentTag
,0,Pos
);
362 if (TermChar
== '{' && LineBuffer
.empty() == true)
363 return _error
->Error("Syntax error %s:%u: Block starts with no name.",FName
.c_str(),CurLine
);
365 if (LineBuffer
.empty() == true)
369 string::size_type Pos
= LineBuffer
.find(' ');
370 if (Pos
== string::npos
)
373 Pos
= LineBuffer
.length();
375 return _error
->Error("Syntax error %s:%u: Tag with no value",FName
.c_str(),CurLine
);
378 string Tag
= string(LineBuffer
,0,Pos
);
383 if (ParentTag
.empty() == true)
386 ParentTag
+= string("::") + Tag
;
390 // We dont have a value to set
391 if (Pos
== LineBuffer
.length())
393 LineBuffer
= string();
397 // Parse off the word
399 if (ParseCWord(LineBuffer
.c_str()+Pos
,Word
) == false)
400 return _error
->Error("Syntax error %s:%u: Malformed value",FName
.c_str(),CurLine
);
402 // Generate the item name
404 if (ParentTag
.empty() == true)
408 if (Tag
.empty() == true)
411 Item
= ParentTag
+ "::" + Tag
;
414 // Set the item in the configuration class
418 LineBuffer
= string();
424 // Store the fragment
425 const char *Stripd
= _strstrip(Buffer
);
426 if (*Stripd
!= 0 && LineBuffer
.empty() == false)
428 LineBuffer
+= Stripd
;