Configuration.cc

Go to the documentation of this file.
00001 //
00002 // Configuration.cc
00003 //
00004 // Configuration: This class provides an object lookup table.  Each object 
00005 //                in the Configuration is indexed with a string.  The objects 
00006 //                can be returned by mentioning their string index. Values may
00007 //                include files with `/path/to/file` or other configuration
00008 //                variables with ${variable}
00009 //
00010 // Part of the ht://Dig package   <http://www.htdig.org/>
00011 // Copyright (c) 1999, 2000, 2001 The ht://Dig Group
00012 // For copyright details, see the file COPYING in your distribution
00013 // or the GNU General Public License version 2 or later 
00014 // <http://www.gnu.org/copyleft/gpl.html>
00015 //
00016 // $Id: Configuration_8cc-source.html,v 1.1 2008/06/08 10:12:52 sebdiaz Exp $
00017 //
00018 
00019 #ifdef HAVE_CONFIG_H
00020 #include "config.h"
00021 #endif /* HAVE_CONFIG_H */
00022 
00023 #include <stdio.h>
00024 #include "Configuration.h"
00025 #include "htString.h"
00026 #include "ParsedString.h"
00027 
00028 #include <stdlib.h>
00029 #include <ctype.h>
00030 #include <locale.h>
00031 
00032 
00033 //*********************************************************************
00034 // Configuration::Configuration()
00035 //
00036 Configuration::Configuration()
00037 {
00038   separators = String("=:");
00039   allow_multiple = 0;
00040 }
00041 
00042 Configuration::Configuration(const Configuration& other) : Object()
00043 {
00044   separators = other.separators;
00045   allow_multiple = other.allow_multiple;
00046 
00047   DictionaryCursor cursor;
00048   const char* key;
00049   for(other.dcGlobalVars.Start_Get(cursor); (key = other.dcGlobalVars.Get_Next(cursor));) {
00050     Add(key, other[key]);
00051   }
00052 }
00053 
00054 //*********************************************************************
00055 // void Configuration::NameValueSeparators(char *s)
00056 //
00057 void Configuration::NameValueSeparators(const String& s)
00058 {
00059     separators = s;
00060 }
00061 
00062 
00063 //*********************************************************************
00064 //   Add an entry to the configuration table.
00065 //
00066 void Configuration::Add(const String& str_arg)
00067 {
00068     const char* str = str_arg;
00069     String      name, value;
00070         
00071     while (str && *str)
00072     {
00073         while (isspace(*str))
00074             str++;
00075         name = 0;
00076         if (!isalpha(*str))
00077             break;
00078         // Some isalnum() implementations don't allow all the letters that
00079         // isalpha() does, e.g. accented ones.  They're not POSIX.2 compliant
00080         // but we won't punish them with an infinite loop...
00081         if (!isalnum(*str))
00082             break;
00083         while (isalnum(*str) || *str == '-' || *str == '_')
00084             name << *str++;
00085 
00086         name.lowercase();
00087                 
00088         //
00089         // We have the name.  Let's see if we will get a value
00090         //
00091         while (isspace(*str))
00092             str++;
00093         if (!*str)
00094         {
00095             //
00096             // End of string.  We need to store the name as a boolean TRUE
00097             //
00098             Add(name, "true");
00099             return;
00100         }
00101 
00102         if (!strchr((char*)separators, *str))
00103         {
00104             //
00105             // We are now at a new name.  The previous one needs to be set
00106             // to boolean TRUE
00107             //
00108             Add(name, "true");
00109             continue;
00110         }
00111 
00112         //
00113         // We now need to deal with the value
00114         //
00115         str++;                  // Skip the separator
00116         while (isspace(*str))
00117             str++;
00118         if (!*str)
00119         {
00120             //
00121             // End of string reached.  The value must be blank
00122             //
00123             Add(name, "");
00124             break;
00125         }
00126         value = 0;
00127         if (*str == '"')
00128         {
00129             //
00130             // Ah!  A quoted value.  This should be easy to deal with...
00131             // (Just kidding!)
00132             //
00133             str++;
00134             while (*str && *str != '"')
00135             {
00136                 value << *str++;
00137             }
00138             Add(name, value);
00139             if (*str == '"')
00140                 str++;
00141             continue;
00142         }
00143         else if (*str == '\'')
00144         {
00145             // A single quoted value.
00146             str++;
00147             while (*str && *str != '\'')
00148             {
00149                 value << *str++;
00150             }
00151             Add(name, value);
00152             if (*str == '\'')
00153                 str++;
00154             continue;
00155         }
00156         else
00157         {
00158             //
00159             // A non-quoted string.  This string will terminate at the
00160             // next blank
00161             //
00162             while (*str && !isspace(*str))
00163             {
00164                 value << *str++;
00165             }
00166             Add(name, value);
00167             continue;
00168         }
00169     }
00170 }
00171 
00172 
00173 //*********************************************************************
00174 //   Add an entry to the configuration table, without allowing variable
00175 //   or file expansion of the value.
00176 //
00177 void Configuration::Add(const String& name, const String& value)
00178 {
00179     String      escaped;
00180     const char  *s = value.get();
00181     while (*s)
00182     {
00183         if (strchr("$`\\", *s))
00184             escaped << '\\';
00185         escaped << *s++;
00186     }
00187     ParsedString        *ps = new ParsedString(escaped);
00188     dcGlobalVars.Add(name, ps);
00189 }
00190 
00191 
00192 //*********************************************************************
00193 //   Add an entry to the configuration table, allowing parsing for variable
00194 //   or file expansion of the value.
00195 //
00196 void Configuration::AddParsed(const String& name, const String& value)
00197 {
00198     ParsedString        *ps = new ParsedString(value);
00199     if (strcasecmp(name, "locale") == 0)
00200     {
00201         String str(setlocale(LC_ALL, ps->get(dcGlobalVars)));
00202         ps->set(str);
00203 
00204         //
00205         // Set time format to standard to avoid sending If-Modified-Since
00206         // http headers in native format which http servers can't
00207         // understand
00208         //
00209         setlocale(LC_TIME, "C");
00210     }
00211     dcGlobalVars.Add(name, ps);
00212 }
00213 
00214 
00215 //*********************************************************************
00216 //   Remove an entry from both the hash table and from the list of keys.
00217 //
00218 int Configuration::Remove(const String& name)
00219 {
00220     return dcGlobalVars.Remove(name);
00221 }
00222 
00223 
00224 //*********************************************************************
00225 // char *Configuration::Find(const char *name) const
00226 //   Retrieve a variable from the configuration database.  This variable
00227 //   will be parsed and a new String object will be returned.
00228 //
00229 const String Configuration::Find(const String& name) const
00230 {
00231     ParsedString        *ps = (ParsedString *) dcGlobalVars[name];
00232     if (ps)
00233     {
00234         return ps->get(dcGlobalVars);
00235     }
00236     else
00237     {
00238 #ifdef DEBUG_CONFIGURATION
00239         fprintf (stderr, "Could not find configuration option %s\n", (const char*)name);
00240 #endif
00241         return 0;
00242     }
00243 }
00244 
00245 //*********************************************************************
00246 Object *Configuration::Get_Object(char *name) {
00247 return dcGlobalVars[name];
00248 }
00249 
00250 
00251 //*********************************************************************
00252 //
00253 int Configuration::Value(const String& name, int default_value) const
00254 {
00255     return Find(name).as_integer(default_value);
00256 }
00257 
00258 
00259 //*********************************************************************
00260 //
00261 double Configuration::Double(const String& name, double default_value) const
00262 {
00263     return Find(name).as_double(default_value);
00264 }
00265 
00266 
00267 //*********************************************************************
00268 // int Configuration::Boolean(char *name, int default_value)
00269 //
00270 int Configuration::Boolean(const String& name, int default_value) const
00271 {
00272     int         value = default_value;
00273     const String s = Find(name);
00274     if (s[0])
00275     {
00276         if (s.nocase_compare("true") == 0 ||
00277             s.nocase_compare("yes") == 0 ||
00278             s.nocase_compare("1") == 0)
00279             value = 1;
00280         else if (s.nocase_compare("false") == 0 ||
00281                  s.nocase_compare("no") == 0 ||
00282                  s.nocase_compare("0") == 0)
00283             value = 0;
00284     }
00285 
00286     return value;
00287 }
00288 
00289 
00290 //*********************************************************************
00291 //
00292 const String Configuration::operator[](const String& name) const
00293 {
00294     return Find(name);
00295 }
00296 
00297 
00298 //*********************************************************************
00299 //
00300 int Configuration::Read(const String& filename)
00301 {
00302     FILE* in = fopen((const char*)filename, "r");
00303  
00304     if(!in) {
00305       fprintf(stderr, "Configuration::Read: cannot open %s for reading : ", (const char*)filename);
00306       perror("");
00307       return NOTOK;
00308     }
00309 
00310 #define CONFIG_BUFFER_SIZE (50*1024) 
00311      //
00312      // Make the line buffer large so that we can read long lists of start
00313      // URLs.
00314      //
00315      char       buffer[CONFIG_BUFFER_SIZE + 1];
00316      char       *current;
00317      String     line;
00318      String     name;
00319      char       *value;
00320      int        len;
00321      while (fgets(buffer, CONFIG_BUFFER_SIZE, in))
00322      {
00323          line << buffer;
00324          line.chop("\r\n");
00325          if (line.last() == '\\')
00326          {
00327              line.chop(1);
00328              continue;                  // Append the next line to this one
00329          }
00330  
00331          current = line.get();
00332          if (*current == '#' || *current == '\0')
00333          {
00334              line = 0;
00335              continue;                  // Comments and blank lines are skipped
00336          }
00337  
00338          name = strtok(current, ": =\t");
00339          value = strtok(0, "\r\n");
00340          if (!value)
00341              value = "";                        // Blank value
00342  
00343          //
00344          // Skip any whitespace before the actual text
00345          //
00346          while (*value == ' ' || *value == '\t')
00347              value++;
00348         len = strlen(value) - 1;
00349         //
00350         // Skip any whitespace after the actual text
00351         //
00352         while (value[len] == ' ' || value[len] == '\t')
00353           {
00354             value[len] = '\0';
00355             len--;
00356           }
00357  
00358         if (strcasecmp((char*)name, "include") == 0)
00359         {
00360             ParsedString        ps(value);
00361             String              str(ps.get(dcGlobalVars));
00362             if (str[0] != '/')          // Given file name not fully qualified
00363             {
00364                 str = filename;         // so strip dir. name from current one
00365                 len = str.lastIndexOf('/') + 1;
00366                 if (len > 0)
00367                     str.chop(str.length() - len);
00368                 else
00369                     str = "";           // No slash in current filename
00370                 str << ps.get(dcGlobalVars);
00371             }
00372             Read(str);
00373             line = 0;
00374             continue;
00375         }
00376  
00377          AddParsed(name, value);
00378          line = 0;
00379      }
00380      fclose(in);
00381      return OK;
00382 }
00383 
00384 
00385 //*********************************************************************
00386 // void Configuration::Defaults(ConfigDefaults *array)
00387 //
00388 void Configuration::Defaults(const ConfigDefaults *array)
00389 {
00390     for (int i = 0; array[i].name; i++)
00391     {
00392         AddParsed(array[i].name, array[i].value);
00393     }
00394 }
00395 

Generated on Sun Jun 8 10:56:39 2008 for GNUmifluz by  doxygen 1.5.5