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 OptionsParser.cpp
15 : /// @author Daniel Krajzewicz
16 : /// @author Jakob Erdmann
17 : /// @author Michael Behrisch
18 : /// @date Mon, 17 Dec 2001
19 : ///
20 : // Parses the command line arguments
21 : /****************************************************************************/
22 : #include <config.h>
23 :
24 : #include <iostream>
25 : #include <cstring>
26 : #include "Option.h"
27 : #include "OptionsCont.h"
28 : #include "OptionsParser.h"
29 : #include <utils/common/UtilExceptions.h>
30 : #include <utils/common/MsgHandler.h>
31 :
32 :
33 : // ===========================================================================
34 : // method definitions
35 : // ===========================================================================
36 : bool
37 115541 : OptionsParser::parse(const std::vector<std::string>& args, const bool ignoreAppenders) {
38 115541 : bool ok = true;
39 115541 : const int argc = (int)args.size();
40 1000362 : for (int i = 1; i < argc;) {
41 : try {
42 : int add;
43 : // try to set the current option
44 884821 : if (i < argc - 1) {
45 827874 : add = check(args[i], &args[i + 1], ok, ignoreAppenders);
46 : } else {
47 56947 : add = check(args[i], nullptr, ok, ignoreAppenders);
48 : }
49 884773 : i += add;
50 48 : } catch (ProcessError& e) {
51 96 : WRITE_ERROR("On processing option '" + args[i] + "':\n " + e.what());
52 48 : i++;
53 48 : ok = false;
54 48 : }
55 : }
56 115541 : return ok;
57 : }
58 :
59 :
60 : int
61 884821 : OptionsParser::check(const std::string& arg1, const std::string* const arg2, bool& ok, const bool ignoreAppenders) {
62 : // the first argument should be an option
63 : // (only the second may be a free string)
64 884821 : if (!checkParameter(arg1)) {
65 33 : ok = false;
66 33 : return 1;
67 : }
68 :
69 884788 : OptionsCont& oc = OptionsCont::getOptions();
70 884788 : const bool append = arg1[0] == '+';
71 : // process not abbreviated switches
72 884788 : if (append || arg1[1] == '-') {
73 1280582 : const std::string tmp(arg1.substr(append ? 1 : 2));
74 640306 : const std::string::size_type idx1 = tmp.find('=');
75 640306 : if (append && ignoreAppenders) {
76 19 : return idx1 == std::string::npos ? 2 : 1;
77 : }
78 : // check whether a parameter was submitted
79 640291 : if (idx1 != std::string::npos) {
80 87761 : ok &= oc.set(tmp.substr(0, idx1), tmp.substr(idx1 + 1), append);
81 : } else {
82 552542 : if (arg2 == nullptr || (oc.isBool(tmp) && (*arg2)[0] == '-')) {
83 270203 : ok &= oc.set(tmp, "true");
84 : } else {
85 282357 : ok &= oc.set(tmp, *arg2, append);
86 282357 : return 2;
87 : }
88 : }
89 357886 : return 1;
90 : }
91 : // go through the abbreviated switches
92 244482 : const int len = (int)arg1.size();
93 278596 : for (int i = 1; i < len; i++) {
94 : // set boolean switches
95 244482 : const std::string abbr = arg1.substr(i, 1);
96 244482 : if (oc.isBool(abbr)) {
97 34114 : if (arg2 == nullptr || (*arg2)[0] == '-' || i != len - 1) {
98 34114 : ok &= oc.set(abbr, "true");
99 : } else {
100 0 : ok &= oc.set(abbr, *arg2);
101 0 : return 2;
102 : }
103 : // set non-boolean switches
104 : } else {
105 : // check whether the parameter comes directly after the switch
106 : // and process if so
107 210368 : if (arg2 == nullptr || i != len - 1) {
108 8872 : ok &= processNonBooleanSingleSwitch(oc, arg1.substr(i), append);
109 8872 : return 1;
110 : // process parameter following after a space
111 : } else {
112 201496 : ok &= oc.set(abbr, *arg2, append);
113 : // option name and attribute were in two arguments
114 201496 : return 2;
115 : }
116 : }
117 : }
118 : // all switches within the current argument were boolean switches
119 : return 1;
120 : }
121 :
122 :
123 : bool
124 8872 : OptionsParser::processNonBooleanSingleSwitch(OptionsCont& oc, const std::string& arg, const bool append) {
125 8872 : if (arg[1] == '=') {
126 8866 : if (arg.size() < 3) {
127 0 : WRITE_ERRORF(TL("Missing value for parameter '%'."), arg.substr(0, 1));
128 0 : return false;
129 : } else {
130 17732 : return oc.set(arg.substr(0, 1), arg.substr(2), append);
131 : }
132 : } else {
133 6 : if (arg.size() < 2) {
134 3 : WRITE_ERRORF(TL("Missing value for parameter '%'."), arg);
135 1 : return false;
136 : } else {
137 10 : return oc.set(arg.substr(0, 1), arg.substr(1), append);
138 : }
139 : }
140 : }
141 :
142 :
143 : bool
144 884821 : OptionsParser::checkParameter(const std::string& arg1) {
145 884821 : if (arg1[0] != '-' && arg1[0] != '+') {
146 75 : WRITE_ERRORF(TL("The parameter '%' is not allowed in this context.\n Switch or parameter name expected."), arg1);
147 25 : return false;
148 : }
149 884796 : if ((arg1[0] == '-' && arg1[1] == '+') || (arg1[0] == '+' && arg1[1] == '-')) {
150 24 : WRITE_ERRORF(TL("Mixed parameter syntax in '%'."), arg1);
151 8 : return false;
152 : }
153 : return true;
154 : }
155 :
156 :
157 : /****************************************************************************/
|