]>
git.saurik.com Git - apt.git/blob - apt-pkg/contrib/configuration.cc
   1 // -*- mode: cpp; mode: fold -*- 
   3 // $Id: configuration.cc,v 1.12 1999/01/27 02:48:52 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()); 
 284    bool InComment 
= false; 
 285    while (F
.eof() == false) 
 287       F
.getline(Buffer
,sizeof(Buffer
)); 
 289       _strtabexpand(Buffer
,sizeof(Buffer
)); 
 292       // Multi line comment 
 293       if (InComment 
== true) 
 295          for (const char *I 
= Buffer
; *I 
!= 0; I
++) 
 297             if (*I 
== '*' && I
[1] == '/') 
 299                memmove(Buffer
,I
+2,strlen(I
+2) + 1); 
 304          if (InComment 
== true) 
 308       // Discard single line comments 
 309       bool InQuote 
= false; 
 310       for (char *I 
= Buffer
; *I 
!= 0; I
++) 
 317          if (*I 
== '/' && I
[1] == '/') 
 324       // Look for multi line comments 
 325       for (char *I 
= Buffer
; *I 
!= 0; I
++) 
 332          if (*I 
== '/' && I
[1] == '*') 
 335             for (char *J 
= Buffer
; *J 
!= 0; J
++) 
 337                if (*J 
== '*' && J
[1] == '/') 
 339                   memmove(I
,J
+2,strlen(J
+2) + 1); 
 345             if (InComment 
== true) 
 357       // We now have a valid line fragment 
 358       for (char *I 
= Buffer
; *I 
!= 0;) 
 360          if (*I 
== '{' || *I 
== ';' || *I 
== '}') 
 362             // Put the last fragement into the buffer 
 363             char *Start 
= Buffer
; 
 365             for (; Start 
!= I 
&& isspace(*Start
) != 0; Start
++); 
 366             for (; Stop 
!= Start 
&& isspace(Stop
[-1]) != 0; Stop
--); 
 367             if (LineBuffer
.empty() == false && Stop 
- Start 
!= 0) 
 369             LineBuffer 
+= string(Start
,Stop 
- Start
); 
 371             // Remove the fragment 
 373             memmove(Buffer
,I 
+ 1,strlen(I 
+ 1) + 1); 
 379                string::size_type Pos 
= ParentTag
.rfind("::"); 
 380                if (Pos 
== string::npos
) 
 381                   ParentTag 
= string(); 
 383                   ParentTag 
= string(ParentTag
,0,Pos
); 
 387             if (TermChar 
== '{' && LineBuffer
.empty() == true) 
 388                return _error
->Error("Syntax error %s:%u: Block starts with no name.",FName
.c_str(),CurLine
); 
 390             if (LineBuffer
.empty() == true) 
 395             const char *Pos 
= LineBuffer
.c_str(); 
 396             if (ParseQuoteWord(Pos
,Tag
) == false) 
 397                return _error
->Error("Syntax error %s:%u: Malformed Tag",FName
.c_str(),CurLine
);      
 402                if (ParentTag
.empty() == true) 
 405                   ParentTag 
+= string("::") + Tag
; 
 409             // Parse off the word 
 411             if (ParseCWord(Pos
,Word
) == false) 
 420             // Generate the item name 
 422             if (ParentTag
.empty() == true) 
 426                if (TermChar 
!= '{' || Tag
.empty() == false) 
 427                   Item 
= ParentTag 
+ "::" + Tag
; 
 432             // Set the item in the configuration class 
 436             LineBuffer 
= string(); 
 442       // Store the fragment 
 443       const char *Stripd 
= _strstrip(Buffer
); 
 444       if (*Stripd 
!= 0 && LineBuffer
.empty() == false) 
 446       LineBuffer 
+= Stripd
;