Line data Source code
1 : /****************************************************************************/
2 : // Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo
3 : // Copyright (C) 2001-2024 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 : /****************************************************************************/
14 : /// @file OptionsIO.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Michael Behrisch
17 : /// @date Mon, 17 Dec 2001
18 : ///
19 : // Helper for parsing command line arguments and reading configuration files
20 : /****************************************************************************/
21 : #include <config.h>
22 :
23 : #include <string>
24 : #include <iostream>
25 : #include <cstdlib>
26 : #include <cstring>
27 : #include <xercesc/framework/XMLPScanToken.hpp>
28 : #include <xercesc/parsers/SAXParser.hpp>
29 : #include <xercesc/sax/HandlerBase.hpp>
30 : #include <xercesc/sax/AttributeList.hpp>
31 : #include <xercesc/sax/SAXParseException.hpp>
32 : #include <xercesc/sax/SAXException.hpp>
33 : #include <xercesc/util/PlatformUtils.hpp>
34 : #include "OptionsIO.h"
35 : #include "OptionsCont.h"
36 : #include "OptionsLoader.h"
37 : #include "OptionsParser.h"
38 : #include <utils/common/FileHelpers.h>
39 : #include <utils/common/MsgHandler.h>
40 : #include <utils/common/StringUtils.h>
41 : #ifdef HAVE_ZLIB
42 : #include <foreign/zstr/zstr.hpp>
43 : #endif
44 : #include <utils/xml/IStreamInputSource.h>
45 :
46 :
47 : // ===========================================================================
48 : // static member definitions
49 : // ===========================================================================
50 : std::vector<std::string> OptionsIO::myArgs;
51 : std::chrono::time_point<std::chrono::system_clock> OptionsIO::myLoadTime;
52 :
53 :
54 : // ===========================================================================
55 : // method definitions
56 : // ===========================================================================
57 : void
58 56841 : OptionsIO::setArgs(int argc, char** argv) {
59 : myArgs.clear();
60 791827 : for (int i = 0; i < argc; i++) {
61 1469972 : myArgs.push_back(StringUtils::transcodeFromLocal(argv[i]));
62 : }
63 56841 : }
64 :
65 :
66 : void
67 1061 : OptionsIO::setArgs(const std::vector<std::string>& args) {
68 1061 : myArgs.resize(1); // will insert an empty string if no first element is there
69 1061 : myArgs.insert(myArgs.end(), args.begin(), args.end());
70 1061 : }
71 :
72 :
73 : void
74 57902 : OptionsIO::getOptions(const bool commandLineOnly) {
75 57902 : myLoadTime = std::chrono::system_clock::now();
76 57902 : if (myArgs.size() == 2 && myArgs[1][0] != '-') {
77 : // special case only one parameter, check who can handle it
78 48 : if (OptionsCont::getOptions().setByRootElement(getRoot(myArgs[1]), myArgs[1])) {
79 24 : if (!commandLineOnly) {
80 24 : loadConfiguration();
81 : }
82 24 : return;
83 : }
84 : }
85 : // preparse the options
86 : // (maybe another configuration file was chosen)
87 57878 : if (!OptionsParser::parse(myArgs, true)) {
88 132 : throw ProcessError(TL("Could not parse commandline options."));
89 : }
90 65345 : if (!commandLineOnly || OptionsCont::getOptions().isSet("save-configuration", false)) {
91 : // read the configuration when everything's ok
92 50279 : loadConfiguration();
93 : }
94 : }
95 :
96 :
97 : void
98 57836 : OptionsIO::loadConfiguration() {
99 57836 : OptionsCont& oc = OptionsCont::getOptions();
100 115672 : if (oc.exists("configuration-file") && oc.isSet("configuration-file")) {
101 22368 : const std::string path = oc.getString("configuration-file");
102 22368 : if (!FileHelpers::isReadable(path)) {
103 0 : throw ProcessError(TLF("Could not access configuration '%'.", oc.getString("configuration-file")));
104 : }
105 22368 : const bool verbose = !oc.exists("verbose") || oc.getBool("verbose");
106 11184 : if (verbose) {
107 313 : PROGRESS_BEGIN_MESSAGE(TL("Loading configuration"));
108 : }
109 11184 : oc.resetWritable();
110 : // build parser
111 11184 : XERCES_CPP_NAMESPACE::SAXParser parser;
112 11184 : parser.setValidationScheme(XERCES_CPP_NAMESPACE::SAXParser::Val_Never);
113 11184 : parser.setDisableDefaultEntityResolution(true);
114 : // start the parsing
115 11184 : OptionsLoader handler(OptionsCont::getOptions());
116 : try {
117 11184 : parser.setDocumentHandler(&handler);
118 11184 : parser.setErrorHandler(&handler);
119 11184 : parser.parse(StringUtils::transcodeToLocal(path).c_str());
120 11184 : if (handler.errorOccurred()) {
121 21 : throw ProcessError(TLF("Could not load configuration '%'.", path));
122 : }
123 7 : } catch (const XERCES_CPP_NAMESPACE::XMLException& e) {
124 0 : throw ProcessError("Could not load configuration '" + path + "':\n " + StringUtils::transcode(e.getMessage()));
125 0 : }
126 11177 : oc.relocateFiles(path);
127 11177 : if (verbose) {
128 102 : PROGRESS_DONE_MESSAGE();
129 : }
130 11191 : }
131 57829 : if (myArgs.size() > 2) {
132 : // reparse the options (overwrite the settings from the configuration file)
133 57663 : oc.resetWritable();
134 57663 : if (!OptionsParser::parse(myArgs)) {
135 8 : throw ProcessError(TL("Could not parse commandline options."));
136 : }
137 : }
138 57825 : }
139 :
140 :
141 : std::string
142 24 : OptionsIO::getRoot(const std::string& filename) {
143 : // build parser
144 24 : XERCES_CPP_NAMESPACE::SAXParser parser;
145 24 : parser.setValidationScheme(XERCES_CPP_NAMESPACE::SAXParser::Val_Never);
146 24 : parser.setDisableDefaultEntityResolution(true);
147 : // start the parsing
148 24 : OptionsLoader handler(OptionsCont::getOptions());
149 : try {
150 24 : parser.setDocumentHandler(&handler);
151 24 : parser.setErrorHandler(&handler);
152 : XERCES_CPP_NAMESPACE::XMLPScanToken token;
153 72 : if (!FileHelpers::isReadable(filename) || FileHelpers::isDirectory(filename)) {
154 0 : throw ProcessError(TLF("Could not open '%'.", filename));
155 : }
156 : #ifdef HAVE_ZLIB
157 48 : zstr::ifstream istream(StringUtils::transcodeToLocal(filename).c_str(), std::fstream::in | std::fstream::binary);
158 : IStreamInputSource inputStream(istream);
159 24 : const bool result = parser.parseFirst(inputStream, token);
160 : #else
161 : const bool result = parser.parseFirst(StringUtils::transcodeToLocal(filename).c_str(), token);
162 : #endif
163 24 : if (!result) {
164 0 : throw ProcessError(TLF("Can not read XML-file '%'.", filename));
165 : }
166 24 : while (parser.parseNext(token) && handler.getItem() == "");
167 24 : if (handler.errorOccurred()) {
168 0 : throw ProcessError(TLF("Could not load '%'.", filename));
169 : }
170 24 : } catch (const XERCES_CPP_NAMESPACE::XMLException& e) {
171 0 : throw ProcessError("Could not load '" + filename + "':\n " + StringUtils::transcode(e.getMessage()));
172 0 : }
173 24 : return handler.getItem();
174 24 : }
175 :
176 :
177 : /****************************************************************************/
|