00001
00002
00003
00004
00005
00006
00007
00008 #include <threemxl/platform/io/configuration/Configuration.h>
00009 #include <muParser.h>
00010 #include <stdlib.h>
00011
00012 #ifdef WIN32
00013 #include <win32_compat.h>
00014 #endif
00015
00016
00017
00018
00019 bool IConfigProperty::toBool() const
00020 {
00021 if (strcasecmp(toString().c_str(), "true") == 0)
00022 return true;
00023 else if (strcasecmp(toString().c_str(), "yes") == 0)
00024 return true;
00025 else if (strcasecmp(toString().c_str(), "false") == 0)
00026 return false;
00027 else if (strcasecmp(toString().c_str(), "no") == 0)
00028 return false;
00029 else
00030 return atoi(toString().c_str())!=0;
00031 }
00032
00033 long IConfigProperty::toInt() const
00034 {
00035 return strtol(toString().c_str(), NULL, 10);
00036 }
00037
00038 unsigned long IConfigProperty::toUInt() const
00039 {
00040 return strtoul(toString().c_str(), NULL, 10);
00041 }
00042
00043 double IConfigProperty::toFloat() const
00044 {
00045 std::istringstream i(toString());
00046 double result;
00047
00048 if (!(i >> result) || !i.eof())
00049 logErrorLn(CLog2("config"), "Could not convert \"" << toString() << "\" to a floating point value");
00050 else
00051 logCrawlLn(CLog2("config"), name() << "=" << toString());
00052 return result;
00053 }
00054
00055
00056
00057
00058
00059 CConfigProperty::CConfigProperty(IConfigProperty* configPropertyInterface)
00060 {
00061 mIConfigProperty = configPropertyInterface;
00062 }
00063
00064 CConfigProperty::~CConfigProperty()
00065 {
00066 }
00067
00068 std::string CConfigProperty::name() const
00069 {
00070 if (mIConfigProperty)
00071 return mIConfigProperty->name();
00072 else
00073 return "";
00074 }
00075
00076
00077
00078
00079
00080
00081 CConfigSection::CConfigSection(IConfigSection* configSectionInterface)
00082 {
00083 mIConfigSection = configSectionInterface;
00084 }
00085
00086 CConfigSection::~CConfigSection()
00087 {
00088 }
00089
00090 std::string CConfigSection::name() const
00091 {
00092 if (mIConfigSection)
00093 return mIConfigSection->name();
00094 else
00095 return "";
00096 }
00097
00098 bool CConfigSection::hasSection(const std::string& section) const
00099 {
00100 if (mIConfigSection)
00101 return mIConfigSection->hasSection(section);
00102 else
00103 return false;
00104 }
00105
00106 CConfigSection CConfigSection::parent() const
00107 {
00108 IConfigSection *newSection = NULL;
00109 if (mIConfigSection)
00110 newSection = mIConfigSection->parent();
00111 return CConfigSection(newSection);
00112 }
00113
00114 CConfigSection CConfigSection::section(const std::string& section) const
00115 {
00116 IConfigSection *newSection = NULL;
00117 if (mIConfigSection)
00118 newSection = mIConfigSection->section(section);
00119 return CConfigSection(newSection);
00120 }
00121
00122 CConfigSection CConfigSection::firstSection() const
00123 {
00124 IConfigSection *newSection = NULL;
00125 if (mIConfigSection)
00126 newSection = mIConfigSection->firstSection();
00127 return CConfigSection(newSection);
00128 }
00129
00130 CConfigSection CConfigSection::nextSection() const
00131 {
00132 IConfigSection *newSection = NULL;
00133 if (mIConfigSection)
00134 newSection = mIConfigSection->nextSection();
00135 return CConfigSection(newSection);
00136 }
00137
00138 CConfigSection CConfigSection::nextSimilarSection() const
00139 {
00140 IConfigSection *newSection = NULL;
00141 if (mIConfigSection)
00142 newSection = mIConfigSection->nextSimilarSection();
00143 return CConfigSection(newSection);
00144 }
00145
00146 bool CConfigSection::has(const std::string& property) const
00147 {
00148 if (mIConfigSection)
00149 return mIConfigSection->has(property);
00150 else
00151 return false;
00152 }
00153
00162 CConfigProperty CConfigSection::get(const std::string& property) const
00163 {
00164 IConfigProperty *newProperty = NULL;
00165 if (mIConfigSection)
00166 newProperty = mIConfigSection->get(property);
00167 return CConfigProperty(newProperty);
00168 }
00169
00170 CConfigProperty CConfigSection::firstProperty() const
00171 {
00172 IConfigProperty *newProperty = NULL;
00173 if (mIConfigSection)
00174 newProperty = mIConfigSection->firstProperty();
00175 return CConfigProperty(newProperty);
00176 }
00177
00178 #define CCONFIGSECTION_GET_MACRO(TYPE, ASSIGNMENT_STATEMENT) \
00179 bool CConfigSection::get(const std::string& property, TYPE *value) const \
00180 { \
00181 if (mIConfigSection) \
00182 { \
00183 IConfigProperty* iConfigProp = mIConfigSection->get(property); \
00184 if (iConfigProp) \
00185 { \
00186 ASSIGNMENT_STATEMENT; \
00187 return true; \
00188 } \
00189 else \
00190 return false; \
00191 } \
00192 else \
00193 return false; \
00194 }
00195
00196 CCONFIGSECTION_GET_MACRO(std::string , *value = iConfigProp->toString())
00197 CCONFIGSECTION_GET_MACRO(bool , *value = iConfigProp->toBool())
00198 CCONFIGSECTION_GET_MACRO(char , *value = (char)iConfigProp->toInt())
00199 CCONFIGSECTION_GET_MACRO(unsigned char , *value = (unsigned char)iConfigProp->toUInt())
00200 CCONFIGSECTION_GET_MACRO(short , *value = (short)iConfigProp->toInt())
00201 CCONFIGSECTION_GET_MACRO(unsigned short , *value = (unsigned short)iConfigProp->toUInt())
00202 CCONFIGSECTION_GET_MACRO(int , *value = (int)iConfigProp->toInt())
00203 CCONFIGSECTION_GET_MACRO(unsigned int , *value = (unsigned int)iConfigProp->toUInt())
00204 CCONFIGSECTION_GET_MACRO(long , *value = iConfigProp->toInt())
00205 CCONFIGSECTION_GET_MACRO(unsigned long , *value = iConfigProp->toUInt())
00206 CCONFIGSECTION_GET_MACRO(long long , *value = iConfigProp->toInt())
00207 CCONFIGSECTION_GET_MACRO(unsigned long long , *value = iConfigProp->toUInt())
00208 CCONFIGSECTION_GET_MACRO(float , *value = (float)iConfigProp->toFloat())
00209 CCONFIGSECTION_GET_MACRO(double , *value = iConfigProp->toFloat())
00210
00211 CCONFIGSECTION_GET_MACRO(COptionBool , *value = iConfigProp->toBool())
00212 CCONFIGSECTION_GET_MACRO(COptionInt , *value = iConfigProp->toInt())
00213 CCONFIGSECTION_GET_MACRO(COptionDouble , *value = iConfigProp->toFloat())
00214 CCONFIGSECTION_GET_MACRO(COptionChar , *value = (char)iConfigProp->toInt())
00215 CCONFIGSECTION_GET_MACRO(COptionByte , *value = (unsigned char)iConfigProp->toUInt())
00216 CCONFIGSECTION_GET_MACRO(COptionWord , *value = (unsigned short)iConfigProp->toUInt())
00217
00218 #define CCONFIGSECTION_GET_PRESET_MACRO(TYPE) \
00219 bool CConfigSection::get(const std::string& property, TYPE *value, TYPE preset) const \
00220 { \
00221 if (get(property, value)) \
00222 return true; \
00223 else \
00224 { \
00225 *value = preset; \
00226 return false; \
00227 } \
00228 }
00229
00230 CCONFIGSECTION_GET_PRESET_MACRO(std::string)
00231 CCONFIGSECTION_GET_PRESET_MACRO(bool)
00232 CCONFIGSECTION_GET_PRESET_MACRO(char)
00233 CCONFIGSECTION_GET_PRESET_MACRO(unsigned char)
00234 CCONFIGSECTION_GET_PRESET_MACRO(short)
00235 CCONFIGSECTION_GET_PRESET_MACRO(unsigned short)
00236 CCONFIGSECTION_GET_PRESET_MACRO(int)
00237 CCONFIGSECTION_GET_PRESET_MACRO(unsigned int)
00238 CCONFIGSECTION_GET_PRESET_MACRO(long)
00239 CCONFIGSECTION_GET_PRESET_MACRO(unsigned long)
00240 CCONFIGSECTION_GET_PRESET_MACRO(long long)
00241 CCONFIGSECTION_GET_PRESET_MACRO(unsigned long long)
00242 CCONFIGSECTION_GET_PRESET_MACRO(double)
00243 CCONFIGSECTION_GET_PRESET_MACRO(float)
00244
00245 bool CConfigSection::isNull() const
00246 {
00247 return (mIConfigSection == NULL);
00248 }
00249
00250 bool CConfigSection::getArray(const std::string& property, CConfigPropertyArray* array) const
00251 {
00252 if (mIConfigSection)
00253 {
00254 IConfigProperty* iConfigProp = mIConfigSection->get(property);
00255 if (iConfigProp)
00256 {
00257 array->setData(iConfigProp->toString());
00258 return true;
00259 }
00260 else
00261 return false;
00262 }
00263 else
00264 return false;
00265 }
00266
00267 bool CConfigSection::getArray(const std::string& property, double* array, unsigned int maxNumElements) const
00268 {
00269 CConfigPropertyArray propArray;
00270 if (getArray(property, &propArray))
00271 {
00272 for (unsigned int i=0; i<propArray.size() && i<maxNumElements; i++)
00273 array[i] = propArray[i].toFloat();
00274 return true;
00275 }
00276 else
00277 return false;
00278 }
00279
00280
00281
00282
00283
00284
00285 std::string CConfigProperty::value() const
00286 {
00287 if (mIConfigProperty)
00288 return mIConfigProperty->toString();
00289 else
00290 return "";
00291 }
00292
00293 CConfigProperty CConfigProperty::nextProperty() const
00294 {
00295 IConfigProperty *newProperty = NULL;
00296 if (mIConfigProperty)
00297 newProperty = mIConfigProperty->nextProperty();
00298 return CConfigProperty(newProperty);
00299 }
00300
00301 bool CConfigProperty::isNull() const
00302 {
00303 return (mIConfigProperty == NULL);
00304 }
00305
00306 void CConfigProperty::set(const std::string& value)
00307 {
00308 if (mIConfigProperty)
00309 mIConfigProperty->set(value);
00310 }
00311
00312
00313
00314
00315
00316 void CConfigPropertyArray::setData(const std::string& data, const char delimiter)
00317 {
00318 clear();
00319 std::istringstream ss(data);
00320 std::string dataFieldStr;
00321
00322 while (std::getline(ss, dataFieldStr, delimiter))
00323 push_back(IConfigPropertyString(dataFieldStr));
00324 }
00325
00326 CConfigProperty CConfigPropertyArray::operator[](size_type __n)
00327 {
00328 return CConfigProperty(&at(__n));
00329 }
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393
00394 std::string CConfiguration::replaceConstants(const std::string& expr, mu::Parser *parser)
00395 {
00396 char buf[256];
00397 std::string result(expr);
00398 mu::valmap_type cmap = parser->GetConst();
00399 if (cmap.size())
00400 {
00401 for (mu::valmap_type::const_iterator item = cmap.begin(); item!=cmap.end(); ++item)
00402 {
00403 int pos=-1;
00404 while ((pos = result.find(item->first, pos+1)) != (int)result.npos)
00405 {
00406 if ((pos == 0 || !isalpha(result[pos-1])) &&
00407 (pos+item->first.length() == result.length() || !isalnum(result[pos+item->first.length()])))
00408 {
00409 if (snprintf(buf, 255, "%.20g", item->second) >= 255) buf[255] = '\0';
00410 result.replace(pos, item->first.length(), buf);
00411 }
00412 }
00413 }
00414 }
00415 return result;
00416 }
00417
00418 std::string CConfiguration::replaceStringConstants(const std::string& expr)
00419 {
00420 std::string result(expr);
00421 if (mStringConstants.size())
00422 {
00423 for (std::map<std::string, std::string>::const_iterator item = mStringConstants.begin(); item!=mStringConstants.end(); ++item)
00424 {
00425 int pos=-1;
00426 while ((pos = result.find(item->first, pos+1)) != (int)result.npos)
00427 {
00428 if ((pos == 0 || !isalpha(result[pos-1])) &&
00429 (pos+item->first.length() == result.length() || !isalnum(result[pos+item->first.length()])))
00430 {
00431 result.replace(pos, item->first.length(), item->second);
00432 }
00433 }
00434 }
00435 }
00436 return result;
00437 }
00438
00439 int CConfiguration::resolveExpressionsInSection(const CConfigSection& section, mu::Parser *parser)
00440 {
00441 int numResolvedExpressions = 0;
00442
00443 if (shouldParseNode(section.name()))
00444 {
00445
00446
00447 for (CConfigProperty iProp = section.firstProperty(); !iProp.isNull(); iProp = iProp.nextProperty())
00448 {
00449
00450
00451 if (shouldParseNode(iProp.name()) && !isRegisteredString(iProp.value()))
00452 {
00453 std::string expression = iProp.value();
00454 char buf[256];
00455
00456
00457 parser->SetExpr(expression);
00458 try
00459 {
00460 double resolvedValue = parser->Eval();
00461 if (snprintf(buf, 255, "%.20g", resolvedValue) >= 255) buf[255] = '\0';
00462 expression = std::string(buf);
00463 }
00464 catch (...)
00465 {
00466
00467 expression = replaceConstants(expression, parser);
00468
00469
00470
00471 double dummy=0;
00472 for (std::map<std::string, std::string>::const_iterator item = mStringConstants.begin(); item!=mStringConstants.end(); ++item)
00473 parser->DefineVar(item->first, &dummy);
00474 parser->SetExpr(expression);
00475 try
00476 {
00477 parser->Eval();
00478
00479
00480 }
00481 catch (...)
00482 {
00483
00484 if (expression.find(CONFIGURATION_ARRAY_DELIMITER) == std::string::npos)
00485 mLogNoticeLn("Found expression with unknowns: \"" << expression << "\"");
00486 }
00487
00488 for (std::map<std::string, std::string>::const_iterator item = mStringConstants.begin(); item!=mStringConstants.end(); ++item)
00489 parser->RemoveVar(item->first);
00490
00491 expression = replaceStringConstants(expression);
00492 }
00493
00494 if (expression != iProp.value())
00495 {
00496 mLogCrawlLn("Resolved expression \"" << iProp.value() << "\" to \"" << expression << "\".");
00497 numResolvedExpressions++;
00498 iProp.set(expression);
00499 }
00500
00501 if (iProp.isVerbose())
00502 mLogNoticeLn("**VERBOSE** " << iProp.name() << " = " << expression);
00503 }
00504 }
00505
00506
00507 for (CConfigSection iSection = section.firstSection(); !iSection.isNull(); iSection = iSection.nextSection())
00508 numResolvedExpressions += resolveExpressionsInSection(iSection, parser);
00509 }
00510
00511 return numResolvedExpressions;
00512 }
00513
00514 int CConfiguration::resolveExpressions()
00515 {
00516
00517 mu::Parser parser;
00518
00519
00520
00521 CConfigSection constantsSection = root().section(CONST_ConfConstantsSectionName);
00522 if (!constantsSection.isNull())
00523 {
00524 for (CConfigProperty iProp = constantsSection.firstProperty(); !iProp.isNull(); iProp = iProp.nextProperty())
00525 {
00526
00527 parser.SetExpr(iProp.value());
00528 try
00529 {
00530
00531 double resolvedValue = parser.Eval();
00532
00533
00534 bool constHasConflict=false;
00535 mu::valmap_type cmap = parser.GetConst();
00536 if (cmap.size())
00537 {
00538 mu::valmap_type::const_iterator item = cmap.begin();
00539 for (; item!=cmap.end(); ++item)
00540 if (item->first == iProp.name())
00541 if (item->second != resolvedValue)
00542 {
00543 constHasConflict = true;
00544 break;
00545 }
00546 }
00547
00548 if (mStringConstants.find(iProp.name()) != mStringConstants.end())
00549 {
00550
00551
00552 constHasConflict = true;
00553 }
00554
00555
00556 if (!constHasConflict)
00557 {
00558 parser.DefineConst(iProp.name(), resolvedValue);
00559 mLogCrawlLn(iProp.name() << "=" << std::setprecision(16) << resolvedValue);
00560
00561 if (iProp.isVerbose())
00562 mLogNoticeLn("**VERBOSE** " << iProp.name() << " = " << std::setprecision(16) << resolvedValue);
00563 }
00564 else
00565 mLogErrorLn("Constant \"" << iProp.name() << "\" was redefined with different value " << resolvedValue << "!");
00566
00567 }
00568 catch (mu::Parser::exception_type &e)
00569 {
00570
00571
00572 std::map<std::string, std::string>::iterator strConst = mStringConstants.find(iProp.name());
00573 if ((strConst == mStringConstants.end()) && (parser.GetConst().find(iProp.name()) == parser.GetConst().end()))
00574 {
00575 mStringConstants[iProp.name()] = replaceStringConstants(replaceConstants(iProp.value(), &parser));
00576
00577
00578 mLogInfoLn("Defined string constant \"" << iProp.name() << "\"");
00579 }
00580 else
00581
00582 if (strConst->second != iProp.value())
00583 mLogErrorLn("Constant \"" << iProp.name() << "\" was redefined with different value: " << iProp.value());
00584 }
00585 }
00586 }
00587 else
00588 {
00589
00590 }
00591
00592
00593 CConfigSection stringsSection = root().section(CONST_ConfStringsSectionName);
00594 if (!stringsSection.isNull())
00595 {
00596 for (CConfigProperty iProp = stringsSection.firstProperty(); !iProp.isNull(); iProp = iProp.nextProperty())
00597 {
00598 if ((iProp.name() == "s") || (iProp.name() == "string"))
00599 mRegisteredStrings.push_back(iProp.value());
00600 else if ((iProp.name() == "n") || (iProp.name() == "node"))
00601 mNodesExcludedFromParsing.push_back(iProp.value());
00602 else
00603 mLogErrorLn("Strings section contains item of unknown type <" << iProp.name() << ">. Either use <s> or <string> for strings, and <n> or <node> for trusted node names.");
00604 }
00605 }
00606 else
00607 mLogNoticeLn("You did not specify a <strings> section with validated strings occurring in your configuration file. You may encounter numerous parser warnings.");
00608
00609
00610 mNodesExcludedFromParsing.push_back(CONST_ConfConstantsSectionName);
00611 mNodesExcludedFromParsing.push_back(CONST_ConfStringsSectionName);
00612
00613
00614 return resolveExpressionsInSection(root(), &parser);
00615 }
00616
00617 bool CConfiguration::isRegisteredString(const std::string& str)
00618 {
00619 for (unsigned int i=0; i<mRegisteredStrings.size(); i++)
00620 if (mRegisteredStrings[i] == str)
00621 return true;
00622
00623 return false;
00624 }
00625
00626 bool CConfiguration::shouldParseNode(const std::string& nodeName)
00627 {
00628 for (unsigned int i=0; i<mNodesExcludedFromParsing.size(); i++)
00629 if (mNodesExcludedFromParsing[i] == nodeName)
00630 return false;
00631
00632 return true;
00633 }