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