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