Eclipse SUMO - Simulation of Urban MObility
OptionsCont.cpp
Go to the documentation of this file.
1 /****************************************************************************/
2 // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.org/sumo
3 // Copyright (C) 2001-2022 German Aerospace Center (DLR) and others.
4 // This program and the accompanying materials are made available under the
5 // terms of the Eclipse Public License 2.0 which is available at
6 // https://www.eclipse.org/legal/epl-2.0/
7 // This Source Code may also be made available under the following Secondary
8 // Licenses when the conditions for such availability set forth in the Eclipse
9 // Public License 2.0 are satisfied: GNU General Public License, version 2
10 // or later which is available at
11 // https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html
12 // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later
13 /****************************************************************************/
21 // A storage for options (typed value containers)
22 /****************************************************************************/
23 #include <config.h>
24 
25 #include <map>
26 #include <string>
27 #include <exception>
28 #include <algorithm>
29 #include <vector>
30 #include <iostream>
31 #include <cstdlib>
32 #include <cassert>
33 #include <ctime>
34 #include <cstring>
35 #include <cerrno>
36 #include <iterator>
37 #include "Option.h"
38 #include "OptionsCont.h"
45 #include <sstream>
46 
47 
48 // ===========================================================================
49 // static member definitions
50 // ===========================================================================
52 
53 
54 // ===========================================================================
55 // method definitions
56 // ===========================================================================
59  return myOptions;
60 }
61 
62 
64  : myAddresses(), myValues(), myDeprecatedSynonymes() {
65  myCopyrightNotices.push_back("Copyright (C) 2001-2022 German Aerospace Center (DLR) and others; https://sumo.dlr.de");
66 }
67 
68 
70  clear();
71 }
72 
73 
74 void
75 OptionsCont::doRegister(const std::string& name, Option* v) {
76  assert(v != 0);
77  ItemAddressContType::iterator i = std::find(myAddresses.begin(), myAddresses.end(), v);
78  if (i == myAddresses.end()) {
79  myAddresses.push_back(v);
80  }
81  if (myValues.find(name) != myValues.end()) {
82  throw ProcessError(name + " is an already used option name.");
83  }
84  myValues[name] = v;
85 }
86 
87 
88 void
89 OptionsCont::doRegister(const std::string& name1, char abbr, Option* v) {
90  doRegister(name1, v);
91  doRegister(convertChar(abbr), v);
92 }
93 
94 
95 void
96 OptionsCont::addSynonyme(const std::string& name1, const std::string& name2, bool isDeprecated) {
97  KnownContType::iterator i1 = myValues.find(name1);
98  KnownContType::iterator i2 = myValues.find(name2);
99  if (i1 == myValues.end() && i2 == myValues.end()) {
100  throw ProcessError("Neither the option '" + name1 + "' nor the option '" + name2 + "' is known yet");
101  }
102  if (i1 != myValues.end() && i2 != myValues.end()) {
103  if ((*i1).second == (*i2).second) {
104  return;
105  }
106  throw ProcessError("Both options '" + name1 + "' and '" + name2 + "' do exist and differ.");
107  }
108  if (i1 == myValues.end() && i2 != myValues.end()) {
109  doRegister(name1, (*i2).second);
110  if (isDeprecated) {
111  myDeprecatedSynonymes[name1] = false;
112  }
113  }
114  if (i1 != myValues.end() && i2 == myValues.end()) {
115  doRegister(name2, (*i1).second);
116  if (isDeprecated) {
117  myDeprecatedSynonymes[name2] = false;
118  }
119  }
120 }
121 
122 
123 void
124 OptionsCont::addXMLDefault(const std::string& name, const std::string& xmlRoot) {
125  myXMLDefaults[xmlRoot] = name;
126 }
127 
128 
129 bool
130 OptionsCont::exists(const std::string& name) const {
131  return myValues.count(name) > 0;
132 }
133 
134 
135 bool
136 OptionsCont::isSet(const std::string& name, bool failOnNonExistant) const {
137  KnownContType::const_iterator i = myValues.find(name);
138  if (i == myValues.end()) {
139  if (failOnNonExistant) {
140  throw ProcessError("Internal request for unknown option '" + name + "'!");
141  } else {
142  return false;
143  }
144  }
145  return (*i).second->isSet();
146 }
147 
148 
149 void
150 OptionsCont::unSet(const std::string& name, bool failOnNonExistant) const {
151  KnownContType::const_iterator i = myValues.find(name);
152  if (i == myValues.end()) {
153  if (failOnNonExistant) {
154  throw ProcessError("Internal request for unknown option '" + name + "'!");
155  } else {
156  return;
157  }
158  }
159  (*i).second->unSet();
160 }
161 
162 
163 bool
164 OptionsCont::isDefault(const std::string& name) const {
165  KnownContType::const_iterator i = myValues.find(name);
166  if (i == myValues.end()) {
167  return false;
168  }
169  return (*i).second->isDefault();
170 }
171 
172 
173 Option*
174 OptionsCont::getSecure(const std::string& name) const {
175  KnownContType::const_iterator k = myValues.find(name);
176  if (k == myValues.end()) {
177  throw ProcessError("No option with the name '" + name + "' exists.");
178  }
179  std::map<std::string, bool>::iterator s = myDeprecatedSynonymes.find(name);
180  if (s != myDeprecatedSynonymes.end() && !s->second) {
181  std::string defaultName;
182  for (std::map<std::string, std::vector<std::string> >::const_iterator i = mySubTopicEntries.begin(); i != mySubTopicEntries.end(); ++i) {
183  for (std::vector<std::string>::const_iterator j = i->second.begin(); j != i->second.end(); ++j) {
184  KnownContType::const_iterator l = myValues.find(*j);
185  if (l != myValues.end() && l->second == k->second) {
186  defaultName = *j;
187  break;
188  }
189  }
190  if (defaultName != "") {
191  break;
192  }
193  }
194  WRITE_WARNING("Please note that '" + name + "' is deprecated.\n Use '" + defaultName + "' instead.");
195  s->second = true;
196  }
197  return k->second;
198 }
199 
200 
201 std::string
202 OptionsCont::getValueString(const std::string& name) const {
203  Option* o = getSecure(name);
204  return o->getValueString();
205 }
206 
207 
208 std::string
209 OptionsCont::getString(const std::string& name) const {
210  Option* o = getSecure(name);
211  return o->getString();
212 }
213 
214 
215 double
216 OptionsCont::getFloat(const std::string& name) const {
217  Option* o = getSecure(name);
218  return o->getFloat();
219 }
220 
221 
222 int
223 OptionsCont::getInt(const std::string& name) const {
224  Option* o = getSecure(name);
225  return o->getInt();
226 }
227 
228 
229 bool
230 OptionsCont::getBool(const std::string& name) const {
231  Option* o = getSecure(name);
232  return o->getBool();
233 }
234 
235 
236 const IntVector&
237 OptionsCont::getIntVector(const std::string& name) const {
238  Option* o = getSecure(name);
239  return o->getIntVector();
240 }
241 
242 const StringVector&
243 OptionsCont::getStringVector(const std::string& name) const {
244  Option* o = getSecure(name);
245  return o->getStringVector();
246 }
247 
248 bool
249 OptionsCont::set(const std::string& name, const std::string& value) {
250  Option* o = getSecure(name);
251  if (!o->isWriteable()) {
252  reportDoubleSetting(name);
253  return false;
254  }
255  try {
256  if (!o->set(value)) {
257  return false;
258  }
259  } catch (ProcessError& e) {
260  WRITE_ERROR("While processing option '" + name + "':\n " + e.what());
261  return false;
262  }
263  return true;
264 }
265 
266 
267 bool
268 OptionsCont::setDefault(const std::string& name, const std::string& value) {
269  if (set(name, value)) {
270  getSecure(name)->resetDefault();
271  return true;
272  }
273  return false;
274 }
275 
276 
277 bool
278 OptionsCont::setByRootElement(const std::string& root, const std::string& value) {
279  if (myXMLDefaults.count(root) > 0) {
280  return set(myXMLDefaults[root], value);
281  }
282  if (myXMLDefaults.count("") > 0) {
283  return set(myXMLDefaults[""], value);
284  }
285  return false;
286 }
287 
288 
289 std::vector<std::string>
290 OptionsCont::getSynonymes(const std::string& name) const {
291  Option* o = getSecure(name);
292  std::vector<std::string> v(0);
293  for (KnownContType::const_iterator i = myValues.begin(); i != myValues.end(); i++) {
294  if ((*i).second == o && name != (*i).first) {
295  v.push_back((*i).first);
296  }
297  }
298  return v;
299 }
300 
301 
302 const std::string&
303 OptionsCont::getDescription(const std::string& name) const {
304  return getSecure(name)->getDescription();
305 }
306 
307 
308 std::ostream&
309 operator<<(std::ostream& os, const OptionsCont& oc) {
310  std::vector<std::string> done;
311  os << "Options set:" << std::endl;
312  for (OptionsCont::KnownContType::const_iterator i = oc.myValues.begin();
313  i != oc.myValues.end(); i++) {
314  std::vector<std::string>::iterator j = std::find(done.begin(), done.end(), (*i).first);
315  if (j == done.end()) {
316  std::vector<std::string> synonymes = oc.getSynonymes((*i).first);
317  if (synonymes.size() != 0) {
318  os << (*i).first << " (";
319  for (j = synonymes.begin(); j != synonymes.end(); j++) {
320  if (j != synonymes.begin()) {
321  os << ", ";
322  }
323  os << (*j);
324  }
325  os << ")";
326  } else {
327  os << (*i).first;
328  }
329  if ((*i).second->isSet()) {
330  os << ": " << (*i).second->getValueString() << std::endl;
331  } else {
332  os << ": <INVALID>" << std::endl;
333  }
334  done.push_back((*i).first);
335  copy(synonymes.begin(), synonymes.end(), back_inserter(done));
336  }
337  }
338  return os;
339 }
340 
341 
342 void
343 OptionsCont::relocateFiles(const std::string& configuration) const {
344  for (Option* const option : myAddresses) {
345  if (option->isFileName() && option->isSet()) {
346  StringVector fileList = StringVector(option->getStringVector());
347  for (std::string& f : fileList) {
348  f = FileHelpers::checkForRelativity(f, configuration);
349  try {
350  f = StringUtils::urlDecode(f);
351  } catch (NumberFormatException& e) {
352  WRITE_WARNING(toString(e.what()) + " when trying to decode filename '" + f + "'.");
353  }
354  }
355  const std::string conv = joinToString(fileList, ',');
356  if (conv != joinToString(option->getStringVector(), ',')) {
357  const bool hadDefault = option->isDefault();
358  option->set(conv);
359  if (hadDefault) {
360  option->resetDefault();
361  }
362  }
363  }
364  }
365 }
366 
367 
368 bool
369 OptionsCont::isUsableFileList(const std::string& name) const {
370  Option* o = getSecure(name);
371  // check whether the option is set
372  // return false i not
373  if (!o->isSet()) {
374  return false;
375  }
376  // check whether the list of files is valid
377  bool ok = true;
378  std::vector<std::string> files = getStringVector(name);
379  if (files.size() == 0) {
380  WRITE_ERROR("The file list for '" + name + "' is empty.");
381  ok = false;
382  }
383  for (std::vector<std::string>::const_iterator fileIt = files.begin(); fileIt != files.end(); ++fileIt) {
384  if (!FileHelpers::isReadable(*fileIt)) {
385  if (*fileIt != "") {
386  WRITE_ERROR("File '" + *fileIt + "' is not accessible (" + std::strerror(errno) + ").");
387  ok = false;
388  } else {
389  WRITE_WARNING("Empty file name given; ignoring.");
390  }
391  }
392  }
393  return ok;
394 }
395 
396 
397 bool
398 OptionsCont::checkDependingSuboptions(const std::string& name, const std::string& prefix) const {
399  Option* o = getSecure(name);
400  if (o->isSet()) {
401  return true;
402  }
403  bool ok = true;
404  std::vector<std::string> seenSynonymes;
405  for (KnownContType::const_iterator i = myValues.begin(); i != myValues.end(); i++) {
406  if (std::find(seenSynonymes.begin(), seenSynonymes.end(), (*i).first) != seenSynonymes.end()) {
407  continue;
408  }
409  if ((*i).second->isSet() && !(*i).second->isDefault() && (*i).first.find(prefix) == 0) {
410  WRITE_ERROR("Option '" + (*i).first + "' needs option '" + name + "'.");
411  std::vector<std::string> synonymes = getSynonymes((*i).first);
412  std::copy(synonymes.begin(), synonymes.end(), std::back_inserter(seenSynonymes));
413  ok = false;
414  }
415  }
416  return ok;
417 }
418 
419 
420 void
421 OptionsCont::reportDoubleSetting(const std::string& arg) const {
422  std::vector<std::string> synonymes = getSynonymes(arg);
423  std::ostringstream s;
424  s << "A value for the option '" + arg + "' was already set.\n Possible synonymes: ";
425  for (std::vector<std::string>::iterator i = synonymes.begin(); i != synonymes.end();) {
426  s << (*i);
427  i++;
428  if (i != synonymes.end()) {
429  s << ", ";
430  }
431  }
432  WRITE_ERROR(s.str());
433 }
434 
435 
436 std::string
437 OptionsCont::convertChar(char abbr) const {
438  char buf[2];
439  buf[0] = abbr;
440  buf[1] = 0;
441  std::string s(buf);
442  return s;
443 }
444 
445 
446 bool
447 OptionsCont::isBool(const std::string& name) const {
448  Option* o = getSecure(name);
449  return o->isBool();
450 }
451 
452 
453 void
455  for (ItemAddressContType::iterator i = myAddresses.begin(); i != myAddresses.end(); i++) {
456  (*i)->resetWritable();
457  }
458 }
459 
460 
461 bool
462 OptionsCont::isWriteable(const std::string& name) {
463  Option* o = getSecure(name);
464  return o->isWriteable();
465 }
466 
467 
468 void
470  ItemAddressContType::iterator i;
471  for (i = myAddresses.begin(); i != myAddresses.end(); i++) {
472  delete (*i);
473  }
474  myAddresses.clear();
475  myValues.clear();
476  mySubTopics.clear();
477  mySubTopicEntries.clear();
478 }
479 
480 
481 void
482 OptionsCont::addDescription(const std::string& name,
483  const std::string& subtopic,
484  const std::string& description) {
485  Option* o = getSecure(name);
486  assert(o != 0);
487  assert(find(mySubTopics.begin(), mySubTopics.end(), subtopic) != mySubTopics.end());
488  o->setDescription(description);
489  mySubTopicEntries[subtopic].push_back(name);
490 }
491 
492 
493 void
494 OptionsCont::setApplicationName(const std::string& appName,
495  const std::string& fullName) {
496  myAppName = appName;
497  myFullName = fullName;
498 }
499 
500 
501 void
502 OptionsCont::setApplicationDescription(const std::string& appDesc) {
503  myAppDescription = appDesc;
504 }
505 
506 
507 void
508 OptionsCont::addCallExample(const std::string& example, const std::string& desc) {
509  myCallExamples.push_back(std::make_pair(example, desc));
510 }
511 
512 
513 void
514 OptionsCont::setAdditionalHelpMessage(const std::string& add) {
515  myAdditionalMessage = add;
516 }
517 
518 
519 void
520 OptionsCont::addCopyrightNotice(const std::string& copyrightLine) {
521  myCopyrightNotices.push_back(copyrightLine);
522 }
523 
524 
525 void
527  myCopyrightNotices.clear();
528 }
529 
530 
531 void
532 OptionsCont::addOptionSubTopic(const std::string& topic) {
533  mySubTopics.push_back(topic);
534  mySubTopicEntries[topic] = std::vector<std::string>();
535 }
536 
537 
538 void
539 OptionsCont::splitLines(std::ostream& os, std::string what,
540  int offset, int nextOffset) {
541  while (what.length() > 0) {
542  if ((int)what.length() > 79 - offset) {
543  std::string::size_type splitPos = what.rfind(';', 79 - offset);
544  if (splitPos == std::string::npos) {
545  splitPos = what.rfind(' ', 79 - offset);
546  } else {
547  splitPos++;
548  }
549  if (splitPos != std::string::npos) {
550  os << what.substr(0, splitPos) << std::endl;
551  what = what.substr(splitPos + 1);
552  for (int r = 0; r < nextOffset + 1; ++r) {
553  os << ' ';
554  }
555  } else {
556  os << what;
557  what = "";
558  }
559  offset = nextOffset;
560  } else {
561  os << what;
562  what = "";
563  }
564  }
565  os << std::endl;
566 }
567 
568 
569 bool
570 OptionsCont::processMetaOptions(bool missingOptions) {
571  if (missingOptions) {
572  // no options are given
573  std::cout << myFullName << std::endl;
574  std::cout << " Build features: " << HAVE_ENABLED << std::endl;
575  for (std::vector<std::string>::const_iterator it =
576  myCopyrightNotices.begin(); it != myCopyrightNotices.end(); ++it) {
577  std::cout << " " << *it << std::endl;
578  }
579  std::cout << " License EPL-2.0: Eclipse Public License Version 2 <https://eclipse.org/legal/epl-v20.html>\n";
580  std::cout << " Use --help to get the list of options." << std::endl;
581  return true;
582  }
583 
584  myWriteLicense = getBool("write-license");
585  // check whether the help shall be printed
586  if (getBool("help")) {
587  std::cout << myFullName << std::endl;
588  for (std::vector<std::string>::const_iterator it =
589  myCopyrightNotices.begin(); it != myCopyrightNotices.end(); ++it) {
590  std::cout << " " << *it << std::endl;
591  }
592  printHelp(std::cout);
593  return true;
594  }
595  // check whether the help shall be printed
596  if (getBool("version")) {
597  std::cout << myFullName << std::endl;
598  std::cout << " Build features: " << HAVE_ENABLED << std::endl;
599  for (std::vector<std::string>::const_iterator it =
600  myCopyrightNotices.begin(); it != myCopyrightNotices.end(); ++it) {
601  std::cout << " " << *it << std::endl;
602  }
603  std::cout << "\n" << myFullName << " is part of SUMO.\n";
604  std::cout << "This program and the accompanying materials\n";
605  std::cout << "are made available under the terms of the Eclipse Public License v2.0\n";
606  std::cout << "which accompanies this distribution, and is available at\n";
607  std::cout << "http://www.eclipse.org/legal/epl-v20.html\n";
608  std::cout << "This program may also be made available under the following Secondary\n";
609  std::cout << "Licenses when the conditions for such availability set forth in the Eclipse\n";
610  std::cout << "Public License 2.0 are satisfied: GNU General Public License, version 2\n";
611  std::cout << "or later which is available at\n";
612  std::cout << "https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html\n";
613  std::cout << "SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later" << std::endl;
614  return true;
615  }
616  // check whether the settings shall be printed
617  if (exists("print-options") && getBool("print-options")) {
618  std::cout << (*this);
619  }
620  // check whether something has to be done with options
621  // whether the current options shall be saved
622  if (isSet("save-configuration", false)) { // sumo-gui does not register these
623  if (getString("save-configuration") == "-" || getString("save-configuration") == "stdout") {
624  writeConfiguration(std::cout, true, false, getBool("save-commented"));
625  return true;
626  }
627  std::ofstream out(StringUtils::transcodeToLocal(getString("save-configuration")).c_str());
628  if (!out.good()) {
629  throw ProcessError("Could not save configuration to '" + getString("save-configuration") + "'");
630  } else {
631  writeConfiguration(out, true, false, getBool("save-commented"));
632  if (getBool("verbose")) {
633  WRITE_MESSAGE("Written configuration to '" + getString("save-configuration") + "'");
634  }
635  return true;
636  }
637  }
638  // whether the template shall be saved
639  if (isSet("save-template", false)) { // sumo-gui does not register these
640  if (getString("save-template") == "-" || getString("save-template") == "stdout") {
641  writeConfiguration(std::cout, false, true, getBool("save-commented"));
642  return true;
643  }
644  std::ofstream out(StringUtils::transcodeToLocal(getString("save-template")).c_str());
645  if (!out.good()) {
646  throw ProcessError("Could not save template to '" + getString("save-template") + "'");
647  } else {
648  writeConfiguration(out, false, true, getBool("save-commented"));
649  if (getBool("verbose")) {
650  WRITE_MESSAGE("Written template to '" + getString("save-template") + "'");
651  }
652  return true;
653  }
654  }
655  if (isSet("save-schema", false)) { // sumo-gui does not register these
656  if (getString("save-schema") == "-" || getString("save-schema") == "stdout") {
657  writeSchema(std::cout);
658  return true;
659  }
660  std::ofstream out(StringUtils::transcodeToLocal(getString("save-schema")).c_str());
661  if (!out.good()) {
662  throw ProcessError("Could not save schema to '" + getString("save-schema") + "'");
663  } else {
664  writeSchema(out);
665  if (getBool("verbose")) {
666  WRITE_MESSAGE("Written schema to '" + getString("save-schema") + "'");
667  }
668  return true;
669  }
670  }
671  return false;
672 }
673 
674 void
675 OptionsCont::printHelp(std::ostream& os) {
676  std::vector<std::string>::const_iterator i, j;
677  // print application description
678  splitLines(os, myAppDescription, 0, 0);
679  os << std::endl;
680 
681  // check option sizes first
682  // we want to know how large the largest not-too-large-entry will be
683  int tooLarge = 40;
684  int maxSize = 0;
685  for (i = mySubTopics.begin(); i != mySubTopics.end(); ++i) {
686  const std::vector<std::string>& entries = mySubTopicEntries[*i];
687  for (j = entries.begin(); j != entries.end(); ++j) {
688  Option* o = getSecure(*j);
689  // name, two leading spaces and "--"
690  int csize = (int)j->length() + 2 + 4;
691  // abbreviation length ("-X, "->4chars) if any
692  const std::vector<std::string> synonymes = getSynonymes(*j);
693  for (std::vector<std::string>::const_iterator s = synonymes.begin(); s != synonymes.end(); ++s) {
694  if (s->length() == 1 && myDeprecatedSynonymes.count(*s) == 0) {
695  csize += 4;
696  break;
697  }
698  }
699  // the type name
700  if (!o->isBool()) {
701  csize += 1 + (int)o->getTypeName().length();
702  }
703  // divider
704  csize += 2;
705  if (csize < tooLarge && maxSize < csize) {
706  maxSize = csize;
707  }
708  }
709  }
710 
711  const std::string helpTopic = StringUtils::to_lower_case(getSecure("help")->getValueString());
712  if (helpTopic != "") {
713  bool foundTopic = false;
714  for (const std::string& topic : mySubTopics) {
715  if (StringUtils::to_lower_case(topic).find(helpTopic) != std::string::npos) {
716  foundTopic = true;
717  printHelpOnTopic(topic, tooLarge, maxSize, os);
718  }
719  }
720  if (!foundTopic) {
721  // print topic list
722  os << "Help Topics:" << std::endl;
723  for (std::string t : mySubTopics) {
724  os << " " << t << std::endl;
725  }
726  }
727  return;
728  }
729  // print usage BNF
730  os << "Usage: " << myAppName << " [OPTION]*" << std::endl;
731  // print additional text if any
732  if (myAdditionalMessage.length() > 0) {
733  os << myAdditionalMessage << std::endl << ' ' << std::endl;
734  }
735  // print the options
736  for (i = mySubTopics.begin(); i != mySubTopics.end(); ++i) {
737  printHelpOnTopic(*i, tooLarge, maxSize, os);
738  }
739  os << std::endl;
740  // print usage examples, calc size first
741  if (myCallExamples.size() != 0) {
742  os << "Examples:" << std::endl;
743  for (std::vector<std::pair<std::string, std::string> >::const_iterator e = myCallExamples.begin(); e != myCallExamples.end(); ++e) {
744  os << " " << myAppName << ' ' << e->first << std::endl;
745  os << " " << e->second << std::endl;
746  }
747  }
748  os << std::endl;
749  os << "Report bugs at <https://github.com/eclipse/sumo/issues>." << std::endl;
750  os << "Get in contact via <sumo@dlr.de>." << std::endl;
751 }
752 
753 void
754 OptionsCont::printHelpOnTopic(const std::string& topic, int tooLarge, int maxSize, std::ostream& os) {
755  os << topic << " Options:" << std::endl;
756  for (std::string entry : mySubTopicEntries[topic]) {
757  // start length computation
758  int csize = (int)entry.length() + 2;
759  Option* o = getSecure(entry);
760  os << " ";
761  // write abbreviation if given
762  std::vector<std::string> synonymes = getSynonymes(entry);
763  for (std::vector<std::string>::const_iterator s = synonymes.begin(); s != synonymes.end(); ++s) {
764  if (s->length() == 1 && myDeprecatedSynonymes.count(*s) == 0) {
765  os << '-' << *s << ", ";
766  csize += 4;
767  break;
768  }
769  }
770  // write leading '-'/"--"
771  os << "--";
772  csize += 2;
773  // write the name
774  os << entry;
775  // write the type if not a bool option
776  if (!o->isBool()) {
777  os << ' ' << o->getTypeName();
778  csize += 1 + (int)o->getTypeName().length();
779  }
780  csize += 2;
781  // write the description formatting it
782  os << " ";
783  for (int r = maxSize; r > csize; --r) {
784  os << ' ';
785  }
786  int offset = csize > tooLarge ? csize : maxSize;
787  splitLines(os, o->getDescription(), offset, maxSize);
788  }
789  os << std::endl;
790 }
791 
792 void
793 OptionsCont::writeConfiguration(std::ostream& os, const bool filled,
794  const bool complete, const bool addComments,
795  const bool inComment) const {
796  if (!inComment) {
797  writeXMLHeader(os, false);
798  }
799  os << "<configuration xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:noNamespaceSchemaLocation=\"http://sumo.dlr.de/xsd/";
800  if (myAppName == "sumo-gui") {
801  os << "sumo";
802  } else if (myAppName == "netedit") {
803  os << "netconvert";
804  } else {
805  os << myAppName;
806  }
807  os << "Configuration.xsd\">" << std::endl << std::endl;
808  for (std::vector<std::string>::const_iterator i = mySubTopics.begin(); i != mySubTopics.end(); ++i) {
809  std::string subtopic = *i;
810  if (subtopic == "Configuration" && !complete) {
811  continue;
812  }
813  std::replace(subtopic.begin(), subtopic.end(), ' ', '_');
814  subtopic = StringUtils::to_lower_case(subtopic);
815  const std::vector<std::string>& entries = mySubTopicEntries.find(*i)->second;
816  bool hadOne = false;
817  for (const std::string& name : entries) {
818  Option* o = getSecure(name);
819  bool write = complete || (filled && !o->isDefault());
820  if (!write) {
821  continue;
822  }
823  if (name == "registry-viewport" && !complete) {
824  continue;
825  }
826  if (!hadOne) {
827  os << " <" << subtopic << ">" << std::endl;
828  }
829  // add the comment if wished
830  if (addComments) {
831  os << " <!-- " << StringUtils::escapeXML(o->getDescription(), inComment) << " -->" << std::endl;
832  }
833  // write the option and the value (if given)
834  os << " <" << name << " value=\"";
835  if (o->isSet() && (filled || o->isDefault())) {
836  os << StringUtils::escapeXML(o->getValueString(), inComment);
837  }
838  if (complete) {
839  std::vector<std::string> synonymes = getSynonymes(name);
840  if (!synonymes.empty()) {
841  os << "\" synonymes=\"";
842  for (std::vector<std::string>::const_iterator s = synonymes.begin(); s != synonymes.end(); ++s) {
843  if (s != synonymes.begin()) {
844  os << " ";
845  }
846  os << (*s);
847  }
848  }
849  os << "\" type=\"" << o->getTypeName();
850  if (!addComments) {
851  os << "\" help=\"" << StringUtils::escapeXML(o->getDescription());
852  }
853  }
854  os << "\"/>" << std::endl;
855  // append an endline if a comment was printed
856  if (addComments) {
857  os << std::endl;
858  }
859  hadOne = true;
860  }
861  if (hadOne) {
862  os << " </" << subtopic << ">" << std::endl << std::endl;
863  }
864  }
865  os << "</configuration>" << std::endl;
866 }
867 
868 
869 void
870 OptionsCont::writeSchema(std::ostream& os) {
871  writeXMLHeader(os, false);
872  os << "<xsd:schema elementFormDefault=\"qualified\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n\n";
873  os << " <xsd:include schemaLocation=\"baseTypes.xsd\"/>\n";
874  os << " <xsd:element name=\"configuration\" type=\"configurationType\"/>\n\n";
875  os << " <xsd:complexType name=\"configurationType\">\n";
876  os << " <xsd:all>\n";
877  for (std::vector<std::string>::const_iterator i = mySubTopics.begin(); i != mySubTopics.end(); ++i) {
878  std::string subtopic = *i;
879  if (subtopic == "Configuration") {
880  continue;
881  }
882  std::replace(subtopic.begin(), subtopic.end(), ' ', '_');
883  subtopic = StringUtils::to_lower_case(subtopic);
884  os << " <xsd:element name=\"" << subtopic << "\" type=\"" << subtopic << "TopicType\" minOccurs=\"0\"/>\n";
885  }
886  os << " </xsd:all>\n";
887  os << " </xsd:complexType>\n\n";
888  for (std::vector<std::string>::const_iterator i = mySubTopics.begin(); i != mySubTopics.end(); ++i) {
889  std::string subtopic = *i;
890  if (subtopic == "Configuration") {
891  continue;
892  }
893  std::replace(subtopic.begin(), subtopic.end(), ' ', '_');
894  subtopic = StringUtils::to_lower_case(subtopic);
895  os << " <xsd:complexType name=\"" << subtopic << "TopicType\">\n";
896  os << " <xsd:all>\n";
897  const std::vector<std::string>& entries = mySubTopicEntries[*i];
898  for (std::vector<std::string>::const_iterator j = entries.begin(); j != entries.end(); ++j) {
899  Option* o = getSecure(*j);
900  std::string type = o->getTypeName();
901  type = StringUtils::to_lower_case(type);
902  if (type == "int[]") {
903  type = "intArray";
904  }
905  if (type == "str[]") {
906  type = "strArray";
907  }
908  os << " <xsd:element name=\"" << *j << "\" type=\"" << type << "OptionType\" minOccurs=\"0\"/>\n";
909  }
910  os << " </xsd:all>\n";
911  os << " </xsd:complexType>\n\n";
912  }
913  os << "</xsd:schema>\n";
914 }
915 
916 
917 void
918 OptionsCont::writeXMLHeader(std::ostream& os, const bool includeConfig) const {
919  time_t rawtime;
920  char buffer [80];
921 
922  os << "<?xml version=\"1.0\"" << SUMOSAXAttributes::ENCODING << "?>\n\n";
923  time(&rawtime);
924  strftime(buffer, 80, "<!-- generated on %F %T by ", localtime(&rawtime));
925  os << buffer << myFullName << "\n";
926  if (myWriteLicense) {
927  os << "This data file and the accompanying materials\n";
928  os << "are made available under the terms of the Eclipse Public License v2.0\n";
929  os << "which accompanies this distribution, and is available at\n";
930  os << "http://www.eclipse.org/legal/epl-v20.html\n";
931  os << "SPDX-License-Identifier: EPL-2.0\n";
932  }
933  if (includeConfig) {
934  writeConfiguration(os, true, false, false, true);
935  }
936  os << "-->\n\n";
937 }
938 
939 
940 bool
941 OptionsCont::isInStringVector(const std::string& optionName,
942  const std::string& itemName) const {
943  if (isSet(optionName)) {
944  std::vector<std::string> values = getStringVector(optionName);
945  return std::find(values.begin(), values.end(), itemName) != values.end();
946  }
947  return false;
948 }
949 
950 
951 /****************************************************************************/
#define WRITE_MESSAGE(msg)
Definition: MsgHandler.h:282
#define WRITE_ERROR(msg)
Definition: MsgHandler.h:288
#define WRITE_WARNING(msg)
Definition: MsgHandler.h:280
std::vector< std::string > StringVector
Definition of a vector of strings.
Definition: Option.h:43
std::vector< int > IntVector
Definition of a vector of ints.
Definition: Option.h:38
std::ostream & operator<<(std::ostream &os, const OptionsCont &oc)
std::string joinToString(const std::vector< T > &v, const T_BETWEEN &between, std::streamsize accuracy=gPrecision)
Definition: ToString.h:269
std::string toString(const T &t, std::streamsize accuracy=gPrecision)
Definition: ToString.h:46
static std::string checkForRelativity(const std::string &filename, const std::string &basePath)
Returns the path from a configuration so that it is accessable from the current working directory.
static bool isReadable(std::string path)
Checks whether the given file is readable.
Definition: FileHelpers.cpp:49
A class representing a single program option.
Definition: Option.h:73
bool isWriteable() const
Returns the information whether the option may be set a further time.
Definition: Option.cpp:142
bool isSet() const
returns the information whether this options holds a valid value
Definition: Option.cpp:67
virtual bool isDefault() const
Returns the information whether the option holds the default value.
Definition: Option.cpp:130
virtual std::string getString() const
Returns the stored string value.
Definition: Option.cpp:85
virtual const IntVector & getIntVector() const
Returns the stored integer vector.
Definition: Option.cpp:97
const std::string & getDescription() const
Returns the description of what this option does.
Definition: Option.cpp:160
virtual bool set(const std::string &v)=0
Stores the given value.
virtual const StringVector & getStringVector() const
Returns the stored string vector.
Definition: Option.cpp:102
void setDescription(const std::string &desc)
Sets the description of what this option does.
Definition: Option.cpp:166
virtual const std::string & getTypeName() const
Returns the mml-type name of this option.
Definition: Option.cpp:172
virtual int getInt() const
Returns the stored integer value.
Definition: Option.cpp:79
virtual double getFloat() const
Returns the stored double value.
Definition: Option.cpp:73
virtual bool getBool() const
Returns the stored boolean value.
Definition: Option.cpp:91
void resetDefault()
Resets the option to be on its default value.
Definition: Option.cpp:154
virtual bool isBool() const
Returns the information whether the option is a bool option.
Definition: Option.cpp:124
virtual std::string getValueString() const =0
Returns the string-representation of the value.
A storage for options typed value containers)
Definition: OptionsCont.h:89
void setAdditionalHelpMessage(const std::string &add)
Sets an additional message to be printed at the begin of the help screen.
~OptionsCont()
Destructor.
Definition: OptionsCont.cpp:69
void unSet(const std::string &name, bool failOnNonExistant=true) const
Marks the option as unset.
void addDescription(const std::string &name, const std::string &subtopic, const std::string &description)
Adds a description for an option.
void doRegister(const std::string &name, Option *v)
Adds an option under the given name.
Definition: OptionsCont.cpp:75
bool isSet(const std::string &name, bool failOnNonExistant=true) const
Returns the information whether the named option is set.
std::vector< std::pair< std::string, std::string > > myCallExamples
list of call examples
Definition: OptionsCont.h:739
bool isWriteable(const std::string &name)
Returns the information whether the named option may be set.
std::map< std::string, std::vector< std::string > > mySubTopicEntries
A map from subtopic to option.
Definition: OptionsCont.h:745
void writeXMLHeader(std::ostream &os, const bool includeConfig=true) const
Writes a standard XML header, including the configuration.
double getFloat(const std::string &name) const
Returns the double-value of the named option (only for Option_Float)
bool set(const std::string &name, const std::string &value)
Sets the given value for the named option.
int getInt(const std::string &name) const
Returns the int-value of the named option (only for Option_Integer)
void writeConfiguration(std::ostream &os, const bool filled, const bool complete, const bool addComments, const bool inComment=false) const
Writes the configuration.
void splitLines(std::ostream &os, std::string what, int offset, int nextOffset)
Writes the given string 'formatted'.
void setApplicationName(const std::string &appName, const std::string &fullName)
Sets the application name.
void printHelpOnTopic(const std::string &topic, int tooLarge, int maxSize, std::ostream &os)
Prints help on the given topic.
std::string myAdditionalMessage
Definition: OptionsCont.h:736
std::vector< std::string > myCopyrightNotices
Definition: OptionsCont.h:742
const IntVector & getIntVector(const std::string &name) const
Returns the list of integer-value of the named option (only for Option_IntVector)
std::vector< std::string > getSynonymes(const std::string &name) const
Returns the synonymes of an option name.
void reportDoubleSetting(const std::string &arg) const
Reports an error that the option has already been set.
std::vector< std::string > mySubTopics
lists of option subtopics and copyright notices
Definition: OptionsCont.h:742
std::string getString(const std::string &name) const
Returns the string-value of the named option (only for Option_String)
bool myWriteLicense
Information whether we should always include license information in file headers.
Definition: OptionsCont.h:754
ItemAddressContType myAddresses
Definition: OptionsCont.h:730
void addSynonyme(const std::string &name1, const std::string &name2, bool isDeprecated=false)
Adds a synonyme for an options name (any order)
Definition: OptionsCont.cpp:96
bool isDefault(const std::string &name) const
Returns the information whether the named option has still the default value.
bool setDefault(const std::string &name, const std::string &value)
Sets the given value for the named option as new default value.
bool exists(const std::string &name) const
Returns the information whether the named option is known.
KnownContType myValues
Definition: OptionsCont.h:733
bool isBool(const std::string &name) const
Returns the information whether the option is a boolean option.
void addCopyrightNotice(const std::string &copyrightLine)
Adds a copyright notice to the help output.
void writeSchema(std::ostream &os)
Writes the xml schema for the configuration.
void clear()
Removes all information from the container.
void setApplicationDescription(const std::string &appDesc)
Sets the application description.
void clearCopyrightNotices()
Removes all copyright information.
std::string convertChar(char abbr) const
Converts an abbreviation into a name.
void addOptionSubTopic(const std::string &topic)
Adds an option subtopic.
bool getBool(const std::string &name) const
Returns the boolean-value of the named option (only for Option_Bool)
const StringVector & getStringVector(const std::string &name) const
Returns the list of string-value of the named option (only for Option_StringVector)
OptionsCont()
Constructor.
Definition: OptionsCont.cpp:63
void printHelp(std::ostream &os)
Prints the help.
std::string getValueString(const std::string &name) const
Returns the string-value of the named option (all options)
std::string myAppDescription
Definition: OptionsCont.h:736
const std::string & getDescription(const std::string &name) const
Returns the option description.
bool setByRootElement(const std::string &name, const std::string &value)
Sets the given value for the option which can handle the given XML root.
std::map< std::string, bool > myDeprecatedSynonymes
A map from deprecated options to a bool indicating whether we warned about deprecation.
Definition: OptionsCont.h:751
static OptionsCont myOptions
The static options container used.
Definition: OptionsCont.h:721
bool checkDependingSuboptions(const std::string &name, const std::string &prefix) const
Checks whether an option is set, which has options with a prefix depending on it.
std::map< std::string, std::string > myXMLDefaults
A map from XML root element to option.
Definition: OptionsCont.h:748
std::string myAppName
some information on the application
Definition: OptionsCont.h:736
void resetWritable()
Resets all options to be writeable.
void addXMLDefault(const std::string &name, const std::string &xmlRoot="")
Adds an XML root element to handle by default. The special root "" denotes the default handler.
static OptionsCont & getOptions()
Retrieves the options.
Definition: OptionsCont.cpp:58
std::string myFullName
Definition: OptionsCont.h:736
Option * getSecure(const std::string &name) const
Returns the named option.
void relocateFiles(const std::string &configuration) const
Modifies file name options according to the configuration path.
bool isInStringVector(const std::string &optionName, const std::string &itemName) const
Returns the named option is a list of string values containing the specified item.
bool processMetaOptions(bool missingOptions)
Checks for help and configuration output, returns whether we should exit.
bool isUsableFileList(const std::string &name) const
Checks whether the named option is usable as a file list (with at least a single file)
void addCallExample(const std::string &example, const std::string &desc)
Add a call example.
static const std::string ENCODING
The encoding of parsed strings.
static std::string urlDecode(const std::string &encoded)
static std::string escapeXML(const std::string &orig, const bool maskDoubleHyphen=false)
Replaces the standard escapes by their XML entities.
static std::string to_lower_case(std::string str)
Transfers the content to lower case.
Definition: StringUtils.cpp:59
static std::string transcodeToLocal(const std::string &utf8String)
convert a string from UTF-8 to the local codepage
static std::string strerror()