SUMO - Simulation of Urban MObility
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
OptionsCont.cpp
Go to the documentation of this file.
1 /****************************************************************************/
10 // A storage for options (typed value containers)
11 /****************************************************************************/
12 // SUMO, Simulation of Urban MObility; see http://sumo.sourceforge.net/
13 // Copyright (C) 2001-2012 DLR (http://www.dlr.de/) and contributors
14 /****************************************************************************/
15 //
16 // This file is part of SUMO.
17 // SUMO is free software: you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation, either version 3 of the License, or
20 // (at your option) any later version.
21 //
22 /****************************************************************************/
23 // ===========================================================================
24 // included modules
25 // ===========================================================================
26 #ifdef _MSC_VER
27 #include <windows_config.h>
28 #else
29 #include <config.h>
30 #endif
31 
32 #include <map>
33 #include <string>
34 #include <exception>
35 #include <algorithm>
36 #include <vector>
37 #include <iostream>
38 #include <cstdlib>
39 #include <cassert>
40 #include <ctime>
41 #include <iterator>
42 #include "Option.h"
43 #include "OptionsCont.h"
50 #include <sstream>
51 
52 #ifdef CHECK_MEMORY_LEAKS
53 #include <foreign/nvwa/debug_new.h>
54 #endif // CHECK_MEMORY_LEAKS
55 
56 
57 // ===========================================================================
58 // static member definitions
59 // ===========================================================================
61 
62 
63 // ===========================================================================
64 // method definitions
65 // ===========================================================================
68  return myOptions;
69 }
70 
71 
73  : myAddresses(), myValues(), myDeprecatedSynonymes(), myHaveInformedAboutDeprecatedDivider(false) {
74  myCopyrightNotices.push_back("Copyright (C) 2001-2012 DLR and contributors; http://sumo.sourceforge.net");
75 }
76 
77 
79  clear();
80 }
81 
82 
83 void
84 OptionsCont::doRegister(const std::string& name, Option* v) {
85  assert(v != 0);
86  ItemAddressContType::iterator i = find(myAddresses.begin(), myAddresses.end(), v);
87  if (i == myAddresses.end()) {
88  myAddresses.push_back(v);
89  }
90  if (myValues.find(name) != myValues.end()) {
91  throw ProcessError(name + " is an already used option name.");
92  }
93  myValues[name] = v;
94 }
95 
96 
97 void
98 OptionsCont::doRegister(const std::string& name1, char abbr, Option* v) {
99  doRegister(name1, v);
100  doRegister(convertChar(abbr), v);
101 }
102 
103 
104 void
105 OptionsCont::addSynonyme(const std::string& name1, const std::string& name2, bool isDeprecated) {
106  KnownContType::iterator i1 = myValues.find(name1);
107  KnownContType::iterator i2 = myValues.find(name2);
108  if (i1 == myValues.end() && i2 == myValues.end()) {
109  throw ProcessError("Neither the option '" + name1 + "' nor the option '" + name2 + "' is known yet");
110  }
111  if (i1 != myValues.end() && i2 != myValues.end()) {
112  if ((*i1).second == (*i2).second) {
113  return;
114  }
115  throw ProcessError("Both options '" + name1 + "' and '" + name2 + "' do exist and differ.");
116  }
117  if (i1 == myValues.end() && i2 != myValues.end()) {
118  doRegister(name1, (*i2).second);
119  if (isDeprecated) {
120  myDeprecatedSynonymes[name1] = false;
121  }
122  }
123  if (i1 != myValues.end() && i2 == myValues.end()) {
124  doRegister(name2, (*i1).second);
125  if (isDeprecated) {
126  myDeprecatedSynonymes[name2] = false;
127  }
128  }
129 }
130 
131 
132 bool
133 OptionsCont::exists(const std::string& name) const {
134  return myValues.count(name) > 0;
135 }
136 
137 
138 bool
139 OptionsCont::isSet(const std::string& name, bool failOnNonExistant) const {
140  KnownContType::const_iterator i = myValues.find(name);
141  if (i == myValues.end()) {
142  if (failOnNonExistant) {
143  throw ProcessError("Internal request for unknown option '" + name + "'!");
144  } else {
145  return false;
146  }
147  }
148  return (*i).second->isSet();
149 }
150 
151 
152 bool
153 OptionsCont::isDefault(const std::string& name) const {
154  KnownContType::const_iterator i = myValues.find(name);
155  if (i == myValues.end()) {
156  return false;
157  }
158  return (*i).second->isDefault();
159 }
160 
161 
162 Option*
163 OptionsCont::getSecure(const std::string& name) const {
164  KnownContType::const_iterator k = myValues.find(name);
165  if (k == myValues.end()) {
166  throw ProcessError("No option with the name '" + name + "' exists.");
167  }
168  std::map<std::string, bool>::iterator s = myDeprecatedSynonymes.find(name);
169  if (s != myDeprecatedSynonymes.end() && !s->second) {
170  std::string defaultName;
171  for (std::map<std::string, std::vector<std::string> >::const_iterator i = mySubTopicEntries.begin(); i != mySubTopicEntries.end(); ++i) {
172  for (std::vector<std::string>::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
173  KnownContType::const_iterator l = myValues.find(*j);
174  if (l != myValues.end() && l->second == k->second) {
175  defaultName = *j;
176  break;
177  }
178  }
179  if (defaultName != "") {
180  break;
181  }
182  }
183  WRITE_WARNING("Please note that '" + name + "' is deprecated.\n Use '" + defaultName + "' instead.");
184  s->second = true;
185  }
186  return k->second;
187 }
188 
189 
190 std::string
191 OptionsCont::getString(const std::string& name) const {
192  Option* o = getSecure(name);
193  return o->getString();
194 }
195 
196 
197 SUMOReal
198 OptionsCont::getFloat(const std::string& name) const {
199  Option* o = getSecure(name);
200  return o->getFloat();
201 }
202 
203 
204 int
205 OptionsCont::getInt(const std::string& name) const {
206  Option* o = getSecure(name);
207  return o->getInt();
208 }
209 
210 
211 bool
212 OptionsCont::getBool(const std::string& name) const {
213  Option* o = getSecure(name);
214  return o->getBool();
215 }
216 
217 
218 const IntVector&
219 OptionsCont::getIntVector(const std::string& name) const {
220  Option* o = getSecure(name);
221  return o->getIntVector();
222 }
223 
224 
225 bool
226 OptionsCont::set(const std::string& name, const std::string& value) {
227  Option* o = getSecure(name);
228  if (!o->isWriteable()) {
229  reportDoubleSetting(name);
230  return false;
231  }
232  try {
233  if (!o->set(value)) {
234  return false;
235  }
236  } catch (ProcessError& e) {
237  WRITE_ERROR("While processing option '" + name + "':\n " + e.what());
238  return false;
239  }
240  return true;
241 }
242 
243 
244 std::vector<std::string>
245 OptionsCont::getSynonymes(const std::string& name) const {
246  Option* o = getSecure(name);
247  std::vector<std::string> v(0);
248  for (KnownContType::const_iterator i = myValues.begin(); i != myValues.end(); i++) {
249  if ((*i).second == o && name != (*i).first) {
250  v.push_back((*i).first);
251  }
252  }
253  return v;
254 }
255 
256 
257 std::ostream&
258 operator<<(std::ostream& os, const OptionsCont& oc) {
259  std::vector<std::string> done;
260  os << "Options set:" << std::endl;
261  for (OptionsCont::KnownContType::const_iterator i = oc.myValues.begin();
262  i != oc.myValues.end(); i++) {
263  std::vector<std::string>::iterator j = find(done.begin(), done.end(), (*i).first);
264  if (j == done.end()) {
265  std::vector<std::string> synonymes = oc.getSynonymes((*i).first);
266  if (synonymes.size() != 0) {
267  os << (*i).first << " (";
268  for (j = synonymes.begin(); j != synonymes.end(); j++) {
269  if (j != synonymes.begin()) {
270  os << ", ";
271  }
272  os << (*j);
273  }
274  os << ")";
275  } else {
276  os << (*i).first;
277  }
278  if ((*i).second->isSet()) {
279  os << ": " << (*i).second->getValueString() << std::endl;
280  } else {
281  os << ": <INVALID>" << std::endl;
282  }
283  done.push_back((*i).first);
284  copy(synonymes.begin(), synonymes.end(), back_inserter(done));
285  }
286  }
287  return os;
288 }
289 
290 
291 void
292 OptionsCont::relocateFiles(const std::string& configuration) const {
293  for (ItemAddressContType::const_iterator i = myAddresses.begin(); i != myAddresses.end(); i++) {
294  if ((*i)->isFileName() && (*i)->isSet()) {
295  StringTokenizer st((*i)->getString(), ";, ", true);
296  std::string conv;
297  while (st.hasNext()) {
298  if (conv.length() != 0) {
299  conv += ',';
300  }
301  std::string tmp = st.next();
302  if (!FileHelpers::isAbsolute(tmp)) {
303  tmp = FileHelpers::getConfigurationRelative(configuration, tmp);
304  }
305  conv += tmp;
306  }
307  (*i)->set(conv);
308  }
309  }
310 }
311 
312 
313 bool
314 OptionsCont::isUsableFileList(const std::string& name) const {
315  Option* o = getSecure(name);
316  // check whether the option is set
317  // return false i not
318  if (!o->isSet()) {
319  return false;
320  }
321  // check whether the list of files is valid
322  bool ok = true;
323  std::vector<std::string> files = getStringVector(name);
324  if (files.size() == 0) {
325  WRITE_ERROR("The file list for '" + name + "' is empty.");
326  ok = false;
327  }
328  for (std::vector<std::string>::const_iterator fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
329  if (!FileHelpers::exists(*fileIt)) {
330  if (*fileIt != "") {
331  WRITE_ERROR("File '" + *fileIt + "' does not exist.");
332  ok = false;
333  } else {
334  WRITE_WARNING("Empty file name given; ignoring.");
335  }
336  }
337  }
338  return ok;
339 }
340 
341 
342 bool
343 OptionsCont::checkDependingSuboptions(const std::string& name, const std::string& prefix) const {
344  Option* o = getSecure(name);
345  if (o->isSet()) {
346  return true;
347  }
348  bool ok = true;
349  std::vector<std::string> seenSynonymes;
350  for (KnownContType::const_iterator i = myValues.begin(); i != myValues.end(); i++) {
351  if (std::find(seenSynonymes.begin(), seenSynonymes.end(), (*i).first) != seenSynonymes.end()) {
352  continue;
353  }
354  if ((*i).second->isSet() && !(*i).second->isDefault() && (*i).first.find(prefix) == 0) {
355  WRITE_ERROR("Option '" + (*i).first + "' needs option '" + name + "'.");
356  std::vector<std::string> synonymes = getSynonymes((*i).first);
357  std::copy(synonymes.begin(), synonymes.end(), std::back_inserter(seenSynonymes));
358  ok = false;
359  }
360  }
361  return ok;
362 }
363 
364 
365 void
366 OptionsCont::reportDoubleSetting(const std::string& arg) const {
367  std::vector<std::string> synonymes = getSynonymes(arg);
368  std::ostringstream s;
369  s << "A value for the option '" + arg + "' was already set.\n Possible synonymes: ";
370  for (std::vector<std::string>::iterator i = synonymes.begin(); i != synonymes.end();) {
371  s << (*i);
372  i++;
373  if (i != synonymes.end()) {
374  s << ", ";
375  }
376  }
377  WRITE_ERROR(s.str());
378 }
379 
380 
381 std::string
382 OptionsCont::convertChar(char abbr) const {
383  char buf[2];
384  buf[0] = abbr;
385  buf[1] = 0;
386  std::string s(buf);
387  return s;
388 }
389 
390 
391 bool
392 OptionsCont::isBool(const std::string& name) const {
393  Option* o = getSecure(name);
394  return o->isBool();
395 }
396 
397 
398 void
400  for (ItemAddressContType::iterator i = myAddresses.begin(); i != myAddresses.end(); i++) {
401  (*i)->resetWritable();
402  }
403 }
404 
405 
406 bool
407 OptionsCont::isWriteable(const std::string& name) {
408  Option* o = getSecure(name);
409  return o->isWriteable();
410 }
411 
412 
413 void
415  ItemAddressContType::iterator i;
416  for (i = myAddresses.begin(); i != myAddresses.end(); i++) {
417  delete(*i);
418  }
419  myAddresses.clear();
420  myValues.clear();
421  mySubTopics.clear();
422  mySubTopicEntries.clear();
423 }
424 
425 
426 void
427 OptionsCont::addDescription(const std::string& name,
428  const std::string& subtopic,
429  const std::string& description) {
430  Option* o = getSecure(name);
431  assert(o != 0);
432  assert(find(mySubTopics.begin(), mySubTopics.end(), subtopic) != mySubTopics.end());
433  o->setDescription(description);
434  mySubTopicEntries[subtopic].push_back(name);
435 }
436 
437 
438 void
439 OptionsCont::setApplicationName(const std::string& appName,
440  const std::string& fullName) {
441  myAppName = appName;
442  myFullName = fullName;
443 }
444 
445 
446 void
447 OptionsCont::setApplicationDescription(const std::string& appDesc) {
448  myAppDescription = appDesc;
449 }
450 
451 
452 void
453 OptionsCont::addCallExample(const std::string& example, const std::string& desc) {
454  myCallExamples.push_back(std::make_pair(example, desc));
455 }
456 
457 
458 void
459 OptionsCont::setAdditionalHelpMessage(const std::string& add) {
460  myAdditionalMessage = add;
461 }
462 
463 
464 void
465 OptionsCont::addCopyrightNotice(const std::string& copyrightLine) {
466  myCopyrightNotices.push_back(copyrightLine);
467 }
468 
469 
470 void
472  myCopyrightNotices.clear();
473 }
474 
475 
476 void
477 OptionsCont::addOptionSubTopic(const std::string& topic) {
478  mySubTopics.push_back(topic);
479  mySubTopicEntries[topic] = std::vector<std::string>();
480 }
481 
482 
483 void
484 OptionsCont::splitLines(std::ostream& os, std::string what,
485  size_t offset, size_t nextOffset) {
486  while (what.length() > 0) {
487  if (what.length() > 79 - offset) {
488  size_t splitPos = what.rfind(';', 79 - offset);
489  if (splitPos == std::string::npos) {
490  splitPos = what.rfind(' ', 79 - offset);
491  } else {
492  splitPos++;
493  }
494  if (splitPos != std::string::npos) {
495  os << what.substr(0, splitPos) << std::endl;
496  what = what.substr(splitPos);
497  for (size_t r = 0; r < nextOffset + 1; ++r) {
498  os << ' ';
499  }
500  } else {
501  os << what;
502  what = "";
503  }
504  offset = nextOffset;
505  } else {
506  os << what;
507  what = "";
508  }
509  }
510  os << std::endl;
511 }
512 
513 
514 bool
515 OptionsCont::processMetaOptions(bool missingOptions) {
516  if (missingOptions) {
517  // no options are given
518  std::cout << myFullName << std::endl;
519  for (std::vector<std::string>::const_iterator it =
520  myCopyrightNotices.begin(); it != myCopyrightNotices.end(); ++it) {
521  std::cout << " " << *it << std::endl;
522  }
523  std::cout << " License GPLv3+: GNU GPL Version 3 or later <http://gnu.org/licenses/gpl.html>\n";
524  std::cout << " Use --help to get the list of options." << std::endl;
525  return true;
526  }
527 
528  // check whether the help shall be printed
529  if (getBool("help")) {
530  std::cout << myFullName << std::endl;
531  for (std::vector<std::string>::const_iterator it =
532  myCopyrightNotices.begin(); it != myCopyrightNotices.end(); ++it) {
533  std::cout << " " << *it << std::endl;
534  }
535  printHelp(std::cout);
536  return true;
537  }
538  // check whether the help shall be printed
539  if (getBool("version")) {
540  std::cout << myFullName << std::endl;
541  for (std::vector<std::string>::const_iterator it =
542  myCopyrightNotices.begin(); it != myCopyrightNotices.end(); ++it) {
543  std::cout << " " << *it << std::endl;
544  }
545  std::cout << "\n" << myFullName << " is part of SUMO.\n";
546  std::cout << "SUMO is free software: you can redistribute it and/or modify\n";
547  std::cout << "it under the terms of the GNU General Public License as published by\n";
548  std::cout << "the Free Software Foundation, either version 3 of the License, or\n";
549  std::cout << "(at your option) any later version.\n\n";
550  std::cout << "This program is distributed in the hope that it will be useful,\n";
551  std::cout << "but WITHOUT ANY WARRANTY; without even the implied warranty of\n";
552  std::cout << "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n";
553  std::cout << "GNU General Public License for more details.\n\n";
554  std::cout << "You should have received a copy of the GNU General Public License\n";
555  std::cout << "along with this program. If not, see http://www.gnu.org/licenses/gpl.html" << std::endl;
556  return true;
557  }
558  // check whether the settings shall be printed
559  if (exists("print-options") && getBool("print-options")) {
560  std::cout << (*this);
561  }
562  // check whether something has to be done with options
563  // whether the current options shall be saved
564  if (isSet("save-configuration", false)) { // sumo-gui does not register these
565  if (getString("save-configuration") == "-" || getString("save-configuration") == "stdout") {
566  writeConfiguration(std::cout, true, false, getBool("save-commented"));
567  return true;
568  }
569  std::ofstream out(getString("save-configuration").c_str());
570  if (!out.good()) {
571  throw ProcessError("Could not save configuration to '" + getString("save-configuration") + "'");
572  } else {
573  writeConfiguration(out, true, false, getBool("save-commented"));
574  if (getBool("verbose")) {
575  WRITE_MESSAGE("Written configuration to '" + getString("save-configuration") + "'");
576  }
577  return true;
578  }
579  }
580  // whether the template shall be saved
581  if (isSet("save-template", false)) { // sumo-gui does not register these
582  if (getString("save-template") == "-" || getString("save-template") == "stdout") {
583  writeConfiguration(std::cout, false, true, getBool("save-commented"));
584  return true;
585  }
586  std::ofstream out(getString("save-template").c_str());
587  if (!out.good()) {
588  throw ProcessError("Could not save template to '" + getString("save-template") + "'");
589  } else {
590  writeConfiguration(out, false, true, getBool("save-commented"));
591  if (getBool("verbose")) {
592  WRITE_MESSAGE("Written template to '" + getString("save-template") + "'");
593  }
594  return true;
595  }
596  }
597  if (isSet("save-schema", false)) { // sumo-gui does not register these
598  if (getString("save-schema") == "-" || getString("save-schema") == "stdout") {
599  writeSchema(std::cout, getBool("save-commented"));
600  return true;
601  }
602  std::ofstream out(getString("save-schema").c_str());
603  if (!out.good()) {
604  throw ProcessError("Could not save schema to '" + getString("save-schema") + "'");
605  } else {
606  writeSchema(out, getBool("save-commented"));
607  if (getBool("verbose")) {
608  WRITE_MESSAGE("Written schema to '" + getString("save-schema") + "'");
609  }
610  return true;
611  }
612  }
613  return false;
614 }
615 
616 void
617 OptionsCont::printHelp(std::ostream& os) {
618  std::vector<std::string>::const_iterator i, j;
619  // print application description
620  splitLines(os, myAppDescription, 0, 0);
621  os << std::endl;
622  // print usage BNF
623  os << "Usage: " << myAppName << " [OPTION]*" << std::endl;
624  // print additional text if any
625  if (myAdditionalMessage.length() > 0) {
626  os << myAdditionalMessage << std::endl << ' ' << std::endl;
627  }
628  // print the options
629  // check their sizes first
630  // we want to know how large the largest not-too-large-entry will be
631  size_t tooLarge = 40;
632  size_t maxSize = 0;
633  for (i = mySubTopics.begin(); i != mySubTopics.end(); ++i) {
634  const std::vector<std::string> &entries = mySubTopicEntries[*i];
635  for (j = entries.begin(); j != entries.end(); ++j) {
636  Option* o = getSecure(*j);
637  // name, two leading spaces and "--"
638  size_t csize = (*j).length() + 2 + 4;
639  // abbreviation length ("-X, "->4chars) if any
640  std::vector<std::string> synonymes = getSynonymes(*j);
641  if (find_if(synonymes.begin(), synonymes.end(), abbreviation_finder()) != synonymes.end()) {
642  csize += 4;
643  }
644  // the type name
645  if (!o->isBool()) {
646  csize += 1 + o->getTypeName().length();
647  }
648  // divider
649  csize += 2;
650  if (csize < tooLarge && maxSize < csize) {
651  maxSize = csize;
652  }
653  }
654  }
655 
656  for (i = mySubTopics.begin(); i != mySubTopics.end(); ++i) {
657  os << *i << " Options:" << std::endl;
658  const std::vector<std::string> &entries = mySubTopicEntries[*i];
659  for (j = entries.begin(); j != entries.end(); ++j) {
660  // start length computation
661  size_t csize = (*j).length() + 2;
662  Option* o = getSecure(*j);
663  os << " ";
664  // write abbreviation if given
665  std::vector<std::string> synonymes = getSynonymes(*j);
666  std::vector<std::string>::iterator a = find_if(synonymes.begin(), synonymes.end(), abbreviation_finder());
667  if (a != synonymes.end()) {
668  os << '-' << (*a) << ", ";
669  csize += 4;
670  }
671  // write leading '-'/"--"
672  os << "--";
673  csize += 2;
674  // write the name
675  os << *j;
676  // write the type if not a bool option
677  if (!o->isBool()) {
678  os << ' ' << o->getTypeName();
679  csize += 1 + o->getTypeName().length();
680  }
681  csize += 2;
682  // write the description formatting it
683  os << " ";
684  for (size_t r = maxSize; r > csize; --r) {
685  os << ' ';
686  }
687  size_t offset = csize > tooLarge ? csize : maxSize;
688  splitLines(os, o->getDescription(), offset, maxSize);
689  }
690  os << std::endl;
691  }
692  os << std::endl;
693  // print usage examples, calc size first
694  if (myCallExamples.size() != 0) {
695  os << "Examples:" << std::endl;
696  for (std::vector<std::pair<std::string,std::string> >::const_iterator e = myCallExamples.begin(); e != myCallExamples.end(); ++e) {
697  os << " " << myAppName << ' ' << e->first << std::endl;
698  os << " " << e->second << std::endl;
699  }
700  }
701  os << std::endl;
702  os << "Report bugs at <http://sourceforge.net/apps/trac/sumo/>." << std::endl;
703  os << "Get in contact via <sumo-user@lists.sourceforge.net>." << std::endl;
704 }
705 
706 
707 void
708 OptionsCont::writeConfiguration(std::ostream& os, bool filled,
709  bool complete, bool addComments) {
710  os << "<?xml version=\"1.0\"" << SUMOSAXAttributes::ENCODING << "?>\n\n";
711  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;
712  for (std::vector<std::string>::const_iterator i = mySubTopics.begin(); i != mySubTopics.end(); ++i) {
713  std::string subtopic = *i;
714  if (subtopic == "Configuration" && !complete) {
715  continue;
716  }
717  std::replace(subtopic.begin(), subtopic.end(), ' ', '_');
718  std::transform(subtopic.begin(), subtopic.end(), subtopic.begin(), tolower);
719  const std::vector<std::string> &entries = mySubTopicEntries[*i];
720  bool hadOne = false;
721  for (std::vector<std::string>::const_iterator j = entries.begin(); j != entries.end(); ++j) {
722  Option* o = getSecure(*j);
723  bool write = complete || (filled && !o->isDefault());
724  if (!write) {
725  continue;
726  }
727  if (!hadOne) {
728  os << " <" << subtopic << ">" << std::endl;
729  }
730  // add the comment if wished
731  if (addComments) {
732  os << " <!-- " << o->getDescription() << " -->" << std::endl;
733  }
734  // write the option and the value (if given)
735  os << " <" << *j << " value=\"";
736  if (o->isSet() && (filled || o->isDefault())) {
737  os << o->getValueString();
738  }
739  if (complete) {
740  std::vector<std::string> synonymes = getSynonymes(*j);
741  if (!synonymes.empty()) {
742  os << "\" synonymes=\"";
743  for (std::vector<std::string>::const_iterator s = synonymes.begin(); s != synonymes.end(); ++s) {
744  if (s != synonymes.begin()) {
745  os << " ";
746  }
747  os << (*s);
748  }
749  }
750  os << "\" type=\"" << o->getTypeName();
751  if (!addComments) {
752  os << "\" help=\"" << o->getDescription();
753  }
754  }
755  os << "\"/>" << std::endl;
756  // append an endline if a comment was printed
757  if (addComments) {
758  os << std::endl;
759  }
760  hadOne = true;
761  }
762  if (hadOne) {
763  os << " </" << subtopic << ">" << std::endl << std::endl;
764  }
765  }
766  os << "</configuration>" << std::endl;
767 }
768 
769 
770 void
771 OptionsCont::writeSchema(std::ostream& os, bool addComments) {
772  os << "<?xml version=\"1.0\"" << SUMOSAXAttributes::ENCODING << "?>\n\n";
773  os << "<xsd:schema elementFormDefault=\"qualified\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n\n";
774  os << " <xsd:element name=\"configuration\" type=\"configurationType\"/>\n\n";
775  os << " <xsd:complexType name=\"configurationType\">\n";
776  os << " <xsd:sequence>\n";
777  for (std::vector<std::string>::const_iterator i = mySubTopics.begin(); i != mySubTopics.end(); ++i) {
778  std::string subtopic = *i;
779  if (subtopic == "Configuration") {
780  continue;
781  }
782  std::replace(subtopic.begin(), subtopic.end(), ' ', '_');
783  std::transform(subtopic.begin(), subtopic.end(), subtopic.begin(), tolower);
784  os << " <xsd:element name=\"" << subtopic << "\" type=\"" << subtopic << "Type\" minOccurs=\"0\" maxOccurs=\"1\"/>\n";
785  }
786  os << " </xsd:sequence>\n";
787  os << " </xsd:complexType>\n\n";
788  for (std::vector<std::string>::const_iterator i = mySubTopics.begin(); i != mySubTopics.end(); ++i) {
789  std::string subtopic = *i;
790  if (subtopic == "Configuration") {
791  continue;
792  }
793  std::replace(subtopic.begin(), subtopic.end(), ' ', '_');
794  std::transform(subtopic.begin(), subtopic.end(), subtopic.begin(), tolower);
795  os << " <xsd:complexType name=\"" << subtopic << "Type\">\n";
796  os << " <xsd:sequence>\n";
797  const std::vector<std::string> &entries = mySubTopicEntries[*i];
798  for (std::vector<std::string>::const_iterator j = entries.begin(); j != entries.end(); ++j) {
799  os << " <xsd:element name=\"" << *j << "\" type=\"" << *j << "Type\" minOccurs=\"0\" maxOccurs=\"1\"/>\n";
800  }
801  os << " </xsd:sequence>\n";
802  os << " </xsd:complexType>\n\n";
803  for (std::vector<std::string>::const_iterator j = entries.begin(); j != entries.end(); ++j) {
804  Option* o = getSecure(*j);
805  std::string type = o->getTypeName();
806  std::transform(type.begin(), type.end(), type.begin(), tolower);
807  if (type == "bool") {
808  type = "boolean";
809  } else {
810  if (type != "int" && type != "float") {
811  type = "string";
812  }
813  }
814  os << " <xsd:complexType name=\"" << *j << "Type\">\n";
815  if (addComments) {
816  os << " <!-- " << o->getDescription() << " -->\n";
817  }
818  os << " <xsd:attribute name=\"value\" type=\"xsd:" << type << "\" use=\"required\"/>\n";
819  os << " <xsd:attribute name=\"synonymes\" type=\"xsd:string\" use=\"optional\"/>\n";
820  os << " <xsd:attribute name=\"type\" type=\"xsd:string\" use=\"optional\"/>\n";
821  os << " <xsd:attribute name=\"help\" type=\"xsd:string\" use=\"optional\"/>\n";
822  os << " </xsd:complexType>\n\n";
823  }
824  }
825  os << "</xsd:schema>\n";
826 }
827 
828 
829 void
830 OptionsCont::writeXMLHeader(std::ostream& os, const std::string xmlParams) {
831  time_t rawtime;
832  char buffer [80];
833 
834  os << "<?xml version=\"1.0\"" << xmlParams << "?>\n\n";
835  time(&rawtime);
836  strftime(buffer, 80, "<!-- generated on %c by ", localtime(&rawtime));
837  os << buffer << myFullName << "\n";
838  writeConfiguration(os, true, false, false);
839  os << "-->\n\n";
840 }
841 
842 
843 std::vector<std::string>
844 OptionsCont::getStringVector(const std::string& name) const {
845  Option* o = getSecure(name);
846  std::string def = o->getString();
847  if (def.find(';') != std::string::npos && !myHaveInformedAboutDeprecatedDivider) {
848  WRITE_WARNING("Please note that using ';' as list separator is deprecated.\n From 1.0 onwards, only ',' will be accepted.");
850  }
851  StringTokenizer st(def, ";,", true);
852  std::vector<std::string> ret = st.getVector();
853  for (std::vector<std::string>::iterator i = ret.begin(); i != ret.end(); ++i) {
854  (*i) = StringUtils::prune(*i);
855  }
856  return ret;
857 }
858 
859 
860 bool
861 OptionsCont::isInStringVector(const std::string& optionName,
862  const std::string& itemName) {
863  if (isSet(optionName)) {
864  std::vector<std::string> values = getStringVector(optionName);
865  return find(values.begin(), values.end(), itemName) != values.end();
866  }
867  return false;
868 }
869 
870 
871 /****************************************************************************/