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