Argus Camera Sample Argus Camera Sample

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

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
67 Options::~Options()
68 {
69 }
70
71 bool Options::initialize()
72 {
73 if (m_initialized)
74 return true;
75
76 m_initialized = true;
77
78 PROPAGATE_ERROR(addOption(
79 Option("help", 'h', "",
80 Option::TYPE_ACTION, Option::FLAG_NO_ARGUMENT,
81 "display this help and exit", printHelp, this)));
82 PROPAGATE_ERROR(addOption(
83 Option("exit", 'x', "",
84 Option::TYPE_ACTION, Option::FLAG_NO_ARGUMENT,
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
126 bool Options::requestExit()
127 {
128 m_requestExit = true;
129 return true;
130 }
131
132 bool Options::requestedExit() const
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 */
212 bool Options::usage()
213 {
214 const Option::Type types[] =
215 {
216 Option::TYPE_OPTION,
217 Option::TYPE_ACTION
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