Visual Servoing Platform  version 3.6.1 under development (2024-07-15)
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 
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 
45 int (*handlerProc1)(const char *dst, const char *key, const char *argument);
46 int (*handlerProc2)(const char *dst, const char *key, int valargc, const char **argument);
47 
70 bool 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:
172  case ARGV_CONSTANT_INT:
173  *((int *)infoPtr->dst) = 1;
174  break;
175  case ARGV_CONSTANT_BOOL:
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) = (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) = (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 
316 argsDone:
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 
327 missingArg:
328  FPRINTF(stderr, "\"%s\" option requires an additional argument\n", curArg);
329  return true;
330 
331 #undef FPRINTF
332 }
333 
348 void 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 = (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 - (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:
466  case ARGV_CONSTANT_INT:
467  case ARGV_CONSTANT_BOOL:
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 
511 int 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 
585 END_VISP_NAMESPACE
static bool parse(int *argcPtr, const char **argv, vpArgvInfo *argTable, int flags)
Definition: vpParseArgv.cpp:70
static vpArgvInfo defaultTable[2]
Definition: vpParseArgv.h:196
@ ARGV_NO_DEFAULTS
No default options like -help.
Definition: vpParseArgv.h:172
@ ARGV_DONT_SKIP_FIRST_ARG
Don't skip first argument.
Definition: vpParseArgv.h:176
@ ARGV_NO_LEFTOVERS
Print an error message if an option is not in the argument list.
Definition: vpParseArgv.h:173
@ ARGV_DOUBLE
Argument is associated to a double.
Definition: vpParseArgv.h:160
@ ARGV_LONG
Argument is associated to a long.
Definition: vpParseArgv.h:156
@ ARGV_STRING
Argument is associated to a char * string.
Definition: vpParseArgv.h:157
@ ARGV_FLOAT
Argument is associated to a float.
Definition: vpParseArgv.h:159
@ ARGV_CONSTANT
Stand alone argument. Same as vpParseArgv::ARGV_CONSTANT_INT.
Definition: vpParseArgv.h:152
@ ARGV_INT
Argument is associated to an int.
Definition: vpParseArgv.h:155
@ ARGV_CONSTANT_BOOL
Stand alone argument associated to a bool var that is set to true.
Definition: vpParseArgv.h:154
@ ARGV_CONSTANT_INT
Stand alone argument associated to an int var that is set to 1.
Definition: vpParseArgv.h:153
@ ARGV_END
End of the argument list.
Definition: vpParseArgv.h:164
@ ARGV_HELP
Argument is for help displaying.
Definition: vpParseArgv.h:163