00001
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #ifdef _MSC_VER
00023 #include <windows_config.h>
00024 #else
00025 #include <config.h>
00026 #endif
00027
00028 #include <map>
00029 #include <string>
00030 #include <exception>
00031 #include <algorithm>
00032 #include <vector>
00033 #include <iostream>
00034 #include <cstdlib>
00035 #include <cassert>
00036 #include <ctime>
00037 #include "Option.h"
00038 #include "OptionsCont.h"
00039 #include <utils/common/UtilExceptions.h>
00040 #include <utils/common/FileHelpers.h>
00041 #include <utils/common/MsgHandler.h>
00042 #include <utils/common/StringTokenizer.h>
00043 #include <utils/common/StringUtils.h>
00044 #include <sstream>
00045
00046 #ifdef CHECK_MEMORY_LEAKS
00047 #include <foreign/nvwa/debug_new.h>
00048 #endif // CHECK_MEMORY_LEAKS
00049
00050
00051
00052
00053
00054 OptionsCont OptionsCont::myOptions;
00055
00056
00057
00058
00059
00060 OptionsCont &
00061 OptionsCont::getOptions() throw() {
00062 return myOptions;
00063 }
00064
00065
00066 OptionsCont::OptionsCont() throw()
00067 : myAddresses(), myValues(), myHaveInformedAboutDeprecatedDivider(false) {}
00068
00069
00070 OptionsCont::~OptionsCont() throw() {
00071 clear();
00072 }
00073
00074
00075 void
00076 OptionsCont::doRegister(const std::string &name, Option *v) throw(InvalidArgument) {
00077 assert(v!=0);
00078 ItemAddressContType::iterator i = find(myAddresses.begin(), myAddresses.end(), v);
00079 if (i==myAddresses.end()) {
00080 myAddresses.push_back(v);
00081 }
00082 if (myValues.find(name)!=myValues.end()) {
00083 throw InvalidArgument(name + " is an already used option name.");
00084 }
00085 myValues[name] = v;
00086 }
00087
00088
00089 void
00090 OptionsCont::doRegister(const std::string &name1, char abbr, Option *v) throw(InvalidArgument) {
00091 doRegister(name1, v);
00092 doRegister(convertChar(abbr), v);
00093 }
00094
00095
00096 void
00097 OptionsCont::addSynonyme(const std::string &name1, const std::string &name2) throw(InvalidArgument) {
00098 KnownContType::iterator i1 = myValues.find(name1);
00099 KnownContType::iterator i2 = myValues.find(name2);
00100 if (i1==myValues.end()&&i2==myValues.end()) {
00101 throw InvalidArgument("Neither the option '" + name1 + "' nor the option '" + name2 + "' is known yet");
00102 }
00103 if (i1!=myValues.end()&&i2!=myValues.end()) {
00104 if ((*i1).second==(*i2).second) {
00105 return;
00106 }
00107 throw InvalidArgument("Both options '" + name1 + "' and '" + name2 + "' do exist and differ.");
00108 }
00109 if (i1==myValues.end()&&i2!=myValues.end()) {
00110 doRegister(name1, (*i2).second);
00111 }
00112 if (i1!=myValues.end()&&i2==myValues.end()) {
00113 doRegister(name2, (*i1).second);
00114 }
00115 }
00116
00117
00118 bool
00119 OptionsCont::exists(const std::string &name) const throw() {
00120 KnownContType::const_iterator i = myValues.find(name);
00121 return i!=myValues.end();
00122 }
00123
00124
00125 bool
00126 OptionsCont::isSet(const std::string &name) const throw(InvalidArgument) {
00127 KnownContType::const_iterator i = myValues.find(name);
00128 if (i==myValues.end()) {
00129 return false;
00130 }
00131 return (*i).second->isSet();
00132 }
00133
00134
00135 bool
00136 OptionsCont::isDefault(const std::string &name) const throw(InvalidArgument) {
00137 KnownContType::const_iterator i = myValues.find(name);
00138 if (i==myValues.end()) {
00139 return false;
00140 }
00141 return (*i).second->isDefault();
00142 }
00143
00144
00145 Option *
00146 OptionsCont::getSecure(const std::string &name) const throw(InvalidArgument) {
00147 KnownContType::const_iterator i = myValues.find(name);
00148 if (i==myValues.end()) {
00149 throw InvalidArgument("No option with the name '" + name + "' exists.");
00150 }
00151 return (*i).second;
00152 }
00153
00154
00155 std::string
00156 OptionsCont::getString(const std::string &name) const throw(InvalidArgument) {
00157 Option *o = getSecure(name);
00158 return o->getString();
00159 }
00160
00161
00162 SUMOReal
00163 OptionsCont::getFloat(const std::string &name) const throw(InvalidArgument) {
00164 Option *o = getSecure(name);
00165 return o->getFloat();
00166 }
00167
00168
00169 int
00170 OptionsCont::getInt(const std::string &name) const throw(InvalidArgument) {
00171 Option *o = getSecure(name);
00172 return o->getInt();
00173 }
00174
00175
00176 bool
00177 OptionsCont::getBool(const std::string &name) const throw(InvalidArgument) {
00178 Option *o = getSecure(name);
00179 return o->getBool();
00180 }
00181
00182
00183 const IntVector &
00184 OptionsCont::getIntVector(const std::string &name) const throw(InvalidArgument) {
00185 Option *o = getSecure(name);
00186 return o->getIntVector();
00187 }
00188
00189
00190 bool
00191 OptionsCont::set(const std::string &name, const std::string &value) throw(InvalidArgument) {
00192 Option *o = getSecure(name);
00193 if (!o->isWriteable()) {
00194 reportDoubleSetting(name);
00195 return false;
00196 }
00197 try {
00198 if (!o->set(value)) {
00199 return false;
00200 }
00201 } catch (InvalidArgument &e) {
00202 MsgHandler::getErrorInstance()->inform("While processing option '" + name + "':\n " + e.what());
00203 return false;
00204 }
00205 return true;
00206 }
00207
00208
00209 bool
00210 OptionsCont::set(const std::string &name, bool value) throw(InvalidArgument) {
00211 Option *o = getSecure(name);
00212 if (!o->isBool()) {
00213 throw InvalidArgument("The option '" + name + "' is not a boolean attribute and requires an argument.");
00214 }
00215 if (!o->isWriteable()) {
00216 reportDoubleSetting(name);
00217 return false;
00218 }
00219 try {
00220 if (!o->set(value)) {
00221 return false;
00222 }
00223 } catch (InvalidArgument &e) {
00224 MsgHandler::getErrorInstance()->inform("While processing option '" + name + "':\n " + e.what());
00225 return false;
00226 }
00227 return true;
00228 }
00229
00230
00231 std::vector<std::string>
00232 OptionsCont::getSynonymes(const std::string &name) const throw(InvalidArgument) {
00233 Option *o = getSecure(name);
00234 std::vector<std::string> v(0);
00235 for (KnownContType::const_iterator i=myValues.begin(); i!=myValues.end(); i++) {
00236 if ((*i).second==o&&name!=(*i).first) {
00237 v.push_back((*i).first);
00238 }
00239 }
00240 return v;
00241 }
00242
00243
00244 std::ostream&
00245 operator<<(std::ostream& os, const OptionsCont& oc) {
00246 std::vector<std::string> done;
00247 os << "Options set:" << std::endl;
00248 for (OptionsCont::KnownContType::const_iterator i=oc.myValues.begin();
00249 i!=oc.myValues.end(); i++) {
00250 std::vector<std::string>::iterator j = find(done.begin(), done.end(), (*i).first);
00251 if (j==done.end()) {
00252 std::vector<std::string> synonymes = oc.getSynonymes((*i).first);
00253 if (synonymes.size()!=0) {
00254 os << (*i).first << " (";
00255 for (j=synonymes.begin(); j!=synonymes.end(); j++) {
00256 if (j!=synonymes.begin()) {
00257 os << ", ";
00258 }
00259 os << (*j);
00260 }
00261 os << ")";
00262 } else {
00263 os << (*i).first;
00264 }
00265 if ((*i).second->isSet()) {
00266 os << ": " << (*i).second->getValueString() << std::endl;
00267 } else {
00268 os << ": <INVALID>" << std::endl;
00269 }
00270 done.push_back((*i).first);
00271 copy(synonymes.begin(), synonymes.end(), back_inserter(done));
00272 }
00273 }
00274 return os;
00275 }
00276
00277
00278 void
00279 OptionsCont::relocateFiles(const std::string &configuration) const throw() {
00280 for (ItemAddressContType::const_iterator i=myAddresses.begin(); i!=myAddresses.end(); i++) {
00281 if ((*i)->isFileName() && (*i)->isSet()) {
00282 StringTokenizer st((*i)->getString(), ";, ", true);
00283 std::string conv;
00284 while (st.hasNext()) {
00285 if (conv.length()!=0) {
00286 conv += ',';
00287 }
00288 std::string tmp = st.next();
00289 if (!FileHelpers::isAbsolute(tmp)) {
00290 tmp = FileHelpers::getConfigurationRelative(configuration, tmp);
00291 }
00292 conv += tmp;
00293 }
00294 (*i)->set(conv);
00295 }
00296 }
00297 }
00298
00299
00300 bool
00301 OptionsCont::isUsableFileList(const std::string &name) const throw(InvalidArgument) {
00302 Option *o = getSecure(name);
00303
00304
00305 if (!o->isSet()) {
00306 return false;
00307 }
00308
00309 bool ok = true;
00310 std::vector<std::string> files = getStringVector(name);
00311 if (files.size()==0) {
00312 MsgHandler::getErrorInstance()->inform("The file list for '" + name + "' is empty.");
00313 ok = false;
00314 }
00315 for (std::vector<std::string>::const_iterator fileIt=files.begin(); fileIt!=files.end(); ++fileIt) {
00316 if (!FileHelpers::exists(*fileIt)) {
00317 if (*fileIt!="") {
00318 MsgHandler::getErrorInstance()->inform("File '" + *fileIt + "' does not exist.");
00319 ok = false;
00320 } else {
00321 MsgHandler::getWarningInstance()->inform("Empty file name given; ignoring.");
00322 }
00323 }
00324 }
00325 return ok;
00326 }
00327
00328
00329 bool
00330 OptionsCont::checkDependingSuboptions(const std::string &name, const std::string &prefix) const throw(InvalidArgument) {
00331 Option *o = getSecure(name);
00332 if (o->isSet()) {
00333 return true;
00334 }
00335 bool ok = true;
00336 for (KnownContType::const_iterator i=myValues.begin(); i!=myValues.end(); i++) {
00337 if ((*i).second->isSet() && !(*i).second->isDefault() && (*i).first.find(prefix) == 0) {
00338 MsgHandler::getErrorInstance()->inform("Option '" + (*i).first + "' needs option '" + name + "'.");
00339 ok = false;
00340 }
00341 }
00342 return ok;
00343 }
00344
00345
00346 void
00347 OptionsCont::reportDoubleSetting(const std::string &arg) const throw() {
00348 std::vector<std::string> synonymes = getSynonymes(arg);
00349 std::ostringstream s;
00350 s << "A value for the option '" + arg + "' was already set.\n Possible synonymes: ";
00351 for (std::vector<std::string>::iterator i=synonymes.begin(); i!=synonymes.end();) {
00352 s << (*i);
00353 i++;
00354 if (i!=synonymes.end()) {
00355 s << ", ";
00356 }
00357 }
00358 MsgHandler::getErrorInstance()->inform(s.str());
00359 }
00360
00361
00362 std::string
00363 OptionsCont::convertChar(char abbr) const throw() {
00364 char buf[2];
00365 buf[0] = abbr;
00366 buf[1] = 0;
00367 std::string s(buf);
00368 return s;
00369 }
00370
00371
00372 bool
00373 OptionsCont::isBool(const std::string &name) const throw(InvalidArgument) {
00374 Option *o = getSecure(name);
00375 return o->isBool();
00376 }
00377
00378
00379 void
00380 OptionsCont::resetWritable() throw() {
00381 for (ItemAddressContType::iterator i=myAddresses.begin(); i!=myAddresses.end(); i++) {
00382 (*i)->myAmWritable = true;
00383 }
00384 }
00385
00386
00387 bool
00388 OptionsCont::isWriteable(const std::string &name) throw(InvalidArgument) {
00389 Option *o = getSecure(name);
00390 return o->isWriteable();
00391 }
00392
00393
00394 void
00395 OptionsCont::clear() throw() {
00396 ItemAddressContType::iterator i;
00397 for (i=myAddresses.begin(); i!=myAddresses.end(); i++) {
00398 delete(*i);
00399 }
00400 myAddresses.clear();
00401 myValues.clear();
00402 mySubTopics.clear();
00403 mySubTopicEntries.clear();
00404 }
00405
00406
00407 void
00408 OptionsCont::addDescription(const std::string &name,
00409 const std::string &subtopic,
00410 const std::string &description) throw(InvalidArgument) {
00411 Option *o = getSecure(name);
00412 assert(o!=0);
00413 assert(o->myDescription=="");
00414 assert(find(mySubTopics.begin(), mySubTopics.end(), subtopic)!=mySubTopics.end());
00415 o->myDescription = description;
00416 mySubTopicEntries[subtopic].push_back(name);
00417 }
00418
00419
00420 void
00421 OptionsCont::setApplicationName(const std::string &appName,
00422 const std::string &fullName) throw() {
00423 myAppName = appName;
00424 myFullName = fullName;
00425 }
00426
00427
00428 void
00429 OptionsCont::setApplicationDescription(const std::string &appDesc) throw() {
00430 myAppDescription = appDesc;
00431 }
00432
00433
00434 void
00435 OptionsCont::addCallExample(const std::string &example) throw() {
00436 myCallExamples.push_back(example);
00437 }
00438
00439
00440 void
00441 OptionsCont::setAdditionalHelpMessage(const std::string &add) throw() {
00442 myAdditionalMessage = add;
00443 }
00444
00445
00446 void
00447 OptionsCont::addOptionSubTopic(const std::string &topic) throw() {
00448 mySubTopics.push_back(topic);
00449 mySubTopicEntries[topic] = std::vector<std::string>();
00450 }
00451
00452
00453 void
00454 OptionsCont::splitLines(std::ostream &os, std::string what,
00455 size_t offset, size_t nextOffset) throw() {
00456 while (what.length()>0) {
00457 if (what.length()>79-offset) {
00458 size_t splitPos = what.rfind(';', 79-offset);
00459 if (splitPos==std::string::npos) {
00460 splitPos = what.rfind(' ', 79-offset);
00461 } else {
00462 splitPos++;
00463 }
00464 if (splitPos!=std::string::npos) {
00465 os << what.substr(0, splitPos) << std::endl;
00466 what = what.substr(splitPos);
00467 for (size_t r=0; r<nextOffset+1; ++r) {
00468 os << ' ';
00469 }
00470 } else {
00471 os << what;
00472 what = "";
00473 }
00474 offset = nextOffset;
00475 } else {
00476 os << what;
00477 what = "";
00478 }
00479 }
00480 os << std::endl;
00481 }
00482
00483
00484 bool
00485 OptionsCont::processMetaOptions(bool missingOptions) throw(ProcessError) {
00486 if (missingOptions) {
00487
00488 std::cout << myFullName << std::endl;
00489 std::cout << " (c) DLR 2001-2009; http://sumo.sourceforge.net" << std::endl;
00490 std::cout << " Use --help to get the list of options." << std::endl;
00491 return true;
00492 }
00493
00494 OptionsCont &oc = OptionsCont::getOptions();
00495
00496 if (oc.getBool("help")) {
00497 std::cout << myFullName << std::endl;
00498 std::cout << " (c) DLR 2001-2009; http://sumo.sourceforge.net" << std::endl;
00499 oc.printHelp(std::cout);
00500 return true;
00501 }
00502
00503 if (oc.getBool("print-options")) {
00504 std::cout << oc;
00505 }
00506
00507
00508 if (oc.isSet("save-configuration")) {
00509 std::ofstream out(oc.getString("save-configuration").c_str());
00510 if (!out.good()) {
00511 throw ProcessError("Could not save configuration to '" + oc.getString("save-configuration") + "'");
00512 } else {
00513 oc.writeConfiguration(out, true, false, false);
00514 if (oc.getBool("verbose")) {
00515 MsgHandler::getMessageInstance()->inform("Written configuration to '" + oc.getString("save-configuration") + "'");
00516 }
00517 return true;
00518 }
00519 }
00520
00521 if (oc.isSet("save-template")) {
00522 std::ofstream out(oc.getString("save-template").c_str());
00523 if (!out.good()) {
00524 throw ProcessError("Could not save template to '" + oc.getString("save-template") + "'");
00525 } else {
00526 oc.writeConfiguration(out, false, true, oc.getBool("save-template.commented"));
00527 if (oc.getBool("verbose")) {
00528 MsgHandler::getMessageInstance()->inform("Written template to '" + oc.getString("save-template") + "'");
00529 }
00530 return true;
00531 }
00532 }
00533 return false;
00534 }
00535
00536 void
00537 OptionsCont::printHelp(std::ostream &os) throw() {
00538 std::vector<std::string>::const_iterator i, j;
00539
00540 os << ' ' << std::endl;
00541 splitLines(os, myAppDescription , 0, 0);
00542 os << std::endl;
00543
00544 os << "Usage: " << myAppName << " [OPTION]*" << std::endl;
00545 os << ' ' << std::endl;
00546
00547 if (myCallExamples.size()>1) {
00548 os << " Examples:" << std::endl;
00549 } else if (myCallExamples.size()!=0) {
00550 os << " Example:" << std::endl;
00551 }
00552 if (myCallExamples.size()!=0) {
00553 for (i=myCallExamples.begin(); i!=myCallExamples.end(); ++i) {
00554 os << " " << myAppName << ' ' << (*i) << std::endl;
00555 }
00556 }
00557 os << ' ' << std::endl;
00558
00559 if (myAdditionalMessage.length()>0) {
00560 os << myAdditionalMessage << std::endl << ' ' << std::endl;
00561 }
00562
00563
00564
00565 size_t tooLarge = 40;
00566 size_t maxSize = 0;
00567 for (i=mySubTopics.begin(); i!=mySubTopics.end(); ++i) {
00568 const std::vector<std::string> &entries = mySubTopicEntries[*i];
00569 for (j=entries.begin(); j!=entries.end(); ++j) {
00570 Option *o = getSecure(*j);
00571
00572 size_t csize = (*j).length() + 2 + 4;
00573
00574 std::vector<std::string> synonymes = getSynonymes(*j);
00575 if (find_if(synonymes.begin(), synonymes.end(), abbreviation_finder())!=synonymes.end()) {
00576 csize += 4;
00577 }
00578
00579 if (!o->isBool()) {
00580 csize += 1 + o->getTypeName().length();
00581 }
00582
00583 csize += 2;
00584 if (csize<tooLarge&&maxSize<csize) {
00585 maxSize = csize;
00586 }
00587 }
00588 }
00589
00590 for (i=mySubTopics.begin(); i!=mySubTopics.end(); ++i) {
00591 os << ' ' << *i << " Options:" << std::endl;
00592 const std::vector<std::string> &entries = mySubTopicEntries[*i];
00593 for (j=entries.begin(); j!=entries.end(); ++j) {
00594
00595 size_t csize = (*j).length() + 2;
00596 Option *o = getSecure(*j);
00597 os << " ";
00598
00599 std::vector<std::string> synonymes = getSynonymes(*j);
00600 std::vector<std::string>::iterator a = find_if(synonymes.begin(), synonymes.end(), abbreviation_finder());
00601 if (a!=synonymes.end()) {
00602 os << '-' << (*a) << ", ";
00603 csize += 4;
00604 }
00605
00606 os << "--";
00607 csize += 2;
00608
00609 os << *j;
00610
00611 if (!o->isBool()) {
00612 os << ' ' << o->getTypeName();
00613 csize += 1 + o->getTypeName().length();
00614 }
00615 csize += 2;
00616
00617 os << " ";
00618 size_t r;
00619 for (r=maxSize; r>csize; --r) {
00620 os << ' ';
00621 }
00622 std::string desc = o->getDescription();
00623 size_t offset = csize > tooLarge ? csize : maxSize;
00624 splitLines(os, desc, offset, maxSize);
00625 }
00626 os << std::endl;
00627 }
00628 }
00629
00630
00631 void
00632 OptionsCont::writeConfiguration(std::ostream &os, bool filled,
00633 bool complete, bool addComments) throw() {
00634 std::vector<std::string>::const_iterator i, j;
00635 os << "<configuration>" << std::endl << std::endl;
00636 for (i=mySubTopics.begin(); i!=mySubTopics.end(); ++i) {
00637 std::string subtopic = *i;
00638 if (subtopic=="Configuration") {
00639 continue;
00640 }
00641 for (size_t k=0; k<subtopic.length(); ++k) {
00642 if (subtopic[k]==' ') {
00643 subtopic[k] = '_';
00644 }
00645 if (subtopic[k]>='A'&&subtopic[k]<='Z') {
00646 subtopic[k] = subtopic[k] - 'A' + 'a';
00647 }
00648 }
00649 const std::vector<std::string> &entries = mySubTopicEntries[*i];
00650 bool hadOne = false;
00651 for (j=entries.begin(); j!=entries.end(); ++j) {
00652 Option *o = getSecure(*j);
00653 bool write = complete || (filled&&!o->isDefault());
00654 if (!write) {
00655 continue;
00656 }
00657 if (!hadOne) {
00658 os << " <" << subtopic << ">" << std::endl;
00659 }
00660
00661 if (addComments) {
00662 os << " <!-- " << o->getDescription() << " -->" << std::endl;
00663 }
00664
00665 os << " <" << *j << " value=\"";
00666 if (o->isSet()) {
00667 os << o->getValueString();
00668 }
00669 os << "\"/>" << std::endl;
00670
00671 if (addComments) {
00672 os << std::endl;
00673 }
00674 hadOne = true;
00675 }
00676 if (hadOne) {
00677 os << " </" << subtopic << ">" << std::endl << std::endl;
00678 }
00679 }
00680 os << "</configuration>" << std::endl;
00681 }
00682
00683
00684 void
00685 OptionsCont::writeXMLHeader(std::ostream &os, const bool writeConfig) throw() {
00686 time_t rawtime;
00687 char buffer [80];
00688
00689 os << "<?xml version=\"1.0\"?>\n\n";
00690 time(&rawtime);
00691 strftime(buffer, 80, "<!-- generated on %c by ", localtime(&rawtime));
00692 os << buffer << myFullName << "\n";
00693 if (writeConfig) {
00694 writeConfiguration(os, true, false, false);
00695 }
00696 os << "-->\n\n";
00697 }
00698
00699
00700 std::vector<std::string>
00701 OptionsCont::getStringVector(const std::string &name) const throw(InvalidArgument) {
00702 Option *o = getSecure(name);
00703 std::string def = o->getString();
00704 if (def.find(';')!=std::string::npos&&!myHaveInformedAboutDeprecatedDivider) {
00705 MsgHandler::getWarningInstance()->inform("Please note that using ';' as list separator is deprecated.\n From 1.0 onwards, only ',' will be accepted.");
00706 myHaveInformedAboutDeprecatedDivider = true;
00707 }
00708 StringTokenizer st(def, ";,", true);
00709 std::vector<std::string> ret = st.getVector();
00710 for (std::vector<std::string>::iterator i=ret.begin(); i!=ret.end(); ++i) {
00711 (*i) = StringUtils::prune(*i);
00712 }
00713 return ret;
00714 }
00715
00716
00717 bool
00718 OptionsCont::isInStringVector(const std::string &optionName,
00719 const std::string &itemName) throw(InvalidArgument) {
00720 if (isSet(optionName)) {
00721 std::vector<std::string> values = getStringVector(optionName);
00722 return find(values.begin(), values.end(), itemName)!=values.end();
00723 }
00724 return false;
00725 }
00726
00727
00728