vsg 1.1.3
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 char** argv() { return _argv; }
50
51 char* operator[](int i) { return _argv[i]; }
52
53 template<typename T>
54 bool read(int& i, T& v)
55 {
56 const int num_args = *_argc;
57 if (i >= num_args) return false;
58
59 if constexpr (std::is_same_v<T, std::string>)
60 {
61 v = _argv[i++];
62 return true;
63 }
64 if constexpr (std::is_same_v<T, vsg::Path>)
65 {
66 v = _argv[i++];
67 return true;
68 }
69 else
70 {
71 std::size_t num_elements = type_num_elements(v);
72
73 _istr.clear();
74 if (num_elements == 1)
75 {
76 _istr.str(_argv[i]);
77 ++i;
78 }
79 else
80 {
81 std::string str;
82 for (; num_elements > 0 && i < num_args; --num_elements, ++i)
83 {
84 str += ' ';
85 str += _argv[i];
86 }
87
88 _istr.str(str);
89 }
90 _istr >> v;
91
92 return (!_istr.fail());
93 }
94 }
95
96 void remove(int i, int num)
97 {
98 if (i >= *_argc) return;
99
100 int source = i + num;
101 if (source >= *_argc)
102 {
103 // removed section is at end of argv so just reset argc to i
104 *_argc = i;
105 }
106 else
107 {
108 // shift all the remaining entries down to fill the removed space
109 for (; source < *_argc; ++i, ++source)
110 {
111 _argv[i] = _argv[source];
112 }
113
114 *_argc -= num;
115 }
116 // Preserve C invariant that argv ends with a null pointer
117 _argv[*_argc] = nullptr;
118 }
119
120 template<typename... Args>
121 bool read(const std::string& match, Args&... args)
122 {
123 for (int i = 1; i < *_argc; ++i)
124 {
125 if (match == _argv[i])
126 {
127 int start = i;
128 ++i;
129
130 // match any parameters
131 bool result = (read(i, args) && ...);
132
133 if (result)
134 {
135 remove(start, i - start);
136 }
137 else
138 {
139 std::string parameters = ((match + " ") + ... + type_name(args));
140 std::string errorMessage = std::string("Failed to match command line required parameters for ") + parameters;
141 _errorMessages.push_back(errorMessage);
142 }
143
144 return result;
145 }
146 }
147 return false;
148 }
149
150 template<typename... Args>
151 bool read(std::initializer_list<std::string> matches, Args&... args)
152 {
153 bool result = false;
154 for (auto str : matches) result = read(str, args...) | result;
155 return result;
156 }
157
158 template<typename T, typename... Args>
159 T value(T defaultValue, const std::string& match, Args&... args)
160 {
161 T v{defaultValue};
162 read(match, args..., v);
163 return v;
164 }
165
166 template<typename T, typename... Args>
167 T value(T defaultValue, std::initializer_list<std::string> matches, Args&... args)
168 {
169 T v{defaultValue};
170 read(matches, args..., v);
171 return v;
172 }
173
174 template<typename T>
175 bool readAndAssign(const std::string& match, Options* options)
176 {
177 if constexpr (std::is_same_v<T, void>)
178 {
179 if (options && read(std::string("--") + match))
180 {
181 options->setValue(match, true);
182 return true;
183 }
184 }
185 else
186 {
187 T v;
188 if (options && read(std::string("--") + match, v))
189 {
190 options->setValue(match, v);
191 return true;
192 }
193 }
194 return false;
195 }
196
197 bool read(Options* options);
198
199 using Messages = std::vector<std::string>;
200 bool errors() const { return !_errorMessages.empty(); }
201
202 Messages& getErrorMessages() { return _errorMessages; }
203 const Messages& getErrorMessages() const { return _errorMessages; }
204
205 int writeErrorMessages(std::ostream& out) const
206 {
207 if (_errorMessages.empty()) return 1;
208 for (auto message : _errorMessages) out << message << std::endl;
209 return 0;
210 }
211
212 protected:
213 int* _argc;
214 char** _argv;
215 std::istringstream _istr;
216 Messages _errorMessages;
217 };
218
219 // specialize handling of bool parameter
220 template<>
221 inline bool CommandLine::read(int& i, bool& v)
222 {
223 const int num_args = *_argc;
224 if (i >= num_args) return false;
225
226 const char* str = _argv[i];
227 if (!str) return false;
228
229 if (std::strcmp(str, "true") == 0 || std::strcmp(str, "True") == 0 || std::strcmp(str, "TRUE") == 0 || std::strcmp(str, "1") == 0)
230 {
231 v = true;
232 ++i;
233 return true;
234 }
235
236 if (std::strcmp(str, "false") == 0 || std::strcmp(str, "False") == 0 || std::strcmp(str, "FALSE") == 0 || std::strcmp(str, "0") == 0)
237 {
238 v = false;
239 ++i;
240 return true;
241 }
242 return false;
243 }
244
245 // specialize matching of bool parameters
246 template<>
247 inline bool CommandLine::read(const std::string& match, bool& v)
248 {
249 for (int i = 1; i < *_argc; ++i)
250 {
251 if (match == _argv[i])
252 {
253 int start = i;
254 ++i;
255
256 // match any parameters
257 if (!read(i, v))
258 {
259 v = true;
260 }
261
262 remove(start, i - start);
263
264 return true;
265 }
266 }
267 return false;
268 }
269
270} // namespace vsg
Definition CommandLine.h:44
void setValue(const std::string &key, const T &value)
Definition Value.h:159
Class for passing IO related options to vsg::read/write calls.
Definition Options.h:37