Argus Camera Sample
Argus Camera Sample
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Options.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016, NVIDIA CORPORATION. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * * Redistributions of source code must retain the above copyright
8  * notice, this list of conditions and the following disclaimer.
9  * * Redistributions in binary form must reproduce the above copyright
10  * notice, this list of conditions and the following disclaimer in the
11  * documentation and/or other materials provided with the distribution.
12  * * Neither the name of NVIDIA CORPORATION nor the names of its
13  * contributors may be used to endorse or promote products derived
14  * from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <getopt.h>
30 #include <stdint.h>
31 #include <string.h>
32 
33 #include <sstream>
34 
35 #include "Error.h"
36 #include "Options.h"
37 
38 namespace ArgusSamples
39 {
40 
41 /* static */ bool Options::printHelp(void *userPtr, const char *optArg)
42 {
43  Options *options = reinterpret_cast<Options*>(userPtr);
44 
45  PROPAGATE_ERROR(options->usage());
46  PROPAGATE_ERROR(options->requestExit());
47 
48  return true;
49 }
50 
51 /* static */ bool Options::exit(void *userPtr, const char *optArg)
52 {
53  Options *options = reinterpret_cast<Options*>(userPtr);
54 
55  PROPAGATE_ERROR(options->requestExit());
56 
57  return true;
58 }
59 
60 Options::Options(const char *programName)
61  : m_initialized(false)
62  , m_requestExit(false)
63  , m_programName(programName)
64 {
65 }
66 
68 {
69 }
70 
72 {
73  if (m_initialized)
74  return true;
75 
76  m_initialized = true;
77 
78  PROPAGATE_ERROR(addOption(
79  Option("help", 'h', "",
81  "display this help and exit", printHelp, this)));
82  PROPAGATE_ERROR(addOption(
83  Option("exit", 'x', "",
85  "exit from the program", exit, this)));
86 
87  return true;
88 }
89 
90 bool Options::addOption(const Option &option, void *userPtr)
91 {
92  PROPAGATE_ERROR(initialize());
93 
94  if (userPtr)
95  {
96  Option optionCopy = option;
97  optionCopy.m_userPtr = userPtr;
98 
99  m_options.push_back(optionCopy);
100  }
101  else
102  {
103  m_options.push_back(option);
104  }
105 
106  return true;
107 }
108 
109 bool Options::addOptions(size_t count, const Option *options, void *userPtr)
110 {
111  for (size_t i = 0; i < count; ++i)
112  {
113  PROPAGATE_ERROR(addOption(options[i], userPtr));
114  }
115  return true;
116 }
117 
118 bool Options::addDescription(const char *description)
119 {
120  PROPAGATE_ERROR(initialize());
121 
122  m_description += description;
123  return true;
124 }
125 
127 {
128  m_requestExit = true;
129  return true;
130 }
131 
133 {
134  return m_requestExit;
135 }
136 
137 bool Options::parse(const int argc, char * const *argv)
138 {
139  std::string optString;
140  std::vector<option> options;
141  std::vector<Option>::iterator it;
142 
143  PROPAGATE_ERROR(initialize());
144 
145  // build the long option struct and the short option string
146  for (it = m_options.begin(); it < m_options.end(); ++it)
147  {
148  option getoptOption;
149 
150  memset(&getoptOption, 0, sizeof(getoptOption));
151 
152  getoptOption.name = it->m_name.c_str();
153  if (it->m_flags == Option::FLAG_NO_ARGUMENT)
154  getoptOption.has_arg = no_argument;
155  else if (it->m_flags == Option::FLAG_OPTIONAL_ARGUMENT)
156  getoptOption.has_arg = optional_argument;
157  else if (it->m_flags == Option::FLAG_REQUIRED_ARGUMENT)
158  getoptOption.has_arg = required_argument;
159  else
160  ORIGINATE_ERROR("Unhandled flag");
161  getoptOption.flag = NULL;
162  getoptOption.val = it->m_shortName;
163 
164  options.push_back(getoptOption);
165 
166  if (it->m_shortName)
167  {
168  optString += it->m_shortName;
169  if (it->m_flags == Option::FLAG_REQUIRED_ARGUMENT)
170  optString += ":";
171  else if (it->m_flags == Option::FLAG_OPTIONAL_ARGUMENT)
172  optString += "::";
173  }
174  }
175 
176  // The last element of the array has to be filled with zeros
177  option lastElement;
178  memset(&lastElement, 0, sizeof(lastElement));
179  options.push_back(lastElement);
180 
181  while (!m_requestExit)
182  {
183  int optionIndex = 0;
184  int c = getopt_long(argc, argv, optString.c_str(), options.data(), &optionIndex);
185 
186  if (c == -1)
187  break;
188 
189  for (it = m_options.begin(); it < m_options.end(); ++it)
190  {
191  if (((c == 0) && (it->m_name == options[optionIndex].name)) ||
192  ((c != 0) && (it->m_shortName == c)))
193  {
194  PROPAGATE_ERROR(it->m_function(it->m_userPtr, optarg));
195  break;
196  }
197  }
198 
199  if (it == m_options.end())
200  {
201  PROPAGATE_ERROR(usage());
202  ORIGINATE_ERROR("Error parsing command line");
203  }
204  }
205 
206  return true;
207 }
208 
209 /**
210  * Print the usage message
211  */
213 {
214  const Option::Type types[] =
215  {
218  };
219  const size_t lineLength = 80;
220  const size_t optionLength = 24;
221  const size_t helpTextLength = lineLength - optionLength;
222  std::ostringstream usage;
223 
224  usage << "Usage: " << m_programName << " [OPTION]... [ACTION]... \n";
225  usage << m_description;
226  usage << "Options are set and actions are executed in the order they occur. Multiple\n";
227  usage << "actions can be executed.\n";
228  usage << "Mandatory arguments to long options are mandatory for short options too.\n";
229 
230  for (uint32_t typeIndex = 0; typeIndex < sizeof(types) / sizeof(types[0]); ++typeIndex)
231  {
232  const Option::Type type = types[typeIndex];
233 
234  if (type == Option::TYPE_OPTION)
235  usage << "\nOptions:\n";
236  else if (type == Option::TYPE_ACTION)
237  usage << "\nActions:\n";
238  else
239  ORIGINATE_ERROR("Internal error, unhandled type\n");
240 
241  for (std::vector<Option>::iterator it = m_options.begin(); it < m_options.end(); ++it)
242  {
243  if (it->m_type == type)
244  {
245  std::ostringstream optionUsage;
246 
247  // print the short option
248  if (it->m_shortName)
249  optionUsage << " -" << (char)it->m_shortName << ", ";
250  else
251  optionUsage << " ";
252 
253  // print the long option
254  optionUsage << "--" << it->m_name;
255 
256  if ((it->m_flags != Option::FLAG_NO_ARGUMENT) && it->m_argument.empty())
257  ORIGINATE_ERROR("Internal error, argument string required\n");
258 
259  if (it->m_flags == Option::FLAG_REQUIRED_ARGUMENT)
260  optionUsage << "=" << it->m_argument << "";
261  else if (it->m_flags == Option::FLAG_OPTIONAL_ARGUMENT)
262  optionUsage << "[=" << it->m_argument << "]";
263 
264  // if the option is too long insert a new-line
265  if (optionUsage.str().length() >= optionLength)
266  {
267  optionUsage << std::endl;
268  optionUsage << std::string(optionLength, ' ');
269  }
270  else
271  {
272  // insert spaces until option length limit
273  optionUsage << std::string(optionLength - optionUsage.str().length(), ' ');
274  }
275  usage << optionUsage.str();
276 
277  // Build the help text
278  std::string helpText(it->m_usage);
279 
280  // split help message if needed
281  while (helpText.length() > helpTextLength)
282  {
283  // find the last space
284  size_t lastSpace = helpText.find_last_of(' ', helpTextLength);
285 
286  // add until space
287  usage << helpText.substr(0, lastSpace) << std::endl <<
288  std::string(optionLength, ' ');
289  // continue with rest
290  helpText = helpText.substr(lastSpace + 1, std::string::npos);
291  }
292 
293  usage << helpText << std::endl;
294  }
295  }
296  }
297 
298  printf("%s", usage.str().c_str());
299 
300  return true;
301 }
302 
303 }; // namespace ArgusSamples