vsg  1.1.0
VulkanSceneGraph library
CommandLine.h
1 #pragma once
2 
3 /* <editor-fold desc="MIT License">
4 
5 Copyright(c) 2018 Robert Osfield
6 
7 Permission 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 
9 The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10 
11 THE 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 
22 namespace 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:34