|
SUMO - Simulation of Urban MObility
|
00001 /****************************************************************************/ 00007 // A storage for options (typed value containers) 00008 /****************************************************************************/ 00009 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/ 00010 // Copyright (C) 2001-2011 DLR (http://www.dlr.de/) and contributors 00011 /****************************************************************************/ 00012 // 00013 // This program is free software; you can redistribute it and/or modify 00014 // it under the terms of the GNU General Public License as published by 00015 // the Free Software Foundation; either version 2 of the License, or 00016 // (at your option) any later version. 00017 // 00018 /****************************************************************************/ 00019 // =========================================================================== 00020 // included modules 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 <iterator> 00038 #include "Option.h" 00039 #include "OptionsCont.h" 00040 #include <utils/common/UtilExceptions.h> 00041 #include <utils/common/FileHelpers.h> 00042 #include <utils/common/MsgHandler.h> 00043 #include <utils/common/StringTokenizer.h> 00044 #include <utils/common/StringUtils.h> 00045 #include <sstream> 00046 00047 #ifdef CHECK_MEMORY_LEAKS 00048 #include <foreign/nvwa/debug_new.h> 00049 #endif // CHECK_MEMORY_LEAKS 00050 00051 00052 // =========================================================================== 00053 // static member definitions 00054 // =========================================================================== 00055 OptionsCont OptionsCont::myOptions; 00056 00057 00058 // =========================================================================== 00059 // method definitions 00060 // =========================================================================== 00061 OptionsCont& 00062 OptionsCont::getOptions() { 00063 return myOptions; 00064 } 00065 00066 00067 OptionsCont::OptionsCont() 00068 : myAddresses(), myValues(), myDeprecatedSynonymes(), myHaveInformedAboutDeprecatedDivider(false) { 00069 myCopyrightNotices.push_back("Copyright (C) 2001-2011 DLR and contributors; http://sumo.sourceforge.net"); 00070 } 00071 00072 00073 OptionsCont::~OptionsCont() { 00074 clear(); 00075 } 00076 00077 00078 void 00079 OptionsCont::doRegister(const std::string& name, Option* v) { 00080 assert(v!=0); 00081 ItemAddressContType::iterator i = find(myAddresses.begin(), myAddresses.end(), v); 00082 if (i==myAddresses.end()) { 00083 myAddresses.push_back(v); 00084 } 00085 if (myValues.find(name)!=myValues.end()) { 00086 throw ProcessError(name + " is an already used option name."); 00087 } 00088 myValues[name] = v; 00089 } 00090 00091 00092 void 00093 OptionsCont::doRegister(const std::string& name1, char abbr, Option* v) { 00094 doRegister(name1, v); 00095 doRegister(convertChar(abbr), v); 00096 } 00097 00098 00099 void 00100 OptionsCont::addSynonyme(const std::string& name1, const std::string& name2, bool isDeprecated) { 00101 KnownContType::iterator i1 = myValues.find(name1); 00102 KnownContType::iterator i2 = myValues.find(name2); 00103 if (i1==myValues.end()&&i2==myValues.end()) { 00104 throw ProcessError("Neither the option '" + name1 + "' nor the option '" + name2 + "' is known yet"); 00105 } 00106 if (i1!=myValues.end()&&i2!=myValues.end()) { 00107 if ((*i1).second==(*i2).second) { 00108 return; 00109 } 00110 throw ProcessError("Both options '" + name1 + "' and '" + name2 + "' do exist and differ."); 00111 } 00112 if (i1==myValues.end()&&i2!=myValues.end()) { 00113 doRegister(name1, (*i2).second); 00114 if (isDeprecated) { 00115 myDeprecatedSynonymes[name1] = false; 00116 } 00117 } 00118 if (i1!=myValues.end()&&i2==myValues.end()) { 00119 doRegister(name2, (*i1).second); 00120 if (isDeprecated) { 00121 myDeprecatedSynonymes[name2] = false; 00122 } 00123 } 00124 } 00125 00126 00127 bool 00128 OptionsCont::exists(const std::string& name) const { 00129 return myValues.count(name) > 0; 00130 } 00131 00132 00133 bool 00134 OptionsCont::isSet(const std::string& name, bool failOnNonExistant) const { 00135 KnownContType::const_iterator i = myValues.find(name); 00136 if (i==myValues.end()) { 00137 if (failOnNonExistant) { 00138 throw ProcessError("Internal request for unknown option '" + name + "'!"); 00139 } else { 00140 return false; 00141 } 00142 } 00143 return (*i).second->isSet(); 00144 } 00145 00146 00147 bool 00148 OptionsCont::isDefault(const std::string& name) const { 00149 KnownContType::const_iterator i = myValues.find(name); 00150 if (i==myValues.end()) { 00151 return false; 00152 } 00153 return (*i).second->isDefault(); 00154 } 00155 00156 00157 Option* 00158 OptionsCont::getSecure(const std::string& name) const { 00159 KnownContType::const_iterator k = myValues.find(name); 00160 if (k==myValues.end()) { 00161 throw ProcessError("No option with the name '" + name + "' exists."); 00162 } 00163 std::map<std::string, bool>::iterator s = myDeprecatedSynonymes.find(name); 00164 if (s != myDeprecatedSynonymes.end() && !s->second) { 00165 std::string defaultName; 00166 for (std::map<std::string, std::vector<std::string> >::const_iterator i=mySubTopicEntries.begin(); i!=mySubTopicEntries.end(); ++i) { 00167 for (std::vector<std::string>::const_iterator j=i->second.begin(); j!=i->second.end(); ++j) { 00168 KnownContType::const_iterator l = myValues.find(*j); 00169 if (l != myValues.end() && l->second == k->second) { 00170 defaultName = *j; 00171 break; 00172 } 00173 } 00174 if (defaultName != "") { 00175 break; 00176 } 00177 } 00178 WRITE_WARNING("Please note that '" + name + "' is deprecated.\n Use '" + defaultName + "' instead."); 00179 s->second = true; 00180 } 00181 return k->second; 00182 } 00183 00184 00185 std::string 00186 OptionsCont::getString(const std::string& name) const { 00187 Option* o = getSecure(name); 00188 return o->getString(); 00189 } 00190 00191 00192 SUMOReal 00193 OptionsCont::getFloat(const std::string& name) const { 00194 Option* o = getSecure(name); 00195 return o->getFloat(); 00196 } 00197 00198 00199 int 00200 OptionsCont::getInt(const std::string& name) const { 00201 Option* o = getSecure(name); 00202 return o->getInt(); 00203 } 00204 00205 00206 bool 00207 OptionsCont::getBool(const std::string& name) const { 00208 Option* o = getSecure(name); 00209 return o->getBool(); 00210 } 00211 00212 00213 const IntVector& 00214 OptionsCont::getIntVector(const std::string& name) const { 00215 Option* o = getSecure(name); 00216 return o->getIntVector(); 00217 } 00218 00219 00220 bool 00221 OptionsCont::set(const std::string& name, const std::string& value) { 00222 Option* o = getSecure(name); 00223 if (!o->isWriteable()) { 00224 reportDoubleSetting(name); 00225 return false; 00226 } 00227 try { 00228 if (!o->set(value)) { 00229 return false; 00230 } 00231 } catch (ProcessError& e) { 00232 WRITE_ERROR("While processing option '" + name + "':\n " + e.what()); 00233 return false; 00234 } 00235 return true; 00236 } 00237 00238 00239 std::vector<std::string> 00240 OptionsCont::getSynonymes(const std::string& name) const { 00241 Option* o = getSecure(name); 00242 std::vector<std::string> v(0); 00243 for (KnownContType::const_iterator i=myValues.begin(); i!=myValues.end(); i++) { 00244 if ((*i).second==o&&name!=(*i).first) { 00245 v.push_back((*i).first); 00246 } 00247 } 00248 return v; 00249 } 00250 00251 00252 std::ostream& 00253 operator<<(std::ostream& os, const OptionsCont& oc) { 00254 std::vector<std::string> done; 00255 os << "Options set:" << std::endl; 00256 for (OptionsCont::KnownContType::const_iterator i=oc.myValues.begin(); 00257 i!=oc.myValues.end(); i++) { 00258 std::vector<std::string>::iterator j = find(done.begin(), done.end(), (*i).first); 00259 if (j==done.end()) { 00260 std::vector<std::string> synonymes = oc.getSynonymes((*i).first); 00261 if (synonymes.size()!=0) { 00262 os << (*i).first << " ("; 00263 for (j=synonymes.begin(); j!=synonymes.end(); j++) { 00264 if (j!=synonymes.begin()) { 00265 os << ", "; 00266 } 00267 os << (*j); 00268 } 00269 os << ")"; 00270 } else { 00271 os << (*i).first; 00272 } 00273 if ((*i).second->isSet()) { 00274 os << ": " << (*i).second->getValueString() << std::endl; 00275 } else { 00276 os << ": <INVALID>" << std::endl; 00277 } 00278 done.push_back((*i).first); 00279 copy(synonymes.begin(), synonymes.end(), back_inserter(done)); 00280 } 00281 } 00282 return os; 00283 } 00284 00285 00286 void 00287 OptionsCont::relocateFiles(const std::string& configuration) const { 00288 for (ItemAddressContType::const_iterator i=myAddresses.begin(); i!=myAddresses.end(); i++) { 00289 if ((*i)->isFileName() && (*i)->isSet()) { 00290 StringTokenizer st((*i)->getString(), ";, ", true); 00291 std::string conv; 00292 while (st.hasNext()) { 00293 if (conv.length()!=0) { 00294 conv += ','; 00295 } 00296 std::string tmp = st.next(); 00297 if (!FileHelpers::isAbsolute(tmp)) { 00298 tmp = FileHelpers::getConfigurationRelative(configuration, tmp); 00299 } 00300 conv += tmp; 00301 } 00302 (*i)->set(conv); 00303 } 00304 } 00305 } 00306 00307 00308 bool 00309 OptionsCont::isUsableFileList(const std::string& name) const { 00310 Option* o = getSecure(name); 00311 // check whether the option is set 00312 // return false i not 00313 if (!o->isSet()) { 00314 return false; 00315 } 00316 // check whether the list of files is valid 00317 bool ok = true; 00318 std::vector<std::string> files = getStringVector(name); 00319 if (files.size()==0) { 00320 WRITE_ERROR("The file list for '" + name + "' is empty."); 00321 ok = false; 00322 } 00323 for (std::vector<std::string>::const_iterator fileIt=files.begin(); fileIt!=files.end(); ++fileIt) { 00324 if (!FileHelpers::exists(*fileIt)) { 00325 if (*fileIt!="") { 00326 WRITE_ERROR("File '" + *fileIt + "' does not exist."); 00327 ok = false; 00328 } else { 00329 WRITE_WARNING("Empty file name given; ignoring."); 00330 } 00331 } 00332 } 00333 return ok; 00334 } 00335 00336 00337 bool 00338 OptionsCont::checkDependingSuboptions(const std::string& name, const std::string& prefix) const { 00339 Option* o = getSecure(name); 00340 if (o->isSet()) { 00341 return true; 00342 } 00343 bool ok = true; 00344 std::vector<std::string> seenSynonymes; 00345 for (KnownContType::const_iterator i=myValues.begin(); i!=myValues.end(); i++) { 00346 if (std::find(seenSynonymes.begin(), seenSynonymes.end(), (*i).first)!=seenSynonymes.end()) { 00347 continue; 00348 } 00349 if ((*i).second->isSet() && !(*i).second->isDefault() && (*i).first.find(prefix) == 0) { 00350 WRITE_ERROR("Option '" + (*i).first + "' needs option '" + name + "'."); 00351 std::vector<std::string> synonymes = getSynonymes((*i).first); 00352 std::copy(synonymes.begin(), synonymes.end(), std::back_inserter(seenSynonymes)); 00353 ok = false; 00354 } 00355 } 00356 return ok; 00357 } 00358 00359 00360 void 00361 OptionsCont::reportDoubleSetting(const std::string& arg) const { 00362 std::vector<std::string> synonymes = getSynonymes(arg); 00363 std::ostringstream s; 00364 s << "A value for the option '" + arg + "' was already set.\n Possible synonymes: "; 00365 for (std::vector<std::string>::iterator i=synonymes.begin(); i!=synonymes.end();) { 00366 s << (*i); 00367 i++; 00368 if (i!=synonymes.end()) { 00369 s << ", "; 00370 } 00371 } 00372 WRITE_ERROR(s.str()); 00373 } 00374 00375 00376 std::string 00377 OptionsCont::convertChar(char abbr) const { 00378 char buf[2]; 00379 buf[0] = abbr; 00380 buf[1] = 0; 00381 std::string s(buf); 00382 return s; 00383 } 00384 00385 00386 bool 00387 OptionsCont::isBool(const std::string& name) const { 00388 Option* o = getSecure(name); 00389 return o->isBool(); 00390 } 00391 00392 00393 void 00394 OptionsCont::resetWritable() { 00395 for (ItemAddressContType::iterator i=myAddresses.begin(); i!=myAddresses.end(); i++) { 00396 (*i)->resetWritable(); 00397 } 00398 } 00399 00400 00401 bool 00402 OptionsCont::isWriteable(const std::string& name) { 00403 Option* o = getSecure(name); 00404 return o->isWriteable(); 00405 } 00406 00407 00408 void 00409 OptionsCont::clear() { 00410 ItemAddressContType::iterator i; 00411 for (i=myAddresses.begin(); i!=myAddresses.end(); i++) { 00412 delete(*i); 00413 } 00414 myAddresses.clear(); 00415 myValues.clear(); 00416 mySubTopics.clear(); 00417 mySubTopicEntries.clear(); 00418 } 00419 00420 00421 void 00422 OptionsCont::addDescription(const std::string& name, 00423 const std::string& subtopic, 00424 const std::string& description) { 00425 Option* o = getSecure(name); 00426 assert(o!=0); 00427 assert(find(mySubTopics.begin(), mySubTopics.end(), subtopic)!=mySubTopics.end()); 00428 o->setDescription(description); 00429 mySubTopicEntries[subtopic].push_back(name); 00430 } 00431 00432 00433 void 00434 OptionsCont::setApplicationName(const std::string& appName, 00435 const std::string& fullName) { 00436 myAppName = appName; 00437 myFullName = fullName; 00438 } 00439 00440 00441 void 00442 OptionsCont::setApplicationDescription(const std::string& appDesc) { 00443 myAppDescription = appDesc; 00444 } 00445 00446 00447 void 00448 OptionsCont::addCallExample(const std::string& example) { 00449 myCallExamples.push_back(example); 00450 } 00451 00452 00453 void 00454 OptionsCont::setAdditionalHelpMessage(const std::string& add) { 00455 myAdditionalMessage = add; 00456 } 00457 00458 00459 void 00460 OptionsCont::addCopyrightNotice(const std::string& copyrightLine) { 00461 myCopyrightNotices.push_back(copyrightLine); 00462 } 00463 00464 00465 void 00466 OptionsCont::clearCopyrightNotices() { 00467 myCopyrightNotices.clear(); 00468 } 00469 00470 00471 void 00472 OptionsCont::addOptionSubTopic(const std::string& topic) { 00473 mySubTopics.push_back(topic); 00474 mySubTopicEntries[topic] = std::vector<std::string>(); 00475 } 00476 00477 00478 void 00479 OptionsCont::splitLines(std::ostream& os, std::string what, 00480 size_t offset, size_t nextOffset) { 00481 while (what.length()>0) { 00482 if (what.length()>79-offset) { 00483 size_t splitPos = what.rfind(';', 79-offset); 00484 if (splitPos==std::string::npos) { 00485 splitPos = what.rfind(' ', 79-offset); 00486 } else { 00487 splitPos++; 00488 } 00489 if (splitPos!=std::string::npos) { 00490 os << what.substr(0, splitPos) << std::endl; 00491 what = what.substr(splitPos); 00492 for (size_t r=0; r<nextOffset+1; ++r) { 00493 os << ' '; 00494 } 00495 } else { 00496 os << what; 00497 what = ""; 00498 } 00499 offset = nextOffset; 00500 } else { 00501 os << what; 00502 what = ""; 00503 } 00504 } 00505 os << std::endl; 00506 } 00507 00508 00509 bool 00510 OptionsCont::processMetaOptions(bool missingOptions) throw(ProcessError) { 00511 if (missingOptions) { 00512 // no options are given 00513 std::cout << myFullName << std::endl; 00514 for (std::vector<std::string>::const_iterator it = 00515 myCopyrightNotices.begin(); it != myCopyrightNotices.end(); ++it) { 00516 std::cout << " " << *it << std::endl; 00517 } 00518 std::cout << " License GPLv3+: GNU GPL Version 3 or later <http://gnu.org/licenses/gpl.html>\n"; 00519 std::cout << " Use --help to get the list of options." << std::endl; 00520 return true; 00521 } 00522 00523 // check whether the help shall be printed 00524 if (getBool("help")) { 00525 std::cout << myFullName << std::endl; 00526 for (std::vector<std::string>::const_iterator it = 00527 myCopyrightNotices.begin(); it != myCopyrightNotices.end(); ++it) { 00528 std::cout << " " << *it << std::endl; 00529 } 00530 printHelp(std::cout); 00531 return true; 00532 } 00533 // check whether the help shall be printed 00534 if (getBool("version")) { 00535 std::cout << myFullName << std::endl; 00536 for (std::vector<std::string>::const_iterator it = 00537 myCopyrightNotices.begin(); it != myCopyrightNotices.end(); ++it) { 00538 std::cout << " " << *it << std::endl; 00539 } 00540 std::cout << "\nThis program is free software; you can redistribute it and/or modify\n"; 00541 std::cout << "it under the terms of the GNU General Public License as published by\n"; 00542 std::cout << "the Free Software Foundation; either version 3 of the License, or\n"; 00543 std::cout << "(at your option) any later version.\n\n"; 00544 std::cout << "This program is distributed in the hope that it will be useful,\n"; 00545 std::cout << "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"; 00546 std::cout << "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"; 00547 std::cout << "GNU General Public License for more details.\n\n"; 00548 std::cout << "You should have received a copy of the GNU General Public License\n"; 00549 std::cout << "along with this program. If not, see http://www.gnu.org/licenses/gpl.html" << std::endl; 00550 return true; 00551 } 00552 // check whether the settings shall be printed 00553 if (exists("print-options") && getBool("print-options")) { 00554 std::cout << (*this); 00555 } 00556 // check whether something has to be done with options 00557 // whether the current options shall be saved 00558 if (isSet("save-configuration", false)) { // sumo-gui does not register these 00559 if (getString("save-configuration") == "-" || getString("save-configuration") == "stdout") { 00560 writeConfiguration(std::cout, true, false, getBool("save-commented")); 00561 return true; 00562 } 00563 std::ofstream out(getString("save-configuration").c_str()); 00564 if (!out.good()) { 00565 throw ProcessError("Could not save configuration to '" + getString("save-configuration") + "'"); 00566 } else { 00567 writeConfiguration(out, true, false, getBool("save-commented")); 00568 if (getBool("verbose")) { 00569 WRITE_MESSAGE("Written configuration to '" + getString("save-configuration") + "'"); 00570 } 00571 return true; 00572 } 00573 } 00574 // whether the template shall be saved 00575 if (isSet("save-template", false)) { // sumo-gui does not register these 00576 if (getString("save-template") == "-" || getString("save-template") == "stdout") { 00577 writeConfiguration(std::cout, false, true, getBool("save-commented")); 00578 return true; 00579 } 00580 std::ofstream out(getString("save-template").c_str()); 00581 if (!out.good()) { 00582 throw ProcessError("Could not save template to '" + getString("save-template") + "'"); 00583 } else { 00584 writeConfiguration(out, false, true, getBool("save-commented")); 00585 if (getBool("verbose")) { 00586 WRITE_MESSAGE("Written template to '" + getString("save-template") + "'"); 00587 } 00588 return true; 00589 } 00590 } 00591 if (isSet("save-schema", false)) { // sumo-gui does not register these 00592 if (getString("save-schema") == "-" || getString("save-schema") == "stdout") { 00593 writeSchema(std::cout, getBool("save-commented")); 00594 return true; 00595 } 00596 std::ofstream out(getString("save-schema").c_str()); 00597 if (!out.good()) { 00598 throw ProcessError("Could not save schema to '" + getString("save-schema") + "'"); 00599 } else { 00600 writeSchema(out, getBool("save-commented")); 00601 if (getBool("verbose")) { 00602 WRITE_MESSAGE("Written schema to '" + getString("save-schema") + "'"); 00603 } 00604 return true; 00605 } 00606 } 00607 return false; 00608 } 00609 00610 void 00611 OptionsCont::printHelp(std::ostream& os) { 00612 std::vector<std::string>::const_iterator i, j; 00613 //#define WIKI_OUTPUT 1 00614 #ifdef WIKI_OUTPUT 00615 for (i=mySubTopics.begin(); i!=mySubTopics.end(); ++i) { 00616 os << "===" << (*i) << "===\n"; 00617 os << "{| cellspacing=\"0\" border=\"1\" width=\"90%\" align=\"center\"\n"; 00618 os << "|-\n"; 00619 os << "! style=\"background:#ddffdd;\" valign=\"top\" | Option\n"; 00620 os << "! style=\"background:#ddffdd;\" valign=\"top\" | Default Value\n"; 00621 os << "! style=\"background:#ddffdd;\" valign=\"top\" | Description\n"; 00622 const std::vector<std::string> &entries = mySubTopicEntries[*i]; 00623 for (j=entries.begin(); j!=entries.end(); ++j) { 00624 // start length computation 00625 size_t csize = (*j).length() + 2; 00626 Option* o = getSecure(*j); 00627 os << "|-\n"; 00628 os << "| valign=\"top\" | "; 00629 // write abbreviation if given 00630 std::vector<std::string> synonymes = getSynonymes(*j); 00631 std::vector<std::string>::iterator a = find_if(synonymes.begin(), synonymes.end(), abbreviation_finder()); 00632 std::string outputType = o->getTypeName(); 00633 if (a!=synonymes.end()) { 00634 os << "{{Option|-" << (*a) << " {{DT_" << outputType << "}}}}<br/>"; 00635 } 00636 // write the name 00637 os << "{{Option|--" << *j << " {{DT_" << outputType << "}}}}\n"; 00638 std::string defaultValue = o->isSet() ? o->getValueString() : ""; 00639 os << "| valign=\"top\" | " << defaultValue << "\n"; 00640 os << "| valign=\"top\" | " << o->getDescription() << "\n"; 00641 } 00642 os << "|-\n"; 00643 os << "|}\n\n"; 00644 } 00645 return; 00646 #endif 00647 // print application description 00648 os << ' ' << std::endl; 00649 splitLines(os, myAppDescription, 0, 0); 00650 os << std::endl; 00651 // print usage BNF 00652 os << "Usage: " << myAppName << " [OPTION]*" << std::endl; 00653 os << ' ' << std::endl; 00654 // print usage examples 00655 if (myCallExamples.size()>1) { 00656 os << " Examples:" << std::endl; 00657 } else if (myCallExamples.size()!=0) { 00658 os << " Example:" << std::endl; 00659 } 00660 if (myCallExamples.size()!=0) { 00661 for (i=myCallExamples.begin(); i!=myCallExamples.end(); ++i) { 00662 os << " " << myAppName << ' ' << (*i) << std::endl; 00663 } 00664 } 00665 os << ' ' << std::endl; 00666 // print additional text if any 00667 if (myAdditionalMessage.length()>0) { 00668 os << myAdditionalMessage << std::endl << ' ' << std::endl; 00669 } 00670 // print the options 00671 // check their sizes first 00672 // we want to know how large the largest not-too-large-entry will be 00673 size_t tooLarge = 40; 00674 size_t maxSize = 0; 00675 for (i=mySubTopics.begin(); i!=mySubTopics.end(); ++i) { 00676 const std::vector<std::string> &entries = mySubTopicEntries[*i]; 00677 for (j=entries.begin(); j!=entries.end(); ++j) { 00678 Option* o = getSecure(*j); 00679 // name, two leading spaces and "--" 00680 size_t csize = (*j).length() + 2 + 4; 00681 // abbreviation length ("-X, "->4chars) if any 00682 std::vector<std::string> synonymes = getSynonymes(*j); 00683 if (find_if(synonymes.begin(), synonymes.end(), abbreviation_finder())!=synonymes.end()) { 00684 csize += 4; 00685 } 00686 // the type name 00687 if (!o->isBool()) { 00688 csize += 1 + o->getTypeName().length(); 00689 } 00690 // divider 00691 csize += 2; 00692 if (csize<tooLarge&&maxSize<csize) { 00693 maxSize = csize; 00694 } 00695 } 00696 } 00697 00698 for (i=mySubTopics.begin(); i!=mySubTopics.end(); ++i) { 00699 os << ' ' << *i << " Options:" << std::endl; 00700 const std::vector<std::string> &entries = mySubTopicEntries[*i]; 00701 for (j=entries.begin(); j!=entries.end(); ++j) { 00702 // start length computation 00703 size_t csize = (*j).length() + 2; 00704 Option* o = getSecure(*j); 00705 os << " "; 00706 // write abbreviation if given 00707 std::vector<std::string> synonymes = getSynonymes(*j); 00708 std::vector<std::string>::iterator a = find_if(synonymes.begin(), synonymes.end(), abbreviation_finder()); 00709 if (a!=synonymes.end()) { 00710 os << '-' << (*a) << ", "; 00711 csize += 4; 00712 } 00713 // write leading '-'/"--" 00714 os << "--"; 00715 csize += 2; 00716 // write the name 00717 os << *j; 00718 // write the type if not a bool option 00719 if (!o->isBool()) { 00720 os << ' ' << o->getTypeName(); 00721 csize += 1 + o->getTypeName().length(); 00722 } 00723 csize += 2; 00724 // write the description formatting it 00725 os << " "; 00726 size_t r; 00727 for (r=maxSize; r>csize; --r) { 00728 os << ' '; 00729 } 00730 std::string desc = o->getDescription(); 00731 size_t offset = csize > tooLarge ? csize : maxSize; 00732 splitLines(os, desc, offset, maxSize); 00733 } 00734 os << std::endl; 00735 } 00736 } 00737 00738 00739 void 00740 OptionsCont::writeConfiguration(std::ostream& os, bool filled, 00741 bool complete, bool addComments) { 00742 // to the best of our knowledge files are written in latin-1 on windows and linux 00743 os << "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n\n"; 00744 os << "<configuration xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://sumo.sf.net/xsd/" << myAppName << "Configuration.xsd\">" << std::endl << std::endl; 00745 for (std::vector<std::string>::const_iterator i=mySubTopics.begin(); i!=mySubTopics.end(); ++i) { 00746 std::string subtopic = *i; 00747 if (subtopic=="Configuration") { 00748 continue; 00749 } 00750 std::replace(subtopic.begin(), subtopic.end(), ' ', '_'); 00751 std::transform(subtopic.begin(), subtopic.end(), subtopic.begin(), tolower); 00752 const std::vector<std::string> &entries = mySubTopicEntries[*i]; 00753 bool hadOne = false; 00754 for (std::vector<std::string>::const_iterator j=entries.begin(); j!=entries.end(); ++j) { 00755 Option* o = getSecure(*j); 00756 bool write = complete || (filled&&!o->isDefault()); 00757 if (!write) { 00758 continue; 00759 } 00760 if (!hadOne) { 00761 os << " <" << subtopic << ">" << std::endl; 00762 } 00763 // add the comment if wished 00764 if (addComments) { 00765 os << " <!-- " << o->getDescription() << " -->" << std::endl; 00766 } 00767 // write the option and the value (if given) 00768 os << " <" << *j << " value=\""; 00769 if (o->isSet()) { 00770 os << o->getValueString(); 00771 } 00772 if (complete) { 00773 std::vector<std::string> synonymes = getSynonymes(*j); 00774 if (!synonymes.empty()) { 00775 os << "\" synonymes=\""; 00776 for (std::vector<std::string>::const_iterator s=synonymes.begin(); s!=synonymes.end(); ++s) { 00777 if (s != synonymes.begin()) { 00778 os << " "; 00779 } 00780 os << (*s); 00781 } 00782 } 00783 os << "\" type=\"" << o->getTypeName(); 00784 if (!addComments) { 00785 os << "\" help=\"" << o->getDescription(); 00786 } 00787 } 00788 os << "\"/>" << std::endl; 00789 // append an endline if a comment was printed 00790 if (addComments) { 00791 os << std::endl; 00792 } 00793 hadOne = true; 00794 } 00795 if (hadOne) { 00796 os << " </" << subtopic << ">" << std::endl << std::endl; 00797 } 00798 } 00799 os << "</configuration>" << std::endl; 00800 } 00801 00802 00803 void 00804 OptionsCont::writeSchema(std::ostream& os, bool addComments) { 00805 // to the best of our knowledge files are written in latin-1 on windows and linux 00806 os << "<?xml version=\"1.0\" encoding=\"iso-8859-1\"?>\n\n"; 00807 os << "<xsd:schema elementFormDefault=\"qualified\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n\n"; 00808 os << " <xsd:element name=\"configuration\" type=\"configurationType\"/>\n\n"; 00809 os << " <xsd:complexType name=\"configurationType\">\n"; 00810 os << " <xsd:sequence>\n"; 00811 for (std::vector<std::string>::const_iterator i=mySubTopics.begin(); i!=mySubTopics.end(); ++i) { 00812 std::string subtopic = *i; 00813 if (subtopic=="Configuration") { 00814 continue; 00815 } 00816 std::replace(subtopic.begin(), subtopic.end(), ' ', '_'); 00817 std::transform(subtopic.begin(), subtopic.end(), subtopic.begin(), tolower); 00818 os << " <xsd:element name=\"" << subtopic << "\" type=\"" << subtopic << "Type\" minOccurs=\"0\" maxOccurs=\"1\"/>\n"; 00819 } 00820 os << " </xsd:sequence>\n"; 00821 os << " </xsd:complexType>\n\n"; 00822 for (std::vector<std::string>::const_iterator i=mySubTopics.begin(); i!=mySubTopics.end(); ++i) { 00823 std::string subtopic = *i; 00824 if (subtopic=="Configuration") { 00825 continue; 00826 } 00827 std::replace(subtopic.begin(), subtopic.end(), ' ', '_'); 00828 std::transform(subtopic.begin(), subtopic.end(), subtopic.begin(), tolower); 00829 os << " <xsd:complexType name=\"" << subtopic << "Type\">\n"; 00830 os << " <xsd:sequence>\n"; 00831 const std::vector<std::string> &entries = mySubTopicEntries[*i]; 00832 for (std::vector<std::string>::const_iterator j=entries.begin(); j!=entries.end(); ++j) { 00833 os << " <xsd:element name=\"" << *j << "\" type=\"" << *j << "Type\" minOccurs=\"0\" maxOccurs=\"1\"/>\n"; 00834 } 00835 os << " </xsd:sequence>\n"; 00836 os << " </xsd:complexType>\n\n"; 00837 for (std::vector<std::string>::const_iterator j=entries.begin(); j!=entries.end(); ++j) { 00838 Option* o = getSecure(*j); 00839 std::string type = o->getTypeName(); 00840 std::transform(type.begin(), type.end(), type.begin(), tolower); 00841 if (type == "bool") { 00842 type = "boolean"; 00843 } else { 00844 if (type != "int" && type != "float") { 00845 type = "string"; 00846 } 00847 } 00848 os << " <xsd:complexType name=\"" << *j << "Type\">\n"; 00849 if (addComments) { 00850 os << " <!-- " << o->getDescription() << " -->\n"; 00851 } 00852 os << " <xsd:attribute name=\"value\" type=\"xsd:" << type << "\" use=\"required\"/>\n"; 00853 os << " <xsd:attribute name=\"synonymes\" type=\"xsd:string\" use=\"optional\"/>\n"; 00854 os << " <xsd:attribute name=\"type\" type=\"xsd:string\" use=\"optional\"/>\n"; 00855 os << " <xsd:attribute name=\"help\" type=\"xsd:string\" use=\"optional\"/>\n"; 00856 os << " </xsd:complexType>\n\n"; 00857 } 00858 } 00859 os << "</xsd:schema>\n"; 00860 } 00861 00862 00863 void 00864 OptionsCont::writeXMLHeader(std::ostream& os, const std::string xmlParams) { 00865 time_t rawtime; 00866 char buffer [80]; 00867 00868 os << "<?xml version=\"1.0\"" << xmlParams << "?>\n\n"; 00869 time(&rawtime); 00870 strftime(buffer, 80, "<!-- generated on %c by ", localtime(&rawtime)); 00871 os << buffer << myFullName << "\n"; 00872 writeConfiguration(os, true, false, false); 00873 os << "-->\n\n"; 00874 } 00875 00876 00877 std::vector<std::string> 00878 OptionsCont::getStringVector(const std::string& name) const { 00879 Option* o = getSecure(name); 00880 std::string def = o->getString(); 00881 if (def.find(';')!=std::string::npos&&!myHaveInformedAboutDeprecatedDivider) { 00882 WRITE_WARNING("Please note that using ';' as list separator is deprecated.\n From 1.0 onwards, only ',' will be accepted."); 00883 myHaveInformedAboutDeprecatedDivider = true; 00884 } 00885 StringTokenizer st(def, ";,", true); 00886 std::vector<std::string> ret = st.getVector(); 00887 for (std::vector<std::string>::iterator i=ret.begin(); i!=ret.end(); ++i) { 00888 (*i) = StringUtils::prune(*i); 00889 } 00890 return ret; 00891 } 00892 00893 00894 bool 00895 OptionsCont::isInStringVector(const std::string& optionName, 00896 const std::string& itemName) { 00897 if (isSet(optionName)) { 00898 std::vector<std::string> values = getStringVector(optionName); 00899 return find(values.begin(), values.end(), itemName)!=values.end(); 00900 } 00901 return false; 00902 } 00903 00904 00905 /****************************************************************************/