]>
git.saurik.com Git - apt.git/blob - apt-pkg/contrib/configuration.cc
1 // -*- mode: cpp; mode: fold -*-
3 // $Id: configuration.cc,v 1.6 1998/10/02 04:39:49 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::FindDir - Find a directory /*{{{*/
106 // ---------------------------------------------------------------------
107 /* Directories are stored as the base dir in the Parent node and the
108 sub directory in sub nodes
110 string
Configuration::FindDir(const char *Name
,const char *Default
= 0)
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::FindI - Find an integer value /*{{{*/
138 // ---------------------------------------------------------------------
140 int Configuration::FindI(const char *Name
,int Default
)
142 Item
*Itm
= Lookup(Name
,false);
143 if (Itm
== 0 || Itm
->Value
.empty() == true)
147 int Res
= strtol(Itm
->Value
.c_str(),&End
,0);
148 if (End
== Itm
->Value
.c_str())
154 // Configuration::FindB - Find a boolean type /*{{{*/
155 // ---------------------------------------------------------------------
157 bool Configuration::FindB(const char *Name
,bool Default
)
159 Item
*Itm
= Lookup(Name
,false);
160 if (Itm
== 0 || Itm
->Value
.empty() == true)
164 int Res
= strtol(Itm
->Value
.c_str(),&End
,0);
165 if (End
== Itm
->Value
.c_str() || Res
< 0 || Res
> 1)
167 // Check for positives
168 if (strcasecmp(Itm
->Value
.c_str(),"no") == 0 ||
169 strcasecmp(Itm
->Value
.c_str(),"false") == 0 ||
170 strcasecmp(Itm
->Value
.c_str(),"without") == 0 ||
171 strcasecmp(Itm
->Value
.c_str(),"disable") == 0)
174 // Check for negatives
175 if (strcasecmp(Itm
->Value
.c_str(),"yes") == 0 ||
176 strcasecmp(Itm
->Value
.c_str(),"true") == 0 ||
177 strcasecmp(Itm
->Value
.c_str(),"with") == 0 ||
178 strcasecmp(Itm
->Value
.c_str(),"enable") == 0)
187 // Configuration::Set - Set a value /*{{{*/
188 // ---------------------------------------------------------------------
190 void Configuration::Set(const char *Name
,string Value
)
192 Item
*Itm
= Lookup(Name
,true);
198 // Configuration::Set - Set an integer value /*{{{*/
199 // ---------------------------------------------------------------------
201 void Configuration::Set(const char *Name
,int Value
)
203 Item
*Itm
= Lookup(Name
,true);
207 snprintf(S
,sizeof(S
),"%i",Value
);
211 // Configuration::Exists - Returns true if the Name exists /*{{{*/
212 // ---------------------------------------------------------------------
214 bool Configuration::Exists(const char *Name
)
216 Item
*Itm
= Lookup(Name
,false);
223 // ReadConfigFile - Read a configuration file /*{{{*/
224 // ---------------------------------------------------------------------
225 /* The configuration format is very much like the named.conf format
226 used in bind8, in fact this routine can parse most named.conf files. */
227 bool ReadConfigFile(Configuration
&Conf
,string FName
)
229 // Open the stream for reading
230 ifstream
F(FName
.c_str(),ios::in
| ios::nocreate
);
232 return _error
->Errno("ifstream::ifstream","Opening configuration file %s",FName
.c_str());
241 bool InComment
= false;
242 while (F
.eof() == false)
244 F
.getline(Buffer
,sizeof(Buffer
));
246 _strtabexpand(Buffer
,sizeof(Buffer
));
249 // Multi line comment
250 if (InComment
== true)
252 for (const char *I
= Buffer
; *I
!= 0; I
++)
254 if (*I
== '*' && I
[1] == '/')
256 memmove(Buffer
,I
+2,strlen(I
+2) + 1);
261 if (InComment
== true)
265 // Discard single line comments
266 for (char *I
= Buffer
; *I
!= 0; I
++)
268 if (*I
== '/' && I
[1] == '/')
275 // Look for multi line comments
276 for (char *I
= Buffer
; *I
!= 0; I
++)
278 if (*I
== '/' && I
[1] == '*')
281 for (char *J
= Buffer
; *J
!= 0; J
++)
283 if (*J
== '*' && J
[1] == '/')
285 memmove(I
,J
+2,strlen(J
+2) + 1);
291 if (InComment
== true)
303 // We now have a valid line fragment
304 for (char *I
= Buffer
; *I
!= 0;)
306 if (*I
== '{' || *I
== ';' || *I
== '}')
308 // Put the last fragement into the buffer
309 char *Start
= Buffer
;
311 for (; Start
!= I
&& isspace(*Start
) != 0; Start
++);
312 for (; Stop
!= Start
&& isspace(Stop
[-1]) != 0; Stop
--);
313 if (LineBuffer
.empty() == false && Stop
- Start
!= 0)
315 LineBuffer
+= string(Start
,Stop
- Start
);
317 // Remove the fragment
319 memmove(Buffer
,I
+ 1,strlen(I
+ 1) + 1);
325 string::size_type Pos
= ParentTag
.rfind("::");
326 if (Pos
== string::npos
)
327 ParentTag
= string();
329 ParentTag
= string(ParentTag
,0,Pos
);
333 if (TermChar
== '{' && LineBuffer
.empty() == true)
334 return _error
->Error("Syntax error %s:%u: Block starts with no name.",FName
.c_str(),CurLine
);
336 if (LineBuffer
.empty() == true)
340 string::size_type Pos
= LineBuffer
.find(' ');
341 if (Pos
== string::npos
)
344 Pos
= LineBuffer
.length();
346 return _error
->Error("Syntax error %s:%u: Tag with no value",FName
.c_str(),CurLine
);
349 string Tag
= string(LineBuffer
,0,Pos
);
354 if (ParentTag
.empty() == true)
357 ParentTag
+= string("::") + Tag
;
361 // We dont have a value to set
362 if (Pos
== LineBuffer
.length())
364 LineBuffer
= string();
368 // Parse off the word
370 if (ParseCWord(LineBuffer
.c_str()+Pos
,Word
) == false)
371 return _error
->Error("Syntax error %s:%u: Malformed value",FName
.c_str(),CurLine
);
373 // Generate the item name
375 if (ParentTag
.empty() == true)
379 if (Tag
.empty() == true)
382 Item
= ParentTag
+ "::" + Tag
;
385 // Set the item in the configuration class
389 LineBuffer
= string();
395 // Store the fragment
396 const char *Stripd
= _strstrip(Buffer
);
397 if (*Stripd
!= 0 && LineBuffer
.empty() == false)
399 LineBuffer
+= Stripd
;