Visual Servoing Platform version 3.7.0
Loading...
Searching...
No Matches
vpParseArgv.cpp
1/*
2 * This file contains a procedure that handles table-based
3 * argv-argc parsing.
4 *
5 * Copyright 1990 Regents of the University of California
6 * Permission to use, copy, modify, and distribute this
7 * software and its documentation for any purpose and without
8 * fee is hereby granted, provided that the above copyright
9 * notice appear in all copies. The University of California
10 * makes no representations about the suitability of this
11 * software for any purpose. It is provided "as is" without
12 * express or implied warranty.
13 *
14 * This file has been modified to not rely on tcl, tk or X11.
15 * Based on tkArgv.c from tk2.3 :
16 *
17 * Modifications by Peter Neelin (November 27, 1992)
18 * Modifications by Fabien Spindler (June 20, 2006)
19 */
20
25
26#include <ctype.h>
27#include <math.h>
28#include <stdint.h>
29#include <stdio.h>
30#include <stdlib.h>
31#include <string.h>
32#include <visp3/io/vpParseArgv.h>
33
35
36/*
37 * Default table of argument descriptors. These are normally available
38 * in every application.
39 */
40
41 vpParseArgv::vpArgvInfo vpParseArgv::defaultTable[2] = {
42 {"-help", ARGV_HELP, (char *)nullptr, (char *)nullptr, "Print summary of command-line options and abort.\n"},
43 {nullptr, ARGV_END, (char *)nullptr, (char *)nullptr, (char *)nullptr} };
44
45int (*handlerProc1)(const char *dst, const char *key, const char *argument);
46int (*handlerProc2)(const char *dst, const char *key, int valargc, const char **argument);
47
70bool vpParseArgv::parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
71
72{
73 vpArgvInfo *infoPtr; /* Pointer to the current entry in the
74 * table of argument descriptions. */
75 vpArgvInfo *matchPtr; /* Descriptor that matches current argument. */
76 const char *curArg; /* Current argument */
77 char c; /* Second character of current arg (used for
78 * quick check for matching; use 2nd char.
79 * because first char. will almost always
80 * be '-'). */
81 int srcIndex; /* Location from which to read next argument
82 * from argv. */
83 int dstIndex; /* Index into argv to which next unused
84 * argument should be copied (never greater
85 * than srcIndex). */
86 int argc; /* # arguments in argv still to process. */
87 size_t length; /* Number of characters in current argument. */
88 unsigned long long nargs; /* Number of following arguments to get. */
89
90/* Macro to optionally print errors */
91#define FPRINTF \
92 if (!(flags & ARGV_NO_PRINT)) \
93 (void)fprintf
94
95 if (flags & ARGV_DONT_SKIP_FIRST_ARG) {
96 srcIndex = dstIndex = 0;
97 argc = *argcPtr;
98 }
99 else {
100 srcIndex = dstIndex = 1;
101 argc = *argcPtr - 1;
102 }
103
104 while (argc > 0) {
105 curArg = argv[srcIndex];
106 srcIndex++;
107 argc--;
108 c = curArg[1];
109 length = strlen(curArg);
110
111 /*
112 * Loop throught the argument descriptors searching for one with
113 * the matching key string. If found, leave a pointer to it in
114 * matchPtr.
115 */
116
117 matchPtr = nullptr;
118 for (unsigned int i = 0; i < 2; ++i) {
119 if (i == 0) {
120 infoPtr = argTable;
121 }
122 else {
123 infoPtr = defaultTable;
124 }
125 for (; infoPtr->type != ARGV_END; ++infoPtr) {
126 if (infoPtr->key != nullptr) {
127 bool stop_for_loop = false;
128 if ((infoPtr->key[1] != c) || (strncmp(infoPtr->key, curArg, length) != 0)) {
129 stop_for_loop = true;
130 }
131 if (!stop_for_loop) {
132 if (infoPtr->key[length] == 0) {
133 matchPtr = infoPtr;
134 goto gotMatch;
135 }
136 if (flags & ARGV_NO_ABBREV) {
137 stop_for_loop = true;
138 }
139 if (!stop_for_loop) {
140 if (matchPtr != nullptr) {
141 FPRINTF(stderr, "ambiguous option \"%s\"\n", curArg);
142 return true;
143 }
144 matchPtr = infoPtr;
145 }
146 }
147 }
148 }
149 }
150 if (matchPtr == nullptr) {
151
152 /*
153 * Unrecognized argument. Just copy it down, unless the caller
154 * prefers an error to be registered.
155 */
156
157 if (flags & ARGV_NO_LEFTOVERS) {
158 FPRINTF(stderr, "unrecognized argument \"%s\"\n", curArg);
159 }
160 argv[dstIndex] = curArg;
161 dstIndex++;
162 continue;
163 }
164
165 /*
166 * Take the appropriate action based on the option type
167 */
168 gotMatch:
169 infoPtr = matchPtr;
170 switch (infoPtr->type) {
171 case ARGV_CONSTANT:
173 *((int *)infoPtr->dst) = 1;
174 break;
176 *((bool *)infoPtr->dst) = true;
177 break;
178 case ARGV_INT:
179 nargs = (uintptr_t)infoPtr->src;
180 if (nargs < 1)
181 nargs = 1;
182 for (unsigned long i = 0; i < nargs; ++i) {
183 if (argc == 0) {
184 goto missingArg;
185 }
186 else {
187 char *endPtr = nullptr;
188
189 *(((int *)infoPtr->dst) + i) = static_cast<int>(strtol(argv[srcIndex], &endPtr, 0));
190 if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
191 FPRINTF(stderr, "expected integer argument for \"%s\" but got \"%s\"\n", infoPtr->key, argv[srcIndex]);
192 return true;
193 }
194 srcIndex++;
195 argc--;
196 }
197 }
198 break;
199 case ARGV_LONG:
200 nargs = (uintptr_t)infoPtr->src;
201 if (nargs < 1)
202 nargs = 1;
203 for (unsigned long i = 0; i < nargs; ++i) {
204 if (argc == 0) {
205 goto missingArg;
206 }
207 else {
208 char *endPtr = nullptr;
209
210 *(((long *)infoPtr->dst) + i) = strtol(argv[srcIndex], &endPtr, 0);
211 if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
212 FPRINTF(stderr, "expected long argument for \"%s\" but got \"%s\"\n", infoPtr->key, argv[srcIndex]);
213 return true;
214 }
215 srcIndex++;
216 argc--;
217 }
218 }
219 break;
220 case ARGV_STRING:
221 nargs = (uintptr_t)infoPtr->src;
222 if (nargs < 1)
223 nargs = 1;
224 for (unsigned long i = 0; i < nargs; ++i) {
225 if (argc == 0) {
226 goto missingArg;
227 }
228 else {
229 *(((const char **)infoPtr->dst) + i) = argv[srcIndex];
230 srcIndex++;
231 argc--;
232 }
233 }
234 break;
235 case ARGV_REST:
236 *((int *)infoPtr->dst) = dstIndex;
237 goto argsDone;
238 case ARGV_FLOAT:
239 nargs = (uintptr_t)infoPtr->src;
240 if (nargs < 1)
241 nargs = 1;
242 for (unsigned long i = 0; i < nargs; ++i) {
243 if (argc == 0) {
244 goto missingArg;
245 }
246 else {
247 char *endPtr;
248
249 *(((float *)infoPtr->dst) + i) = static_cast<float>(strtod(argv[srcIndex], &endPtr)); // Here we use strtod
250 if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
251 FPRINTF(stderr, "expected floating-point argument for \"%s\" but got\"%s\"\n", infoPtr->key,
252 argv[srcIndex]);
253 return true;
254 }
255 srcIndex++;
256 argc--;
257 }
258 }
259 break;
260 case ARGV_DOUBLE:
261 nargs = (uintptr_t)infoPtr->src;
262 if (nargs < 1)
263 nargs = 1;
264 for (unsigned long i = 0; i < nargs; ++i) {
265 if (argc == 0) {
266 goto missingArg;
267 }
268 else {
269 char *endPtr;
270
271 *(((double *)infoPtr->dst) + i) = strtod(argv[srcIndex], &endPtr);
272 if ((endPtr == argv[srcIndex]) || (*endPtr != 0)) {
273 FPRINTF(stderr, "expected double-point argument for \"%s\" but got\"%s\"\n", infoPtr->key, argv[srcIndex]);
274 return true;
275 }
276 srcIndex++;
277 argc--;
278 }
279 }
280 break;
281
282 case ARGV_FUNC: {
283 handlerProc1 = (int (*)(const char *dst, const char *key, const char *argument))infoPtr->src;
284
285 if ((*handlerProc1)(infoPtr->dst, infoPtr->key, argv[srcIndex])) {
286 srcIndex += 1;
287 argc -= 1;
288 }
289 break;
290 }
291 case ARGV_GENFUNC: {
292 handlerProc2 = (int (*)(const char *dst, const char *key, int valargc, const char **argument))infoPtr->src;
293
294 argc = (*handlerProc2)(infoPtr->dst, infoPtr->key, argc, argv + srcIndex);
295 if (argc < 0) {
296 return true;
297 }
298 break;
299 }
300
301 case ARGV_HELP:
302 printUsage(argTable, flags);
303 return true;
304 case ARGV_END:
305 default:
306 FPRINTF(stderr, "bad argument type %d in vpArgvInfo", infoPtr->type);
307 return true;
308 }
309 }
310
311 /*
312 * If we broke out of the loop because of an OPT_REST argument,
313 * copy the remaining arguments down.
314 */
315
316argsDone:
317 while (argc) {
318 argv[dstIndex] = argv[srcIndex];
319 srcIndex++;
320 dstIndex++;
321 argc--;
322 }
323 argv[dstIndex] = (char *)nullptr;
324 *argcPtr = dstIndex;
325 return false;
326
327missingArg:
328 FPRINTF(stderr, "\"%s\" option requires an additional argument\n", curArg);
329 return true;
330
331#undef FPRINTF
332}
333
348void vpParseArgv::printUsage(vpArgvInfo *argTable, int flags)
349{
350 vpArgvInfo *infoPtr;
351 int width;
352 int numSpaces;
353#define NUM_SPACES 20
354 static char spaces[] = " ";
355 /* char tmp[30]; */
356 unsigned long long nargs;
357
358/* Macro to optionally print errors */
359#define FPRINTF \
360 if (!(flags & ARGV_NO_PRINT)) \
361 (void)fprintf
362
363 /*
364 * First, compute the width of the widest option key, so that we
365 * can make everything line up.
366 */
367
368 width = 4;
369 for (unsigned int i = 0; i < 2; ++i) {
370 for (infoPtr = i ? defaultTable : argTable; infoPtr->type != ARGV_END; ++infoPtr) {
371 int length;
372 if (infoPtr->key == nullptr) {
373 continue;
374 }
375 length = static_cast<int>(strlen(infoPtr->key));
376 if (length > width) {
377 width = length;
378 }
379 }
380 }
381
382 FPRINTF(stderr, "Command-specific options:");
383 for (unsigned int i = 0;; ++i) {
384 for (infoPtr = i ? defaultTable : argTable; infoPtr->type != ARGV_END; ++infoPtr) {
385 if ((infoPtr->type == ARGV_HELP) && (infoPtr->key == nullptr)) {
386 FPRINTF(stderr, "\n%s", infoPtr->help);
387 continue;
388 }
389 FPRINTF(stderr, "\n %s:", infoPtr->key);
390 numSpaces = width + 1 - static_cast<int>(strlen(infoPtr->key));
391 while (numSpaces > 0) {
392 if (numSpaces >= NUM_SPACES) {
393 FPRINTF(stderr, "%s", spaces);
394 }
395 else {
396 FPRINTF(stderr, "%s", spaces + NUM_SPACES - numSpaces);
397 }
398 numSpaces -= NUM_SPACES;
399 }
400 FPRINTF(stderr, "%s", infoPtr->help);
401 switch (infoPtr->type) {
402 case ARGV_INT: {
403 FPRINTF(stderr, "\n\t\tDefault value:");
404 nargs = (uintptr_t)infoPtr->src;
405 if (nargs < 1)
406 nargs = 1;
407 for (unsigned long j = 0; j < nargs; ++j) {
408 FPRINTF(stderr, " %d", *(((int *)infoPtr->dst) + j));
409 }
410 break;
411 }
412 case ARGV_LONG: {
413 FPRINTF(stderr, "\n\t\tDefault value:");
414 nargs = (uintptr_t)infoPtr->src;
415 if (nargs < 1)
416 nargs = 1;
417 for (unsigned long j = 0; j < nargs; ++j) {
418 FPRINTF(stderr, " %ld", *(((long *)infoPtr->dst) + j));
419 }
420 break;
421 }
422 case ARGV_FLOAT: {
423 FPRINTF(stderr, "\n\t\tDefault value:");
424 nargs = (uintptr_t)infoPtr->src;
425 if (nargs < 1)
426 nargs = 1;
427 for (unsigned long j = 0; j < nargs; ++j) {
428 FPRINTF(stderr, " %f", *(((float *)infoPtr->dst) + j));
429 }
430 break;
431 }
432 case ARGV_DOUBLE: {
433 FPRINTF(stderr, "\n\t\tDefault value:");
434 nargs = (uintptr_t)infoPtr->src;
435 if (nargs < 1)
436 nargs = 1;
437 for (unsigned long j = 0; j < nargs; ++j) {
438 FPRINTF(stderr, " %g", *(((double *)infoPtr->dst) + j));
439 }
440 break;
441 }
442 case ARGV_STRING: {
443 const char *string;
444
445 nargs = (uintptr_t)infoPtr->src;
446 if (nargs < 1)
447 nargs = 1;
448 string = *((const char **)infoPtr->dst);
449 if ((nargs == 1) && (string == nullptr))
450 break;
451 for (unsigned long j = 0; j < nargs; ++j) {
452 string = *(((const char **)infoPtr->dst) + j);
453 if (string != nullptr) {
454 FPRINTF(stderr, " \"%s\"", string);
455 }
456 }
457
458 break;
459 }
460 case ARGV_END:
461 case ARGV_HELP:
462 case ARGV_GENFUNC:
463 case ARGV_FUNC:
464 case ARGV_REST:
465 case ARGV_CONSTANT:
468 default: {
469 break;
470 }
471 }
472 }
473
474 if ((flags & ARGV_NO_DEFAULTS) || (i > 0)) {
475 break;
476 }
477 FPRINTF(stderr, "\nGeneric options for all commands:");
478 }
479
480 FPRINTF(stderr, "\n");
481#undef FPRINTF
482}
483
511int vpParseArgv::parse(int argc, const char **argv, const char *validOpts, const char **param)
512{
513 static int iArg = 1;
514 int chOpt;
515 const char *psz = nullptr;
516 const char *pszParam = nullptr;
517
518 if (iArg < argc) {
519 psz = &(argv[iArg][0]);
520 if (*psz == '-') { // || *psz == '/') {
521 // we have an option specifier
522 chOpt = argv[iArg][1];
523 if (isalnum(chOpt) || ispunct(chOpt)) {
524 // we have an option character
525 psz = strchr(validOpts, chOpt);
526 if (psz != nullptr) {
527 // option is valid, we want to return chOpt
528 if (psz[1] == ':') {
529 // option can have a parameter
530 psz = &(argv[iArg][2]);
531 if (*psz == '\0') {
532 // must look at next argv for param
533 if (iArg + 1 < argc) {
534 psz = &(argv[iArg + 1][0]);
535 // next argv is the param
536 iArg++;
537 pszParam = psz;
538 }
539 else {
540 // reached end of args looking for param
541 // option specified without parameter
542 chOpt = -1;
543 pszParam = &(argv[iArg][0]);
544 }
545
546 }
547 else {
548 // param is attached to option
549 pszParam = psz;
550 }
551 }
552 else {
553 // option is alone, has no parameter
554 }
555 }
556 else {
557 // option specified is not in list of valid options
558 chOpt = -1;
559 pszParam = &(argv[iArg][0]);
560 }
561 }
562 else {
563 // though option specifier was given, option character
564 // is not alpha or was was not specified
565 chOpt = -1;
566 pszParam = &(argv[iArg][0]);
567 }
568 }
569 else {
570 // standalone arg given with no option specifier
571 chOpt = 1;
572 pszParam = &(argv[iArg][0]);
573 }
574 }
575 else {
576 // end of argument list
577 chOpt = 0;
578 }
579
580 iArg++;
581 *param = pszParam;
582 return (chOpt);
583}
584
585END_VISP_NAMESPACE
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
static vpArgvInfo defaultTable[2]
Definition vpParseArgv.h:41
@ ARGV_NO_DEFAULTS
No default options like -help.
@ ARGV_DONT_SKIP_FIRST_ARG
Don't skip first argument.
@ ARGV_NO_LEFTOVERS
Print an error message if an option is not in the argument list.
@ ARGV_DOUBLE
Argument is associated to a double.
@ ARGV_LONG
Argument is associated to a long.
@ ARGV_STRING
Argument is associated to a char * string.
@ ARGV_FLOAT
Argument is associated to a float.
@ ARGV_CONSTANT
Stand alone argument. Same as vpParseArgv::ARGV_CONSTANT_INT.
@ ARGV_INT
Argument is associated to an int.
@ ARGV_CONSTANT_BOOL
Stand alone argument associated to a bool var that is set to true.
@ ARGV_CONSTANT_INT
Stand alone argument associated to an int var that is set to 1.
@ ARGV_END
End of the argument list.
@ ARGV_HELP
Argument is for help displaying.