]>
git.saurik.com Git - apt.git/blob - apt-pkg/contrib/configuration.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: configuration.cc,v 1.13 1999/07/02 23:17:00 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>
20 #include <apt-pkg/strutl.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
;
47 // Empty strings match nothing. They are used for lists.
50 for (; I
!= 0; Last
= &I
->Next
, I
= I
->Next
)
51 if ((Res
= stringcasecmp(I
->Tag
.begin(),I
->Tag
.end(),S
,S
+ Len
)) == 0)
55 for (; I
!= 0; Last
= &I
->Next
, I
= I
->Next
);
63 I
->Tag
= string(S
,Len
);
70 // Configuration::Lookup - Lookup a fully scoped item /*{{{*/
71 // ---------------------------------------------------------------------
72 /* This performs a fully scoped lookup of a given name, possibly creating
74 Configuration::Item
*Configuration::Lookup(const char *Name
,bool Create
)
79 const char *Start
= Name
;
80 const char *End
= Start
+ strlen(Name
);
81 const char *TagEnd
= Name
;
83 for (; End
- TagEnd
>= 2; TagEnd
++)
85 if (TagEnd
[0] == ':' && TagEnd
[1] == ':')
87 Itm
= Lookup(Itm
,Start
,TagEnd
- Start
,Create
);
90 TagEnd
= Start
= TagEnd
+ 2;
94 // This must be a trailing ::, we create unique items in a list
101 Itm
= Lookup(Itm
,Start
,End
- Start
,Create
);
105 // Configuration::Find - Find a value /*{{{*/
106 // ---------------------------------------------------------------------
108 string
Configuration::Find(const char *Name
,const char *Default
)
110 Item
*Itm
= Lookup(Name
,false);
111 if (Itm
== 0 || Itm
->Value
.empty() == true)
122 // Configuration::FindFile - Find a Filename /*{{{*/
123 // ---------------------------------------------------------------------
124 /* Directories are stored as the base dir in the Parent node and the
125 sub directory in sub nodes with the final node being the end filename
127 string
Configuration::FindFile(const char *Name
,const char *Default
)
129 Item
*Itm
= Lookup(Name
,false);
130 if (Itm
== 0 || Itm
->Value
.empty() == true)
139 if (Itm
->Value
[0] == '/' || Itm
->Parent
== 0)
142 // ./ is also considered absolute as is anything with ~ in it
143 if (Itm
->Value
[0] != 0 &&
144 ((Itm
->Value
[0] == '.' && Itm
->Value
[1] == '/') ||
145 (Itm
->Value
[0] == '~' && Itm
->Value
[1] == '/')))
148 if (Itm
->Parent
->Value
.end()[-1] == '/')
149 return Itm
->Parent
->Value
+ Itm
->Value
;
151 return Itm
->Parent
->Value
+ '/' + Itm
->Value
;
154 // Configuration::FindDir - Find a directory name /*{{{*/
155 // ---------------------------------------------------------------------
156 /* This is like findfile execept the result is terminated in a / */
157 string
Configuration::FindDir(const char *Name
,const char *Default
)
159 string Res
= FindFile(Name
,Default
);
160 if (Res
.end()[-1] != '/')
165 // Configuration::FindI - Find an integer value /*{{{*/
166 // ---------------------------------------------------------------------
168 int Configuration::FindI(const char *Name
,int Default
)
170 Item
*Itm
= Lookup(Name
,false);
171 if (Itm
== 0 || Itm
->Value
.empty() == true)
175 int Res
= strtol(Itm
->Value
.c_str(),&End
,0);
176 if (End
== Itm
->Value
.c_str())
182 // Configuration::FindB - Find a boolean type /*{{{*/
183 // ---------------------------------------------------------------------
185 bool Configuration::FindB(const char *Name
,bool Default
)
187 Item
*Itm
= Lookup(Name
,false);
188 if (Itm
== 0 || Itm
->Value
.empty() == true)
191 return StringToBool(Itm
->Value
,Default
);
194 // Configuration::Set - Set a value /*{{{*/
195 // ---------------------------------------------------------------------
197 void Configuration::Set(const char *Name
,string Value
)
199 Item
*Itm
= Lookup(Name
,true);
205 // Configuration::Set - Set an integer value /*{{{*/
206 // ---------------------------------------------------------------------
208 void Configuration::Set(const char *Name
,int Value
)
210 Item
*Itm
= Lookup(Name
,true);
214 snprintf(S
,sizeof(S
),"%i",Value
);
218 // Configuration::Exists - Returns true if the Name exists /*{{{*/
219 // ---------------------------------------------------------------------
221 bool Configuration::Exists(const char *Name
)
223 Item
*Itm
= Lookup(Name
,false);
229 // Configuration::Dump - Dump the config /*{{{*/
230 // ---------------------------------------------------------------------
231 /* Dump the entire configuration space */
232 void Configuration::Dump()
234 /* Write out all of the configuration directives by walking the
235 configuration tree */
236 const Configuration::Item
*Top
= _config
->Tree(0);
239 clog
<< Top
->FullTag() << " \"" << Top
->Value
<< "\";" << endl
;
247 while (Top
!= 0 && Top
->Next
== 0)
255 // Configuration::Item::FullTag - Return the fully scoped tag /*{{{*/
256 // ---------------------------------------------------------------------
258 string
Configuration::Item::FullTag() const
260 if (Parent
== 0 || Parent
->Parent
== 0)
262 return Parent
->FullTag() + "::" + Tag
;
266 // ReadConfigFile - Read a configuration file /*{{{*/
267 // ---------------------------------------------------------------------
268 /* The configuration format is very much like the named.conf format
269 used in bind8, in fact this routine can parse most named.conf files. */
270 bool ReadConfigFile(Configuration
&Conf
,string FName
)
272 // Open the stream for reading
273 ifstream
F(FName
.c_str(),ios::in
| ios::nocreate
);
275 return _error
->Errno("ifstream::ifstream","Opening configuration file %s",FName
.c_str());
280 unsigned int StackPos
= 0;
286 bool InComment
= false;
287 while (F
.eof() == false)
289 F
.getline(Buffer
,sizeof(Buffer
));
291 _strtabexpand(Buffer
,sizeof(Buffer
));
294 // Multi line comment
295 if (InComment
== true)
297 for (const char *I
= Buffer
; *I
!= 0; I
++)
299 if (*I
== '*' && I
[1] == '/')
301 memmove(Buffer
,I
+2,strlen(I
+2) + 1);
306 if (InComment
== true)
310 // Discard single line comments
311 bool InQuote
= false;
312 for (char *I
= Buffer
; *I
!= 0; I
++)
319 if (*I
== '/' && I
[1] == '/')
326 // Look for multi line comments
327 for (char *I
= Buffer
; *I
!= 0; I
++)
334 if (*I
== '/' && I
[1] == '*')
337 for (char *J
= Buffer
; *J
!= 0; J
++)
339 if (*J
== '*' && J
[1] == '/')
341 memmove(I
,J
+2,strlen(J
+2) + 1);
347 if (InComment
== true)
359 // We now have a valid line fragment
360 for (char *I
= Buffer
; *I
!= 0;)
362 if (*I
== '{' || *I
== ';' || *I
== '}')
364 // Put the last fragement into the buffer
365 char *Start
= Buffer
;
367 for (; Start
!= I
&& isspace(*Start
) != 0; Start
++);
368 for (; Stop
!= Start
&& isspace(Stop
[-1]) != 0; Stop
--);
369 if (LineBuffer
.empty() == false && Stop
- Start
!= 0)
371 LineBuffer
+= string(Start
,Stop
- Start
);
373 // Remove the fragment
375 memmove(Buffer
,I
+ 1,strlen(I
+ 1) + 1);
382 ParentTag
= string();
384 ParentTag
= Stack
[--StackPos
];
388 if (TermChar
== '{' && LineBuffer
.empty() == true)
389 return _error
->Error("Syntax error %s:%u: Block starts with no name.",FName
.c_str(),CurLine
);
391 if (LineBuffer
.empty() == true)
396 const char *Pos
= LineBuffer
.c_str();
397 if (ParseQuoteWord(Pos
,Tag
) == false)
398 return _error
->Error("Syntax error %s:%u: Malformed Tag",FName
.c_str(),CurLine
);
404 Stack
[StackPos
++] = ParentTag
;
405 if (ParentTag
.empty() == true)
408 ParentTag
+= string("::") + Tag
;
412 // Parse off the word
414 if (ParseCWord(Pos
,Word
) == false)
423 // Generate the item name
425 if (ParentTag
.empty() == true)
429 if (TermChar
!= '{' || Tag
.empty() == false)
430 Item
= ParentTag
+ "::" + Tag
;
435 // Set the item in the configuration class
439 LineBuffer
= string();
445 // Store the fragment
446 const char *Stripd
= _strstrip(Buffer
);
447 if (*Stripd
!= 0 && LineBuffer
.empty() == false)
449 LineBuffer
+= Stripd
;