Utah Raster Toolkit  9999-git
URT Development version (post-3.1b)
scanargs.c
Go to the documentation of this file.
1 /*
2  * $Id: scanargs.c,v 3.0.1.3 1992/02/27 21:18:14 spencer Exp $
3  * Version 7 compatible
4  * Argument scanner, scans argv style argument list.
5  *
6  * Some stuff is a kludge because sscanf screws up
7  *
8  * Gary Newman - 10/4/1979 - Ampex Corp.
9  *
10  * Modified by Spencer W. Thomas, Univ. of Utah, 5/81 to
11  * add args introduced by a flag, add qscanargs call,
12  * allow empty flags.
13  *
14  * If you make improvements we'd like to get them too.
15  * Jay Lepreau lepreau@utah-20, decvax!harpo!utah-cs!lepreau
16  * Spencer Thomas thomas@utah-20, decvax!harpo!utah-cs!thomas
17  *
18  * (I know the code is ugly, but it just grew, you see ...)
19  *
20  * Modified by: Spencer W. Thomas
21  * Date: Feb 25 1983
22  * 1. Fixed scanning of optional args. Now args introduced by a flag
23  * must follow the flag which introduces them and precede any other
24  * flag argument. It is still possible for a flag introduced
25  * argument to be mistaken for a "bare" argument which occurs
26  * earlier in the format string. This implies that flags may not
27  * be conditional upon other flags, and a message will be generated
28  * if this is attempted.
29  *
30  * 2. Usage message can be formatted by inserting newlines, tabs and
31  * spaces into the format string. This is especially useful for
32  * long argument lists.
33  *
34  * 3. Added n/N types for "numeric" args. These args are scanned
35  * using the C language conventions - a number starting 0x is
36  * hexadecimal, a number starting with 0 is octal, otherwise it is
37  * decimal.
38  *
39  * Modified at BRL 16-May-88 by Mike Muuss to avoid Alliant STDC desire
40  * to have all "void" functions so declared.
41  */
42 
43 #include "rle_config.h"
44 #include <stdio.h>
45 #include <ctype.h>
46 #ifndef USE_STDARG
47 #include <varargs.h>
48 #else
49 #include <stdarg.h>
50 #endif
51 
52 typedef char bool;
53 /*
54  * An explicit assumption is made in this code that all pointers look
55  * alike, except possible char * pointers.
56  */
57 typedef int *ptr;
58 
59 #define YES 1
60 #define NO 0
61 #define ERROR(msg) {fprintf(stderr, "%s\n", msg); goto error; }
62 
63 /*
64  * Storage allocation macros
65  */
66 #define NEW( type, cnt ) (type *) malloc( (cnt) * sizeof( type ) )
67 #define RENEW( type, ptr, cnt ) (type *) realloc( ptr, (cnt) * sizeof( type ) )
68 
69 #if defined(c_plusplus) && !defined(USE_PROTOTYPES)
70 #define USE_PROTOTYPES
71 #endif
72 
73 #ifndef USE_PROTOTYPES
74 static char * prformat();
75 static int isnum();
76 static int _do_scanargs();
77 void scan_usage();
78 #else
79 static CONST_DECL char * prformat( CONST_DECL char *, int );
80 static int isnum( CONST_DECL char *, int, int );
81 static int _do_scanargs( int argc, char **argv, CONST_DECL char *format,
82  va_list argl );
83 void scan_usage( char **, CONST_DECL char * );
84 #endif
85 
86 /*
87  * Argument list is (argc, argv, format, ... )
88  */
89 int
90 #ifndef USE_STDARG
92 va_dcl
93 #else
94 scanargs ( int argc, char **argv, CONST_DECL char *format, ... )
95 #endif /* !USE_STDARG */
96 {
97  va_list argl;
98  int retval;
99 #ifndef USE_STDARG
100  int argc;
101  char ** argv;
102  CONST_DECL char *format;
103 
104  va_start( argl );
105  argc = va_arg( argl, int );
106  argv = va_arg( argl, char ** );
107  format = va_arg( argl, CONST_DECL char * );
108 #else
109  va_start( argl, format );
110 #endif
111  retval = _do_scanargs( argc, argv, format, argl );
112  va_end( argl );
113  return retval;
114 }
115 
116 /*
117  * This routine is necessary because of a pyramid compiler botch that
118  * uses parameter registers in a varargs routine. The extra
119  * subroutine call isolates the args on the register stack so they
120  * don't get trashed.
121  */
122 
123 static int
125 int argc; /* Actual arguments */
126 char **argv;
127 CONST_DECL char *format;
128 va_list argl;
129 {
130 
131  int check; /* check counter to be sure all argvs
132  are processed */
133  register CONST_DECL char *cp;
134  int cnt;
135  int optarg = 0; /* where optional args start */
136  int nopt = 0;
137  char tmpflg, /* temp flag */
138  typchr; /* type char from format string */
139  char c;
140  bool * arg_used; /* array of flags */
141  ptr aptr = 0; /* pointer to return loc */
142 
143  bool required;
144  int excnt; /* which flag is set */
145  bool exflag; /* when set, one of a set of exclusive
146  flags is set */
147 
148  bool list_of; /* set if parsing off a list of args */
149  bool comma_list; /* set if AT&T style multiple args */
150  bool no_usage; /* If set, don't print usage msg. */
151  bool help = NO; /* If set, always print usage. */
152  int * cnt_arg = 0; /* where to stuff list count */
153  int list_cnt; /* how many in list */
154  /* These are used to build return lists */
155  char ** strlist = 0;
156  int * intlist = 0;
157  long * longlist = 0;
158  float * fltlist = 0;
159  double *dbllist = 0;
160  char * argp; /* Pointer to argument. */
161 
162  CONST_DECL char *ncp; /* remember cp during flag scanning */
163  static char cntrl[7] = "% %1s"; /* control string for scanf's */
164  char junk[2]; /* junk buffer for scanf's */
165 
166  /* Set up for argument counting. */
167  arg_used = NEW( bool, argc );
168  if (arg_used == NULL)
169  {
170  fprintf(stderr, "malloc failed in scanargs, exiting\n");
171  exit(-1);
172  }
173  else
174  {
175  for (cnt=0; cnt<argc; cnt++)
176  arg_used[cnt] = NO;
177  }
178  check = 0;
179 
180  /* Scan for -help in arg list. */
181  for ( cnt=1; cnt<argc; cnt++ )
182  if ( strcmp( argv[cnt], "-help" ) == 0 )
183  {
184  check += cnt;
185  arg_used[cnt] = YES;
186  if ( argc == 2 )
187  {
188  scan_usage( argv, format );
189  return 0;
190  }
191  else
192  help = YES;
193  }
194 
195  /* If format string ends in @, don't print a usage message. */
196  no_usage = *(format + strlen( format ) - 1) == '&';
197 
198  cp = format;
199  /*
200  * Skip program name
201  */
202  while ( *cp != ' ' && *cp != '\t' && *cp != '\n' && *cp != '\0' )
203  cp++;
204 
205  while (*cp)
206  {
207  required = NO; /* reset per-arg flags */
208  list_of = NO;
209  comma_list = NO;
210  list_cnt = 0;
211  switch (*(cp++))
212  {
213  default: /* all other chars */
214  break;
215  case ' ': /* separators */
216  case '\t':
217  case '\n':
218  optarg = 0; /* end of optional arg string */
219  break;
220 
221  case '(': /* Surrounds a comment. */
222  {
223  int depth = 1; /* Count parenthesis depth. */
224  while ( *cp && depth > 0 )
225  switch ( *(cp++) )
226  {
227  case '(': depth++; break;
228  case ')': depth--; break;
229  }
230  break;
231  }
232 
233  case '!': /* required argument */
234  required = YES;
235  case '%': /* not required argument */
236 reswitch: /* after finding '*' or ',' */
237  switch (typchr = *(cp++))
238  {
239  case ',': /* argument is AT&T list of things */
240  comma_list = YES;
241  case '*': /* argument is list of things */
242  list_of = YES;
243  list_cnt = 0; /* none yet */
244  cnt_arg = va_arg( argl, int *); /* item count * here */
245  goto reswitch; /* try again */
246 
247  case '$': /* "rest" of argument list */
248  while ( argc > 1 && !arg_used[argc-1] )
249  argc--; /* find last used argument */
250  *va_arg( argl, int * ) = argc;
251  break;
252 
253  case '&': /* Return unused args. */
254  /* Count how many. Always include argv[0]. */
255  for ( nopt = cnt = 1; cnt < argc; cnt++ )
256  if ( !arg_used[cnt] )
257  nopt++;
258  if ( nopt == 1 )
259  nopt = 0; /* Special case for no args. */
260  if ( nopt > 0 )
261  {
262  strlist = NEW( char *, nopt + 1 );
263  /* Copy program name, for sure. */
264  strlist[0] = argv[0];
265  for ( nopt = cnt = 1; cnt < argc; cnt++ )
266  if ( !arg_used[cnt] )
267  {
268  strlist[nopt++] = argv[cnt];
269  check += cnt;
270  arg_used[cnt] = 1;
271  }
272  strlist[nopt] = NULL;
273  }
274  else
275  strlist = NULL; /* No args, return empty. */
276 
277  /* Return count and arg list. */
278  *va_arg( argl, int * ) = nopt;
279  *va_arg( argl, char *** ) = strlist;
280  break;
281 
282  case '-': /* argument is flag */
283  if (optarg > 0)
284  ERROR("Format error: flag conditional on flag not allowed");
285 
286  /* go back to label */
287  ncp = cp-1; /* remember */
288  cp -= 3;
289  for (excnt = exflag = 0
290  ; *cp != ' ' && !(*cp=='-' &&(cp[-1]=='!'||cp[-1]=='%'));
291  (--cp, excnt++))
292  {
293  for (cnt = optarg+1; cnt < argc; cnt++)
294  {
295  /* flags all start with - */
296  if (*argv[cnt] == '-' && !arg_used[cnt] &&
297  !isdigit(argv[cnt][1]))
298  if (*(argv[cnt] + 1) == *cp)
299  {
300  if (*(argv[cnt] + 2) != 0)
301  ERROR ("extra flags ignored");
302  if (exflag)
303  ERROR ("more than one exclusive flag chosen");
304  exflag++;
305  required = NO;
306  check += cnt;
307  arg_used[cnt] = 1;
308  nopt = cnt;
309  *va_arg( argl, int *) |= (1 << excnt);
310  break;
311  }
312  }
313  }
314  if (required)
315  ERROR ("flag argument missing");
316  cp = ncp;
317  /*
318  * If none of these flags were found, skip any
319  * optional arguments (in the varargs list, too).
320  */
321  if (!exflag)
322  {
323  (void)va_arg( argl, int * );/* skip the arg, too */
324  while (*++cp && ! isspace(*cp))
325  if (*cp == '!' || *cp == '%')
326  {
327  if ( *++cp == '*' || *cp == ',' )
328  {
329  cp++;
330  (void)va_arg( argl, int * );
331  }
332  /*
333  * Assume that char * might be a
334  * different size, but that all
335  * other pointers are same size.
336  */
337  if ( *cp == 's' )
338  (void)va_arg( argl, char * );
339  else
340  (void)va_arg( argl, ptr );
341  }
342  }
343  else
344  {
345  optarg = nopt;
346  cp++; /* skip over - */
347  }
348 
349  break;
350 
351  case 's': /* char string */
352  case 'd': /* decimal # */
353  case 'o': /* octal # */
354  case 'x': /* hexadecimal # */
355  case 'n': /* "number" in C syntax */
356  case 'f': /* floating # */
357  case 'D': /* long decimal # */
358  case 'O': /* long octal # */
359  case 'X': /* long hexadecimal # */
360  case 'N': /* long number in C syntax */
361  case 'F': /* double precision floating # */
362 #if defined(sgi) && !defined(mips)
363  /* Fix for broken SGI IRIS 2400/3000 floats */
364  if ( typchr == 'F' ) typchr = 'f';
365 #endif /* sgi */
366  for (cnt = optarg+1; cnt < argc; cnt++)
367  {
368  argp = argv[cnt];
369 
370  if ( isnum( argp, typchr, comma_list ) )
371  {
372  ; /* it's ok, then */
373  }
374  else if ( *argp == '-' && argp[1] != '\0' )
375  if ( optarg > 0 ) /* end optional args? */
376  {
377  /* Eat the arg, too, if necessary */
378  if ( list_cnt == 0 ) {
379  if ( typchr == 's' )
380  (void)va_arg( argl, char * );
381  else
382  (void)va_arg( argl, ptr );
383  }
384  break;
385  }
386  else
387  continue;
388  else if ( typchr != 's' )
389  continue; /* not number, keep looking */
390 
391  /*
392  * Otherwise usable argument may already
393  * be used. (Must check this after
394  * checking for flag, though.)
395  */
396  if (arg_used[cnt]) continue;
397 
398  /*
399  * If it's a comma-and-or-space-separated
400  * list then count how many, and separate
401  * the list into an array of strings.
402  */
403  if ( comma_list )
404  {
405  register char * s;
406  int pass;
407 
408  /*
409  * Copy the string so we remain nondestructive
410  */
411  s = NEW( char, strlen(argp)+1 );
412  strcpy( s, argp );
413  argp = s;
414 
415  /*
416  * On pass 0, just count them. On
417  * pass 1, null terminate each string
418  */
419  for ( pass = 0; pass <= 1; pass++ )
420  {
421  for ( s = argp; *s != '\0'; )
422  {
423  if ( pass )
424  strlist[list_cnt] = s;
425  while ( (c = *s) != '\0' && c != ' ' &&
426  c != '\t' && c != ',' )
427  s++;
428  if ( pass )
429  *s = '\0';
430 
431  list_cnt++; /* count separators */
432  /*
433  * Two commas in a row give a null
434  * string, but two spaces
435  * don't. Also skip spaces
436  * after a comma.
437  */
438  if ( c != '\0' )
439  while ( *++s == ' ' || *s == '\t' )
440  ;
441  }
442  if ( pass == 0 )
443  {
444  strlist = NEW( char *, list_cnt );
445  list_cnt = 0;
446  }
447  }
448  }
449  else if ( list_of )
450  list_cnt++; /* getting them one at a time */
451  /*
452  * If it's either type of list, then alloc
453  * storage space for the returned values
454  * (except that comma-separated string
455  * lists already are done).
456  */
457  if ( list_of )
458  {
459  if ( list_cnt == 1 || comma_list )
460  switch( typchr )
461  {
462  case 's':
463  if ( !comma_list )
464  strlist = NEW( char *, 1 );
465  aptr = (ptr) &strlist[0];
466  break;
467  case 'n':
468  case 'd':
469  case 'o':
470  case 'x':
471  intlist = NEW( int, list_cnt );
472  aptr = (ptr) &intlist[0];
473  break;
474  case 'N':
475  case 'D':
476  case 'O':
477  case 'X':
478  longlist = NEW( long, list_cnt );
479  aptr = (ptr) &longlist[0];
480  break;
481  case 'f':
482  fltlist = NEW( float, list_cnt );
483  aptr = (ptr) &fltlist[0];
484  break;
485  case 'F':
486  dbllist = NEW( double, list_cnt );
487  aptr = (ptr) &dbllist[0];
488  break;
489  }
490  else
491  switch( typchr )
492  {
493  case 's':
494  strlist = RENEW( char *, strlist,
495  list_cnt );
496  aptr = (ptr) &strlist[list_cnt-1];
497  break;
498  case 'n':
499  case 'd':
500  case 'o':
501  case 'x':
502  intlist = RENEW( int, intlist,
503  list_cnt );
504  aptr = (ptr) &intlist[list_cnt-1];
505  break;
506  case 'N':
507  case 'D':
508  case 'O':
509  case 'X':
510  longlist = RENEW( long, longlist,
511  list_cnt );
512  aptr = (ptr) &longlist[list_cnt-1];
513  break;
514  case 'f':
515  fltlist = RENEW( float, fltlist,
516  list_cnt );
517  aptr = (ptr) &fltlist[list_cnt-1];
518  break;
519  case 'F':
520  dbllist = RENEW( double, dbllist,
521  list_cnt );
522  aptr = (ptr) &dbllist[list_cnt-1];
523  break;
524  }
525  }
526  else
527  aptr = va_arg( argl, ptr );
528 
529  if ( typchr == 's' )
530  {
531  if ( ! comma_list )
532  *(char **)aptr = argp;
533  }
534  else
535  {
536  nopt = 0;
537  do {
538  /*
539  * Need to update aptr if parsing
540  * a comma list
541  */
542  if ( comma_list && nopt > 0 )
543  {
544  argp = strlist[nopt];
545  switch( typchr )
546  {
547  case 'n':
548  case 'd':
549  case 'o':
550  case 'x':
551  aptr = (ptr) &intlist[nopt];
552  break;
553  case 'N':
554  case 'D':
555  case 'O':
556  case 'X':
557  aptr = (ptr) &longlist[nopt];
558  break;
559  case 'f':
560  aptr = (ptr) &fltlist[nopt];
561  break;
562  case 'F':
563  aptr = (ptr) &dbllist[nopt];
564  break;
565  }
566  }
567  /*
568  * Do conversion for n and N types
569  */
570  tmpflg = typchr;
571  if (typchr == 'n' || typchr == 'N' ) {
572  if (*argp != '0')
573  tmpflg = 'd';
574  else if (*(argp+1) == 'x' ||
575  *(argp+1) == 'X')
576  {
577  tmpflg = 'x';
578  argp += 2;
579  }
580  else
581  tmpflg = 'o';
582  }
583  if (typchr == 'N')
584  tmpflg = toupper( tmpflg );
585 
586 
587  /* put in conversion */
588  if ( isupper( tmpflg ) )
589  {
590  cntrl[1] = 'l';
591  cntrl[2] = tolower( tmpflg );
592  }
593  else
594  {
595  cntrl[1] = tmpflg;
596  cntrl[2] = ' ';
597  }
598  if (sscanf (argp, cntrl, aptr, junk) != 1)
599  ERROR ("Bad numeric argument");
600  } while ( comma_list && ++nopt < list_cnt );
601  }
602  check += cnt;
603  arg_used[cnt] = 1;
604  required = NO;
605  /*
606  * If not looking for multiple args,
607  * then done, otherwise, keep looking.
608  */
609  if ( !( list_of && !comma_list ) )
610  break;
611  else
612  continue;
613  }
614  if (required)
615  switch (typchr)
616  {
617  case 'x':
618  case 'X':
619  ERROR ("missing hexadecimal argument");
620  case 's':
621  ERROR ("missing string argument");
622  case 'o':
623  case 'O':
624  ERROR ("missing octal argument");
625  case 'd':
626  case 'D':
627  ERROR ("missing decimal argument");
628  case 'f':
629  case 'F':
630  ERROR ("missing floating argument");
631  case 'n':
632  case 'N':
633  ERROR ("missing numeric argument");
634  }
635  if ( list_cnt > 0 )
636  {
637  *cnt_arg = list_cnt;
638  switch ( typchr )
639  {
640  case 's':
641  *va_arg( argl, char *** ) = strlist;
642  break;
643  case 'n':
644  case 'd':
645  case 'o':
646  case 'x':
647  *va_arg( argl, int ** ) = intlist;
648  break;
649  case 'N':
650  case 'D':
651  case 'O':
652  case 'X':
653  *va_arg( argl, long ** ) = longlist;
654  break;
655  case 'f':
656  *va_arg( argl, float ** ) = fltlist;
657  break;
658  case 'F':
659  *va_arg( argl, double **) = dbllist;
660  break;
661  }
662  if ( typchr != 's' && comma_list )
663  free( (char *) strlist );
664  }
665  else if ( cnt >= argc )
666  {
667  /* Fell off end looking, so must eat the arg */
668  if ( typchr == 's' )
669  (void)va_arg( argl, char * );
670  else
671  (void)va_arg( argl, ptr );
672  }
673  break;
674  default: /* error */
675  fprintf (stderr,
676  "scanargs: Corrupt or invalid format spec\n");
677  return 0;
678  }
679  }
680  }
681 
682  /* Count up empty flags */
683  for (cnt=1; cnt<argc; cnt++)
684  if (argv[cnt][0] == '-' && argv[cnt][1] == '-' && argv[cnt][2] == 0
685  && !arg_used[cnt] )
686  check += cnt;
687 
688  /* sum from 1 to N = n*(n+1)/2 used to count up checks */
689  if (check != (((argc - 1) * argc) / 2))
690  ERROR ("extra arguments not processed");
691 
692  /* If -help, always print usage. */
693  if ( help )
694  scan_usage( argv, format );
695 
696  free(arg_used);
697  return 1;
698 
699 error:
700  if ( !no_usage )
701  scan_usage( argv, format );
702  free(arg_used);
703  return 0;
704 }
705 
706 void
708 char ** argv;
709 CONST_DECL char * format;
710 {
711  register CONST_DECL char * cp;
712 
713  fprintf (stderr, "usage : ");
714  if (*(cp = format) != ' ')
715  {
716  if ( *cp == '%' )
717  {
718  /*
719  * This is bogus, but until everyone can agree on a name
720  * for (rindex/strrchr) ....
721  */
722  for ( cp = argv[0]; *cp != '\0'; cp++ )
723  ; /* find the end of the string */
724  for ( ; cp > argv[0] && *cp != '/'; cp-- )
725  ; /* find the last / */
726  if ( *cp == '/' )
727  cp++;
728  fprintf( stderr, "%s", cp );
729 
730  cp = format + 1; /* reset to where it should be */
731  }
732  while (putc (*cp++, stderr) != ' ');
733  }
734  else
735  fprintf (stderr, "?? ");
736  while (*cp == ' ')
737  cp++;
738  (void)prformat (cp, NO);
739 }
740 
741 static CONST_DECL char *
743 CONST_DECL char *format;
744 int recurse;
745 {
746  register CONST_DECL char *cp;
747  bool required, comma_list;
748  int list_of, depth;
749 
750  cp = format;
751  if (recurse)
752  putc (' ', stderr);
753 
754  required = NO;
755  list_of = 0;
756  comma_list = NO;
757  while (*cp)
758  {
759  switch (*cp)
760  {
761  default:
762  cp++;
763  break;
764  case ' ':
765  case '\n':
766  case '\t':
767  /* allow annotations */
768  for ( ; format < cp; format++ )
769  putc( *format, stderr );
770  putc(*cp, stderr);
771  format = ++cp;
772  break;
773 
774  case '(':
775  /* Parentheses surround an arbitrary (parenthesis
776  * balanced) comment.
777  */
778  for ( ; format < cp; format++ )
779  putc( *format, stderr );
780  for ( cp++, depth = 1; *cp && depth > 0; )
781  {
782  /* Don't print last close paren. */
783  if ( *cp != ')' || depth > 1 )
784  putc( *cp, stderr );
785  switch( *(cp++) )
786  {
787  case '(': depth++; break;
788  case ')': depth--; break;
789  }
790  }
791  format = cp;
792  break;
793 
794  case '!':
795  required = YES;
796  case '%':
797 reswitch:
798  switch (*++cp)
799  {
800  case ',':
801  comma_list++;
802  case '*':
803  list_of++;
804  goto reswitch;
805 
806  case '$': /* "rest" of argument list */
807  if (!required)
808  putc ('[', stderr);
809  for (; format < cp - 1 - list_of; format++)
810  putc (*format, stderr);
811  fputs( " ...", stderr );
812  if ( !required )
813  putc( ']', stderr );
814  break;
815 
816  case '-': /* flags */
817  if (!required)
818  putc ('[', stderr);
819  putc ('-', stderr);
820 
821  if (cp - format > 2 + list_of)
822  putc ('{', stderr);
823  cp = format;
824  while (*cp != '%' && *cp != '!')
825  putc (*cp++, stderr);
826  if (cp - format > 1 + list_of)
827  putc ('}', stderr);
828  cp += 2; /* skip !- or %- */
829  if (*cp && !isspace(*cp))
830  cp = prformat (cp, YES);
831  /* this is a recursive call */
832 
833  cp--; /* don't ignore next character */
834 
835  if (!required)
836  putc (']', stderr);
837  break;
838  case 's': /* char string */
839  case 'd': /* decimal # */
840  case 'o': /* octal # */
841  case 'x': /* hexadecimal # */
842  case 'f': /* floating # */
843  case 'D': /* long decimal # */
844  case 'O': /* long octal # */
845  case 'X': /* long hexadecimal # */
846  case 'F': /* double precision floating # */
847  case 'n': /* numeric arg (C format) */
848  case 'N': /* long numeric arg */
849  if (!required)
850  putc ('[', stderr);
851  for (; format < cp - 1 - list_of; format++)
852  putc (*format, stderr);
853  if ( list_of != 0 )
854  {
855  if ( comma_list )
856  putc( ',', stderr );
857  else
858  putc( ' ', stderr );
859  fputs( "...", stderr );
860  }
861  if (!required)
862  putc (']', stderr);
863  break;
864  default:
865  break;
866  }
867  required = NO;
868  list_of = NO;
869  comma_list = NO;
870  if (*cp) /* check for end of string */
871  format = ++cp;
872  if (*cp && !isspace(*cp))
873  putc (' ', stderr);
874  }
875  if (recurse && isspace(*cp))
876  break;
877  }
878  if (!recurse)
879  {
880  for ( ; format < cp; format++ )
881  putc( *format, stderr );
882  putc ('\n', stderr);
883  }
884  return (cp);
885 }
886 
887 /*
888  * isnum - determine whether a string MIGHT represent a number.
889  * typchr indicates the type of argument we are looking for, and
890  * determines the legal character set. If comma_list is YES, then
891  * space and comma are also legal characters.
892  */
893 static int
895 register CONST_DECL char * str;
896 int typchr;
897 int comma_list;
898 {
899  register CONST_DECL char *allowed, *digits, *cp;
900  int hasdigit = NO;
901 
902  switch( typchr )
903  {
904  case 'n':
905  case 'N':
906  allowed = " \t,+-x0123456789abcdefABCDEF";
907  break;
908  case 'd':
909  case 'D':
910  allowed = " \t,+-0123456789";
911  break;
912  case 'o':
913  case 'O':
914  allowed = " \t,01234567";
915  break;
916  case 'x':
917  case 'X':
918  allowed = " \t,0123456789abcdefABCDEF";
919  break;
920  case 'f':
921  case 'F':
922  allowed = " \t,+-eE.0123456789";
923  break;
924  case 's': /* only throw out decimal numbers */
925  default:
926  allowed = " \t,+-.0123456789";
927  break;
928  }
929  digits = allowed;
930  while ( *digits != '0' )
931  digits++;
932  if ( ! comma_list )
933  allowed += 3; /* then don't allow space, tab, comma */
934 
935  while ( *str != '\0' )
936  {
937  for ( cp = allowed; *cp != '\0' && *cp != *str; cp++ )
938  ;
939  if ( *cp == '\0' )
940  return NO; /* if not in allowed chars, not number */
941  if ( cp - digits >= 0 )
942  hasdigit = YES;
943  str++;
944  }
945  return hasdigit;
946 }
#define USE_STDARG
Definition: rle_config.h:24
#define USE_PROTOTYPES
Definition: rle_config.h:22
static int _do_scanargs(int argc, char **argv, const char *format, va_list argl)
Definition: scanargs.c:124
#define NEW(type, cnt)
Definition: scanargs.c:66
static const char * prformat(char *format, int recurse) const
Definition: scanargs.c:742
int scanargs(int argc, char **argv, const char *format,...)
Definition: scanargs.c:94
char bool
Definition: scanargs.c:52
#define CONST_DECL
Definition: rle_config.h:42
int * ptr
Definition: scanargs.c:57
#define YES
Definition: scanargs.c:59
static int isnum(const char *str, int typchr, int comma_list)
Definition: scanargs.c:894
void scan_usage()
#define NO
Definition: scanargs.c:60
#define RENEW(type, ptr, cnt)
Definition: scanargs.c:67
#define ERROR(msg)
Definition: scanargs.c:61