vsg: include/vsg/utils/CommandLine.h Source File

vsg 1.1.13 VulkanSceneGraph library

Loading...
Searching...
No Matches
CommandLine.h
1#pragma once
2
3/* <editor-fold desc="MIT License">
4
5Copyright(c) 2018 Robert Osfield
6
7Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
9The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
11THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
12
13</editor-fold> */
14
15#include <vsg/core/Export.h>
16#include <vsg/core/type_name.h>
17#include <vsg/io/Options.h>
18#include <vsg/io/stream.h>
19
20#include <vector>
21
22namespace vsg
23{
24
25 template<typename T>
26 constexpr std::size_t type_num_elements(T) noexcept { return 1; }
27 template<typename T>
28 constexpr std::size_t type_num_elements(const t_vec2<T>&) noexcept { return 2; }
29 template<typename T>
30 constexpr std::size_t type_num_elements(const t_vec3<T>&) noexcept { return 3; }
31 template<typename T>
32 constexpr std::size_t type_num_elements(const t_vec4<T>&) noexcept { return 4; }
33 template<typename T>
34 constexpr std::size_t type_num_elements(const t_mat4<T>&) noexcept { return 16; }
35 template<typename T, typename R>
36 constexpr std::size_t type_num_elements(const std::pair<T, R>&) noexcept { return 2; }
37
38 // forward declare
39 class Options;
40
43 class VSG_DECLSPEC CommandLine
44 {
45 public:
46 CommandLine(int* argc, char** argv);
47
48 int& argc() { return *_argc; }
49 const int& argc() const { return *_argc; }
50
51 char** argv() { return _argv; }
52 const char* const* argv() const { return _argv; }
53
54 char* operator[](int i) { return _argv[i]; }
55 const char* operator[](int i) const { return _argv[i]; }
56
57 template<typename T>
58 bool read(int& i, T& v)
59 {
60 const int num_args = *_argc;
61 if (i >= num_args) return false;
62
63 if constexpr (std::is_same_v<T, std::string>)
64 {
65 v = _argv[i++];
66 return true;
67 }
68 if constexpr (std::is_same_v<T, vsg::Path>)
69 {
70 v = _argv[i++];
71 return true;
72 }
73 else
74 {
75 std::size_t num_elements = type_num_elements(v);
76
77 _istr.clear();
78 if (num_elements == 1)
79 {
80 _istr.str(_argv[i]);
81 ++i;
82 }
83 else
84 {
85 std::string str;
86 for (; num_elements > 0 && i < num_args; --num_elements, ++i)
87 {
88 str += ' ';
89 str += _argv[i];
90 }
91
92 _istr.str(str);
93 }
94 _istr >> v;
95
96 return (!_istr.fail());
97 }
98 }
99
100 void remove(int i, int num)
101 {
102 if (i >= *_argc) return;
103
104 int source = i + num;
105 if (source >= *_argc)
106 {
107 // removed section is at end of argv so just reset argc to i
108 *_argc = i;
109 }
110 else
111 {
112 // shift all the remaining entries down to fill the removed space
113 for (; source < *_argc; ++i, ++source)
114 {
115 _argv[i] = _argv[source];
116 }
117
118 *_argc -= num;
119 }
120 // Preserve C invariant that argv ends with a null pointer
121 _argv[*_argc] = nullptr;
122 }
123
124 template<typename... Args>
125 bool read(const std::string& match, Args&... args)
126 {
127 for (int i = 1; i < *_argc; ++i)
128 {
129 if (match == _argv[i])
130 {
131 int start = i;
132 ++i;
133
134 // match any parameters
135 bool result = (read(i, args) && ...);
136
137 if (result)
138 {
139 remove(start, i - start);
140 }
141 else
142 {
143 std::string parameters = (match + ... + space_type_name(args));
144 std::string errorMessage = std::string("Failed to match command line required parameters for ") + parameters;
145 _errorMessages.push_back(errorMessage);
146 }
147
148 return result;
149 }
150 }
151 return false;
152 }
153
154 template<typename... Args>
155 bool read(std::initializer_list<std::string> matches, Args&... args)
156 {
157 bool result = false;
158 for (auto str : matches) result = read(str, args...) | result;
159 return result;
160 }
161
162 template<typename T, typename... Args>
163 T value(T defaultValue, const std::string& match, Args&... args)
164 {
165 T v{defaultValue};
166 read(match, args..., v);
167 return v;
168 }
169
170 template<typename T, typename... Args>
171 T value(T defaultValue, std::initializer_list<std::string> matches, Args&... args)
172 {
173 T v{defaultValue};
174 read(matches, args..., v);
175 return v;
176 }
177
178 template<typename T>
179 bool readAndAssign(const std::string& match, Options* options)
180 {
181 if constexpr (std::is_same_v<T, void>)
182 {
183 if (options && read(std::string("--") + match))
184 {
185 options->setValue(match, true);
186 return true;
187 }
188 }
189 else
190 {
191 T v;
192 if (options && read(std::string("--") + match, v))
193 {
194 options->setValue(match, v);
195 return true;
196 }
197 }
198 return false;
199 }
200
202 bool read(Options* options);
203
204 using Messages = std::vector<std::string>;
205 bool errors() const { return !_errorMessages.empty(); }
206
207 Messages& getErrorMessages() { return _errorMessages; }
208 const Messages& getErrorMessages() const { return _errorMessages; }
209
210 int writeErrorMessages(std::ostream& out) const
211 {
212 if (_errorMessages.empty()) return 1;
213 for (const auto& message : _errorMessages) out << message << std::endl;
214 return 0;
215 }
216
217 protected:
218 int* _argc;
219 char** _argv;
220 std::istringstream _istr;
221 Messages _errorMessages;
222 };
223
224 // specialize handling of bool parameter
225 template<>
226 inline bool CommandLine::read(int& i, bool& v)
227 {
228 const int num_args = *_argc;
229 if (i >= num_args) return false;
230
231 const char* str = _argv[i];
232 if (!str) return false;
233
234 if (std::strcmp(str, "true") == 0 || std::strcmp(str, "True") == 0 || std::strcmp(str, "TRUE") == 0 || std::strcmp(str, "1") == 0)
235 {
236 v = true;
237 ++i;
238 return true;
239 }
240
241 if (std::strcmp(str, "false") == 0 || std::strcmp(str, "False") == 0 || std::strcmp(str, "FALSE") == 0 || std::strcmp(str, "0") == 0)
242 {
243 v = false;
244 ++i;
245 return true;
246 }
247 return false;
248 }
249
250 // specialize matching of bool parameters
251 template<>
252 inline bool CommandLine::read(const std::string& match, bool& v)
253 {
254 for (int i = 1; i < *_argc; ++i)
255 {
256 if (match == _argv[i])
257 {
258 int start = i;
259 ++i;
260
261 // match any parameters
262 if (!read(i, v))
263 {
264 v = true;
265 }
266
267 remove(start, i - start);
268
269 return true;
270 }
271 }
272 return false;
273 }
274
275 inline std::ostream& operator<<(std::ostream& output, const CommandLine& arguments)
276 {
277 for (int i = 0; i < arguments.argc(); ++i)
278 {
279 if (i > 0) output << ' ';
280 output << arguments[i];
281 }
282 return output;
283 }
284
285} // namespace vsg
vsg::CommandLine
Definition CommandLine.h:44
vsg::CommandLine::read
bool read(Options *options)
deprecated: provided for backwards compatibility, use vsg::Options::readOptions(arguments)
vsg::Object::setValue
void setValue(const std::string &key, const T &value)
Definition Value.h:172
vsg::Options
Class for passing IO related options to vsg::read/write calls.
Definition Options.h:37
vsg::t_mat4
t_mat4 template class that represents a 4x4 matrix.
Definition mat4.h:25
vsg::t_vec2
t_vec2 template class that represents a 2D vector
Definition vec2.h:39
vsg::t_vec3
t_vec3 template class that represents a 3D vector
Definition vec3.h:34
vsg::t_vec4
t_vec4 template class that represents a 4D vector
Definition vec4.h:35