|
reSIProcate/rutil
9694
|
00001 #include <iostream> 00002 #include <fstream> 00003 #include <iterator> 00004 #include <stdexcept> 00005 00006 #include "rutil/ConfigParse.hxx" 00007 #include "rutil/Log.hxx" 00008 #include "rutil/Logger.hxx" 00009 #include "rutil/ParseBuffer.hxx" 00010 #include "rutil/WinLeakCheck.hxx" 00011 00012 using namespace resip; 00013 using namespace std; 00014 00015 #define RESIPROCATE_SUBSYSTEM Subsystem::SIP 00016 00017 namespace resip 00018 { 00019 00020 ConfigParse::ConfigParse(int argc, char** argv, const resip::Data& defaultConfigFilename) 00021 { 00022 parseCommandLine(argc, argv); // will fill in mCmdLineConfigFilename if present 00023 if(mCmdLineConfigFilename.empty()) 00024 { 00025 parseConfigFile(defaultConfigFilename); 00026 } 00027 else 00028 { 00029 parseConfigFile(mCmdLineConfigFilename); 00030 } 00031 } 00032 00033 ConfigParse::ConfigParse() 00034 { 00035 } 00036 00037 ConfigParse::~ConfigParse() 00038 { 00039 } 00040 00041 bool 00042 ConfigParse::getConfigValue(const resip::Data& name, resip::Data &value) 00043 { 00044 Data lowerName(name); lowerName.lowercase(); 00045 ConfigValuesMap::iterator it = mConfigValues.find(lowerName); 00046 if(it != mConfigValues.end()) 00047 { 00048 value = it->second; 00049 return true; 00050 } 00051 // Not found 00052 return false; 00053 } 00054 00055 Data 00056 ConfigParse::getConfigData(const resip::Data& name, const resip::Data& defaultValue, bool useDefaultIfEmpty) 00057 { 00058 Data ret(defaultValue); 00059 if(getConfigValue(name, ret) && ret.empty() && useDefaultIfEmpty) 00060 { 00061 return defaultValue; 00062 } 00063 return ret; 00064 } 00065 00066 bool 00067 ConfigParse::getConfigValue(const resip::Data& name, bool &value) 00068 { 00069 Data lowerName(name); lowerName.lowercase(); 00070 ConfigValuesMap::iterator it = mConfigValues.find(lowerName); 00071 if(it != mConfigValues.end()) 00072 { 00073 if(it->second == "1" || 00074 isEqualNoCase(it->second, "true") || 00075 isEqualNoCase(it->second, "on") || 00076 isEqualNoCase(it->second, "enable")) 00077 { 00078 value = true; 00079 return true; 00080 } 00081 else if(it->second == "0" || 00082 isEqualNoCase(it->second, "false") || 00083 isEqualNoCase(it->second, "off") || 00084 isEqualNoCase(it->second, "disable")) 00085 { 00086 value = false; 00087 return true; 00088 } 00089 cerr << "Invalid boolean setting: " << name << " = " << it->second << ": Valid values are: 1,true,on,enable,0,false,off or disable" << endl; 00090 return false; 00091 } 00092 // Not found 00093 return false; 00094 } 00095 00096 bool 00097 ConfigParse::getConfigBool(const resip::Data& name, bool defaultValue) 00098 { 00099 bool ret = defaultValue; 00100 getConfigValue(name, ret); 00101 return ret; 00102 } 00103 00104 bool 00105 ConfigParse::getConfigValue(const resip::Data& name, unsigned long &value) 00106 { 00107 Data lowerName(name); lowerName.lowercase(); 00108 ConfigValuesMap::iterator it = mConfigValues.find(lowerName); 00109 if(it != mConfigValues.end()) 00110 { 00111 value = it->second.convertUnsignedLong(); 00112 return true; 00113 } 00114 // Not found 00115 return false; 00116 } 00117 00118 unsigned long 00119 ConfigParse::getConfigUnsignedLong(const resip::Data& name, unsigned long defaultValue) 00120 { 00121 unsigned long ret = defaultValue; 00122 getConfigValue(name, ret); 00123 return ret; 00124 } 00125 00126 bool 00127 ConfigParse::getConfigValue(const resip::Data& name, int &value) 00128 { 00129 Data lowerName(name); lowerName.lowercase(); 00130 ConfigValuesMap::iterator it = mConfigValues.find(lowerName); 00131 if(it != mConfigValues.end()) 00132 { 00133 value = it->second.convertInt(); 00134 return true; 00135 } 00136 // Not found 00137 return false; 00138 } 00139 00140 00141 int 00142 ConfigParse::getConfigInt(const resip::Data& name, int defaultValue) 00143 { 00144 int ret = defaultValue; 00145 getConfigValue(name, ret); 00146 return ret; 00147 } 00148 00149 bool 00150 ConfigParse::getConfigValue(const resip::Data& name, unsigned short &value) 00151 { 00152 Data lowerName(name); lowerName.lowercase(); 00153 ConfigValuesMap::iterator it = mConfigValues.find(lowerName); 00154 if(it != mConfigValues.end()) 00155 { 00156 value = it->second.convertInt(); 00157 return true; 00158 } 00159 // Not found 00160 return false; 00161 } 00162 00163 00164 unsigned short 00165 ConfigParse::getConfigUnsignedShort(const resip::Data& name, int defaultValue) 00166 { 00167 int ret = defaultValue; 00168 getConfigValue(name, ret); 00169 return ret; 00170 } 00171 00172 bool 00173 ConfigParse::getConfigValue(const resip::Data& name, std::vector<resip::Data> &value) 00174 { 00175 Data lowerName(name); lowerName.lowercase(); 00176 std::pair<ConfigValuesMap::iterator,ConfigValuesMap::iterator> valuesIts = mConfigValues.equal_range(lowerName); 00177 bool found = false; 00178 for (ConfigValuesMap::iterator it=valuesIts.first; it!=valuesIts.second; ++it) 00179 { 00180 found = true; 00181 ParseBuffer pb(it->second); 00182 Data item; 00183 while(!it->second.empty() && !pb.eof()) 00184 { 00185 pb.skipWhitespace(); 00186 const char *start = pb.position(); 00187 pb.skipToOneOf(ParseBuffer::Whitespace, ","); // allow white space 00188 pb.data(item, start); 00189 value.push_back(item); 00190 if(!pb.eof()) 00191 { 00192 pb.skipChar(); 00193 } 00194 } 00195 } 00196 00197 return found; 00198 } 00199 00200 void 00201 ConfigParse::insertConfigValue(const resip::Data& name, const resip::Data& value) 00202 { 00203 resip::Data lowerName(name); 00204 lowerName.lowercase(); 00205 mConfigValues.insert(ConfigValuesMap::value_type(lowerName, value)); 00206 } 00207 00208 void 00209 ConfigParse::parseCommandLine(int argc, char** argv) 00210 { 00211 int startingArgForNameValuePairs = 1; 00212 // First argument is the configuration filename - it is optional and is never proceeded with a - or / 00213 #ifdef WIN32 00214 if(argc >= 2 && argv[1][0] != '-' && argv[1][0] != '/') 00215 #else 00216 if(argc >= 2 && argv[1][0] != '-') 00217 #endif 00218 { 00219 mCmdLineConfigFilename = argv[1]; 00220 startingArgForNameValuePairs = 2; 00221 } 00222 00223 // Loop through command line arguments and process them 00224 for(int i = startingArgForNameValuePairs; i < argc; i++) 00225 { 00226 Data argData(argv[i]); 00227 00228 // Process all commandNames that don't take values 00229 if(isEqualNoCase(argData, "-?") || 00230 isEqualNoCase(argData, "--?") || 00231 isEqualNoCase(argData, "--help") || 00232 isEqualNoCase(argData, "/?")) 00233 { 00234 printHelpText(argc, argv); 00235 exit(1); 00236 } 00237 else if(argData.at(0) == '-' || argData.at(0) == '/') 00238 { 00239 Data name; 00240 Data value; 00241 ParseBuffer pb(argData); 00242 00243 try 00244 { 00245 pb.skipChars(Data::toBitset("-/")); // Skip any leading -'s or /'s 00246 const char * anchor = pb.position(); 00247 pb.skipToOneOf("=:"); 00248 if(!pb.eof()) 00249 { 00250 pb.data(name, anchor); 00251 pb.skipChar(); 00252 anchor = pb.position(); 00253 pb.skipToEnd(); 00254 pb.data(value, anchor); 00255 00256 //cout << "Command line Name='" << name << "' value='" << value << "'" << endl; 00257 insertConfigValue(name, value); 00258 } 00259 else 00260 { 00261 cerr << "Invalid command line parameters:" << endl; 00262 cerr << " Name/Value pairs must contain an = or a : between the name and the value" << endl; 00263 exit(-1); 00264 } 00265 } 00266 catch(BaseException& ex) 00267 { 00268 cerr << "Invalid command line parameters:" << endl; 00269 cerr << " Exception parsing Name/Value pairs: " << ex << endl; 00270 exit(-1); 00271 } 00272 } 00273 else 00274 { 00275 cerr << "Invalid command line parameters:" << endl; 00276 cerr << " Name/Value pairs must be prefixed with either a -, --, or a /" << endl; 00277 exit(-1); 00278 } 00279 } 00280 } 00281 00282 void 00283 ConfigParse::parseConfigFile(const Data& filename) 00284 { 00285 ifstream configFile(filename.c_str()); 00286 00287 if(!configFile) 00288 { 00289 throw Exception("Error opening/reading configuration file", __FILE__, __LINE__); 00290 } 00291 00292 string sline; 00293 const char * anchor; 00294 while(getline(configFile, sline)) 00295 { 00296 Data line(sline); 00297 Data name; 00298 Data value; 00299 ParseBuffer pb(line); 00300 00301 pb.skipWhitespace(); 00302 anchor = pb.position(); 00303 if(pb.eof() || *anchor == '#') continue; // if line is a comment or blank then skip it 00304 00305 // Look for end of name 00306 pb.skipToOneOf("= \t"); 00307 pb.data(name,anchor); 00308 if(*pb.position()!='=') 00309 { 00310 pb.skipToChar('='); 00311 } 00312 pb.skipChar('='); 00313 pb.skipWhitespace(); 00314 anchor = pb.position(); 00315 if(!pb.eof()) 00316 { 00317 pb.skipToOneOf("\r\n"); 00318 pb.data(value, anchor); 00319 } 00320 //cout << "Config file Name='" << name << "' value='" << value << "'" << endl; 00321 insertConfigValue(name, value); 00322 } 00323 } 00324 00325 EncodeStream& 00326 operator<<(EncodeStream& strm, const ConfigParse& config) 00327 { 00328 ConfigParse::ConfigValuesMap::const_iterator it = config.mConfigValues.begin(); 00329 for(; it != config.mConfigValues.end(); it++) 00330 { 00331 strm << it->first << " = " << it->second << endl; 00332 } 00333 return strm; 00334 } 00335 00336 } 00337 00338 /* ==================================================================== 00339 * The Vovida Software License, Version 1.0 00340 * 00341 * Copyright (c) 2000 Vovida Networks, Inc. All rights reserved. 00342 * 00343 * Redistribution and use in source and binary forms, with or without 00344 * modification, are permitted provided that the following conditions 00345 * are met: 00346 * 00347 * 1. Redistributions of source code must retain the above copyright 00348 * notice, this list of conditions and the following disclaimer. 00349 * 00350 * 2. Redistributions in binary form must reproduce the above copyright 00351 * notice, this list of conditions and the following disclaimer in 00352 * the documentation and/or other materials provided with the 00353 * distribution. 00354 * 00355 * 3. The names "VOCAL", "Vovida Open Communication Application Library", 00356 * and "Vovida Open Communication Application Library (VOCAL)" must 00357 * not be used to endorse or promote products derived from this 00358 * software without prior written permission. For written 00359 * permission, please contact vocal@vovida.org. 00360 * 00361 * 4. Products derived from this software may not be called "VOCAL", nor 00362 * may "VOCAL" appear in their name, without prior written 00363 * permission of Vovida Networks, Inc. 00364 * 00365 * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED 00366 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 00367 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND 00368 * NON-INFRINGEMENT ARE DISCLAIMED. IN NO EVENT SHALL VOVIDA 00369 * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES 00370 * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL, 00371 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 00372 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 00373 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 00374 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00375 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE 00376 * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH 00377 * DAMAGE. 00378 * 00379 * ==================================================================== 00380 * 00381 * This software consists of voluntary contributions made by Vovida 00382 * Networks, Inc. and many individuals on behalf of Vovida Networks, 00383 * Inc. For more information on Vovida Networks, Inc., please see 00384 * <http://www.vovida.org/>. 00385 * 00386 */
1.7.5.1