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