GNUnet  0.11.x
Data Structures | Macros | Enumerations | Functions | Variables
getopt.c File Reference

GNU style option parsing. More...

#include "platform.h"
#include "gnunet_util_lib.h"
Include dependency graph for getopt.c:

Go to the source code of this file.

Data Structures

struct  GNoption
 

Macros

#define LOG(kind, ...)   GNUNET_log_from (kind, "util-getopt", __VA_ARGS__)
 
#define LOG_STRERROR(kind, syscall)   GNUNET_log_from_strerror (kind, "util-getopt", syscall)
 
#define _(msgid)   (msgid)
 
#define SWAP_FLAGS(ch1, ch2)
 
#define NONOPTION_P   (argv[GNoptind][0] != '-' || argv[GNoptind][1] == '\0')
 

Enumerations

enum  { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER }
 

Functions

char * getenv ()
 
static char * my_index (const char *str, int chr)
 
static void exchange (char **argv)
 
static const char * _getopt_initialize (int argc, char *const *argv, const char *optstring)
 
static int GN_getopt_internal (int argc, char *const *argv, const char *optstring, const struct GNoption *longopts, int *longind, int long_only)
 
static int GNgetopt_long (int argc, char *const *argv, const char *options, const struct GNoption *long_options, int *opt_index)
 
int GNUNET_GETOPT_run (const char *binaryOptions, const struct GNUNET_GETOPT_CommandLineOption *allOptions, unsigned int argc, char *const *argv)
 Parse the command line. More...
 

Variables

static char * GNoptarg = NULL
 
static int GNoptind = 1
 
static char * nextchar
 
static enum { ... }  ordering
 
static char * posixly_correct
 
static int first_nonopt
 
static int last_nonopt
 

Detailed Description

GNU style option parsing.

TODO: get rid of statics (make reentrant) and replace main GNU getopt parser with one that actually fits our API.

Definition in file getopt.c.

Macro Definition Documentation

◆ LOG

#define LOG (   kind,
  ... 
)    GNUNET_log_from (kind, "util-getopt", __VA_ARGS__)

Definition at line 50 of file getopt.c.

◆ LOG_STRERROR

#define LOG_STRERROR (   kind,
  syscall 
)    GNUNET_log_from_strerror (kind, "util-getopt", syscall)

Definition at line 52 of file getopt.c.

◆ _

#define _ (   msgid)    (msgid)

Definition at line 62 of file getopt.c.

Referenced by GN_getopt_internal(), and GNUNET_GETOPT_run().

◆ SWAP_FLAGS

#define SWAP_FLAGS (   ch1,
  ch2 
)

Definition at line 232 of file getopt.c.

Referenced by exchange().

◆ NONOPTION_P

#define NONOPTION_P   (argv[GNoptind][0] != '-' || argv[GNoptind][1] == '\0')

Referenced by GN_getopt_internal().

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
REQUIRE_ORDER 
PERMUTE 
RETURN_IN_ORDER 

Definition at line 174 of file getopt.c.

Function Documentation

◆ getenv()

char* getenv ( )

◆ my_index()

static char* my_index ( const char *  str,
int  chr 
)
static

Definition at line 195 of file getopt.c.

Referenced by GN_getopt_internal().

196 {
197  while (*str)
198  {
199  if (*str == chr)
200  return (char *) str;
201  str++;
202  }
203  return 0;
204 }
Here is the caller graph for this function:

◆ exchange()

static void exchange ( char **  argv)
static

Definition at line 250 of file getopt.c.

References _getopt_initialize(), first_nonopt, GNoptind, last_nonopt, len, SWAP_FLAGS, and top.

Referenced by GN_getopt_internal().

251 {
252  int bottom = first_nonopt;
253  int middle = last_nonopt;
254  int top = GNoptind;
255  char *tem;
256 
257  /* Exchange the shorter segment with the far end of the longer segment.
258  * That puts the shorter segment into the right place.
259  * It leaves the longer segment in the right place overall,
260  * but it consists of two parts that need to be swapped next. */
261 
262  while (top > middle && middle > bottom)
263  {
264  if (top - middle > middle - bottom)
265  {
266  /* Bottom segment is the short one. */
267  int len = middle - bottom;
268  register int i;
269 
270  /* Swap it with the top part of the top segment. */
271  for (i = 0; i < len; i++)
272  {
273  tem = argv[bottom + i];
274  argv[bottom + i] = argv[top - (middle - bottom) + i];
275  argv[top - (middle - bottom) + i] = tem;
276  SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
277  }
278  /* Exclude the moved bottom segment from further swapping. */
279  top -= len;
280  }
281  else
282  {
283  /* Top segment is the short one. */
284  int len = top - middle;
285  register int i;
286 
287  /* Swap it with the bottom part of the bottom segment. */
288  for (i = 0; i < len; i++)
289  {
290  tem = argv[bottom + i];
291  argv[bottom + i] = argv[middle + i];
292  argv[middle + i] = tem;
293  SWAP_FLAGS (bottom + i, middle + i);
294  }
295  /* Exclude the moved top segment from further swapping. */
296  bottom += len;
297  }
298  }
299 
300  /* Update records for the slots the non-options now occupy. */
301 
304 }
#define SWAP_FLAGS(ch1, ch2)
Definition: getopt.c:232
static int last_nonopt
Definition: getopt.c:230
struct GNUNET_ATS_TEST_Topology * top
Definition: ats-testing.c:53
static int GNoptind
Definition: getopt.c:133
static int first_nonopt
Definition: getopt.c:229
uint16_t len
length of data (which is always a uint32_t, but presumably this can be used to specify that fewer byt...
Here is the call graph for this function:
Here is the caller graph for this function:

◆ _getopt_initialize()

static const char* _getopt_initialize ( int  argc,
char *const *  argv,
const char *  optstring 
)
static

Definition at line 315 of file getopt.c.

References first_nonopt, getenv(), GNoptind, last_nonopt, nextchar, ordering, PERMUTE, posixly_correct, REQUIRE_ORDER, and RETURN_IN_ORDER.

Referenced by exchange(), and GN_getopt_internal().

316 {
317  /* Start processing options with ARGV-element 1 (since ARGV-element 0
318  * is the program name); the sequence of previously skipped
319  * non-option ARGV-elements is empty. */
320 
322 
323  nextchar = NULL;
324 
325  posixly_correct = getenv ("POSIXLY_CORRECT");
326 
327  /* Determine how to handle the ordering of options and nonoptions. */
328 
329  if (optstring[0] == '-')
330  {
332  ++optstring;
333  }
334  else if (optstring[0] == '+')
335  {
337  ++optstring;
338  }
339  else if (posixly_correct != NULL)
341  else
342  ordering = PERMUTE;
343 
344  return optstring;
345 }
static int last_nonopt
Definition: getopt.c:230
static char * posixly_correct
Definition: getopt.c:177
static int GNoptind
Definition: getopt.c:133
static int first_nonopt
Definition: getopt.c:229
char * getenv()
static char * nextchar
Definition: getopt.c:142
static enum @80 ordering
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GN_getopt_internal()

static int GN_getopt_internal ( int  argc,
char *const *  argv,
const char *  optstring,
const struct GNoption longopts,
int *  longind,
int  long_only 
)
static

Definition at line 405 of file getopt.c.

References _, _getopt_initialize(), exchange(), first_nonopt, GNoption::flag, GNoptarg, GNoptind, GNoption::has_arg, last_nonopt, my_index(), GNoption::name, nextchar, NONOPTION_P, ordering, p, PERMUTE, posixly_correct, REQUIRE_ORDER, and GNoption::val.

Referenced by GNgetopt_long().

411 {
412  static int __getopt_initialized = 0;
413  static int GNopterr = 1;
414 
415  GNoptarg = NULL;
416 
417  if ((GNoptind == 0) || ! __getopt_initialized)
418  {
419  if (GNoptind == 0)
420  GNoptind = 1; /* Don't scan ARGV[0], the program name. */
421  optstring = _getopt_initialize (argc, argv, optstring);
422  __getopt_initialized = 1;
423  }
424 
425  /* Test whether ARGV[GNoptind] points to a non-option argument.
426  * Either it does not have option syntax, or there is an environment flag
427  * from the shell indicating it is not an option. The later information
428  * is only used when the used in the GNU libc. */
429 #define NONOPTION_P (argv[GNoptind][0] != '-' || argv[GNoptind][1] == '\0')
430 
431  if ((nextchar == NULL) || (*nextchar == '\0'))
432  {
433  /* Advance to the next ARGV-element. */
434 
435  /* Give FIRST_NONOPT & LAST_NONOPT rational values if GNoptind has been
436  * moved back by the user (who may also have changed the arguments). */
437  if (last_nonopt > GNoptind)
439  if (first_nonopt > GNoptind)
441 
442  if (ordering == PERMUTE)
443  {
444  /* If we have just processed some options following some non-options,
445  * exchange them so that the options come first. */
446 
447  if ((first_nonopt != last_nonopt) && (last_nonopt != GNoptind) )
448  exchange ((char **) argv);
449  else if (last_nonopt != GNoptind)
451 
452  /* Skip any additional non-options
453  * and extend the range of non-options previously skipped. */
454 
455  while (GNoptind < argc && NONOPTION_P)
456  GNoptind++;
458  }
459 
460  /* The special ARGV-element `--' means premature end of options.
461  * Skip it like a null option,
462  * then exchange with previous non-options as if it were an option,
463  * then skip everything else like a non-option. */
464  if ((GNoptind != argc) && ! strcmp (argv[GNoptind], "--"))
465  {
466  GNoptind++;
467 
468  if ((first_nonopt != last_nonopt) && (last_nonopt != GNoptind) )
469  exchange ((char **) argv);
470  else if (first_nonopt == last_nonopt)
472  last_nonopt = argc;
473 
474  GNoptind = argc;
475  }
476 
477  /* If we have done all the ARGV-elements, stop the scan
478  * and back over any non-options that we skipped and permuted. */
479 
480  if (GNoptind == argc)
481  {
482  /* Set the next-arg-index to point at the non-options
483  * that we previously skipped, so the caller will digest them. */
484  if (first_nonopt != last_nonopt)
485  GNoptind = first_nonopt;
486  return -1;
487  }
488 
489  /* If we have come to a non-option and did not permute it,
490  * either stop the scan or describe it to the caller and pass it by. */
491 
492  if (NONOPTION_P)
493  {
494  if (ordering == REQUIRE_ORDER)
495  return -1;
496  GNoptarg = argv[GNoptind++];
497  return 1;
498  }
499 
500  /* We have found another option-ARGV-element.
501  * Skip the initial punctuation. */
502 
503  nextchar =
504  (argv[GNoptind] + 1 + (longopts != NULL && argv[GNoptind][1] == '-'));
505  }
506 
507  /* Decode the current option-ARGV-element. */
508 
509  /* Check whether the ARGV-element is a long option.
510  *
511  * If long_only and the ARGV-element has the form "-f", where f is
512  * a valid short option, don't consider it an abbreviated form of
513  * a long option that starts with f. Otherwise there would be no
514  * way to give the -f short option.
515  *
516  * On the other hand, if there's a long option "fubar" and
517  * the ARGV-element is "-fu", do consider that an abbreviation of
518  * the long option, just like "--fu", and not "-f" with arg "u".
519  *
520  * This distinction seems to be the most useful approach. */if ((longopts != NULL) &&
521  ((argv[GNoptind][1] == '-') ||
522  (long_only &&
523  (argv[GNoptind][2] || ! my_index (optstring, argv[GNoptind][1])))))
524  {
525  char *nameend;
526  const struct GNoption *p;
527  const struct GNoption *pfound = NULL;
528  int exact = 0;
529  int ambig = 0;
530  int indfound = -1;
531  int option_index;
532 
533  for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
534  /* Do nothing. */;
535 
536  /* Test all long options for either exact match
537  * or abbreviated matches. */
538  for (p = longopts, option_index = 0; p->name; p++, option_index++)
539  if (! strncmp (p->name, nextchar, nameend - nextchar))
540  {
541  if ((unsigned int) (nameend - nextchar) ==
542  (unsigned int) strlen (p->name))
543  {
544  /* Exact match found. */
545  pfound = p;
546  indfound = option_index;
547  exact = 1;
548  break;
549  }
550  else if (pfound == NULL)
551  {
552  /* First nonexact match found. */
553  pfound = p;
554  indfound = option_index;
555  }
556  else
557  /* Second or later nonexact match found. */
558  ambig = 1;
559  }
560 
561  if (ambig && ! exact)
562  {
563  if (GNopterr)
564  fprintf (stderr,
565  _ ("%s: option `%s' is ambiguous\n"),
566  argv[0],
567  argv[GNoptind]);
568  nextchar += strlen (nextchar);
569  GNoptind++;
570  return '?';
571  }
572 
573  if (pfound != NULL)
574  {
575  option_index = indfound;
576  GNoptind++;
577  if (*nameend)
578  {
579  /* Don't test has_arg with >, because some C compilers don't
580  * allow it to be used on enums. */
581  if (pfound->has_arg)
582  GNoptarg = nameend + 1;
583  else
584  {
585  if (GNopterr)
586  {
587  if (argv[GNoptind - 1][1] == '-')
588  /* --option */
589  fprintf (stderr,
590  _ ("%s: option `--%s' does not allow an argument\n"),
591  argv[0],
592  pfound->name);
593  else
594  /* +option or -option */
595  fprintf (stderr,
596  _ ("%s: option `%c%s' does not allow an argument\n"),
597  argv[0],
598  argv[GNoptind - 1][0],
599  pfound->name);
600  }
601  nextchar += strlen (nextchar);
602  return '?';
603  }
604  }
605  else if (pfound->has_arg == 1)
606  {
607  if (GNoptind < argc)
608  {
609  GNoptarg = argv[GNoptind++];
610  }
611  else
612  {
613  if (GNopterr)
614  {
615  fprintf (stderr,
616  _ ("%s: option `%s' requires an argument\n"),
617  argv[0],
618  argv[GNoptind - 1]);
619  }
620  nextchar += strlen (nextchar);
621  return (optstring[0] == ':') ? ':' : '?';
622  }
623  }
624  nextchar += strlen (nextchar);
625  if (longind != NULL)
626  *longind = option_index;
627  if (pfound->flag)
628  {
629  *(pfound->flag) = pfound->val;
630  return 0;
631  }
632  return pfound->val;
633  }
634 
635  /* Can't find it as a long option. If this is not getopt_long_only,
636  * or the option starts with '--' or is not a valid short
637  * option, then it's an error.
638  * Otherwise interpret it as a short option. */
639  if (! long_only || (argv[GNoptind][1] == '-') ||
640  (my_index (optstring, *nextchar) == NULL) )
641  {
642  if (GNopterr)
643  {
644  if (argv[GNoptind][1] == '-')
645  /* --option */
646  fprintf (stderr,
647  _ ("%s: unrecognized option `--%s'\n"),
648  argv[0],
649  nextchar);
650  else
651  /* +option or -option */
652  fprintf (stderr,
653  _ ("%s: unrecognized option `%c%s'\n"),
654  argv[0],
655  argv[GNoptind][0],
656  nextchar);
657  }
658  nextchar = (char *) "";
659  GNoptind++;
660  return '?';
661  }
662  }
663 
664  /* Look at and handle the next short option-character. */
665 
666  {
667  char c = *nextchar++;
668  char *temp = my_index (optstring, c);
669 
670  /* Increment `GNoptind' when we start to process its last character. */
671  if (*nextchar == '\0')
672  ++GNoptind;
673 
674  if ((temp == NULL) || (c == ':'))
675  {
676  if (GNopterr)
677  {
678  if (posixly_correct)
679  /* 1003.2 specifies the format of this message. */
680  fprintf (stderr, _ ("%s: illegal option -- %c\n"), argv[0], c);
681  else
682  fprintf (stderr, _ ("%s: invalid option -- %c\n"), argv[0], c);
683  }
684  return '?';
685  }
686  /* Convenience. Treat POSIX -W foo same as long option --foo */
687  if ((temp[0] == 'W') && (temp[1] == ';'))
688  {
689  char *nameend;
690  const struct GNoption *p;
691  const struct GNoption *pfound = NULL;
692  int exact = 0;
693  int ambig = 0;
694  int indfound = 0;
695  int option_index;
696 
697  /* This is an option that requires an argument. */
698  if (*nextchar != '\0')
699  {
700  GNoptarg = nextchar;
701  /* If we end this ARGV-element by taking the rest as an arg,
702  * we must advance to the next element now. */
703  GNoptind++;
704  }
705  else if (GNoptind == argc)
706  {
707  if (GNopterr)
708  {
709  /* 1003.2 specifies the format of this message. */
710  fprintf (stderr,
711  _ ("%s: option requires an argument -- %c\n"),
712  argv[0],
713  c);
714  }
715  if (optstring[0] == ':')
716  c = ':';
717  else
718  c = '?';
719  return c;
720  }
721  else
722  /* We already incremented `GNoptind' once;
723  * increment it again when taking next ARGV-elt as argument. */
724  GNoptarg = argv[GNoptind++];
725 
726  /* GNoptarg is now the argument, see if it's in the
727  * table of longopts. */
728 
729  for (nextchar = nameend = GNoptarg; *nameend && *nameend != '=';
730  nameend++)
731  /* Do nothing. */;
732 
733  /* Test all long options for either exact match
734  * or abbreviated matches. */
735  if (longopts != NULL)
736  for (p = longopts, option_index = 0; p->name; p++, option_index++)
737  if (! strncmp (p->name, nextchar, nameend - nextchar))
738  {
739  if ((unsigned int) (nameend - nextchar) == strlen (p->name))
740  {
741  /* Exact match found. */
742  pfound = p;
743  indfound = option_index;
744  exact = 1;
745  break;
746  }
747  else if (pfound == NULL)
748  {
749  /* First nonexact match found. */
750  pfound = p;
751  indfound = option_index;
752  }
753  else
754  /* Second or later nonexact match found. */
755  ambig = 1;
756  }
757  if (ambig && ! exact)
758  {
759  if (GNopterr)
760  fprintf (stderr,
761  _ ("%s: option `-W %s' is ambiguous\n"),
762  argv[0],
763  argv[GNoptind]);
764  nextchar += strlen (nextchar);
765  GNoptind++;
766  return '?';
767  }
768  if (pfound != NULL)
769  {
770  option_index = indfound;
771  if (*nameend)
772  {
773  /* Don't test has_arg with >, because some C compilers don't
774  * allow it to be used on enums. */
775  if (pfound->has_arg)
776  GNoptarg = nameend + 1;
777  else
778  {
779  if (GNopterr)
780  fprintf (stderr,
781  _ ("%s: option `-W %s' does not allow an argument\n"),
782  argv[0],
783  pfound->name);
784 
785  nextchar += strlen (nextchar);
786  return '?';
787  }
788  }
789  else if (pfound->has_arg == 1)
790  {
791  if (GNoptind < argc)
792  GNoptarg = argv[GNoptind++];
793  else
794  {
795  if (GNopterr)
796  fprintf (stderr,
797  _ ("%s: option `%s' requires an argument\n"),
798  argv[0],
799  argv[GNoptind - 1]);
800  nextchar += strlen (nextchar);
801  return optstring[0] == ':' ? ':' : '?';
802  }
803  }
804  nextchar += strlen (nextchar);
805  if (longind != NULL)
806  *longind = option_index;
807  if (pfound->flag)
808  {
809  *(pfound->flag) = pfound->val;
810  return 0;
811  }
812  return pfound->val;
813  }
814  nextchar = NULL;
815  return 'W'; /* Let the application handle it. */
816  }
817  if (temp[1] == ':')
818  {
819  if (temp[2] == ':')
820  {
821  /* This is an option that accepts an argument optionally. */
822  if (*nextchar != '\0')
823  {
824  GNoptarg = nextchar;
825  GNoptind++;
826  }
827  else
828  GNoptarg = NULL;
829  nextchar = NULL;
830  }
831  else
832  {
833  /* This is an option that requires an argument. */
834  if (*nextchar != '\0')
835  {
836  GNoptarg = nextchar;
837  /* If we end this ARGV-element by taking the rest as an arg,
838  * we must advance to the next element now. */
839  GNoptind++;
840  }
841  else if (GNoptind == argc)
842  {
843  if (GNopterr)
844  {
845  /* 1003.2 specifies the format of this message. */
846  fprintf (stderr,
847  _ ("%s: option requires an argument -- %c\n"),
848  argv[0],
849  c);
850  }
851  if (optstring[0] == ':')
852  c = ':';
853  else
854  c = '?';
855  }
856  else
857  /* We already incremented `GNoptind' once;
858  * increment it again when taking next ARGV-elt as argument. */
859  GNoptarg = argv[GNoptind++];
860  nextchar = NULL;
861  }
862  }
863  return c;
864  }
865 }
static int last_nonopt
Definition: getopt.c:230
int has_arg
Definition: getopt.c:92
static char * GNoptarg
Definition: getopt.c:118
static const char * _getopt_initialize(int argc, char *const *argv, const char *optstring)
Definition: getopt.c:315
static void exchange(char **argv)
Definition: getopt.c:250
#define _(msgid)
Definition: getopt.c:62
const char * name
Definition: getopt.c:89
static char * posixly_correct
Definition: getopt.c:177
static int GNoptind
Definition: getopt.c:133
int val
Definition: getopt.c:94
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
static int first_nonopt
Definition: getopt.c:229
static char * nextchar
Definition: getopt.c:142
static char * my_index(const char *str, int chr)
Definition: getopt.c:195
int * flag
Definition: getopt.c:93
#define NONOPTION_P
static enum @80 ordering
Here is the call graph for this function:
Here is the caller graph for this function:

◆ GNgetopt_long()

static int GNgetopt_long ( int  argc,
char *const *  argv,
const char *  options,
const struct GNoption long_options,
int *  opt_index 
)
static

Definition at line 869 of file getopt.c.

References GN_getopt_internal().

Referenced by GNUNET_GETOPT_run().

874 {
875  return GN_getopt_internal (argc, argv, options, long_options, opt_index, 0);
876 }
struct GNUNET_GETOPT_CommandLineOption options[]
Definition: 002.c:5
static int GN_getopt_internal(int argc, char *const *argv, const char *optstring, const struct GNoption *longopts, int *longind, int long_only)
Definition: getopt.c:405
Here is the call graph for this function:
Here is the caller graph for this function:

Variable Documentation

◆ GNoptarg

char* GNoptarg = NULL
static

Definition at line 118 of file getopt.c.

Referenced by GN_getopt_internal(), and GNUNET_GETOPT_run().

◆ GNoptind

int GNoptind = 1
static

Definition at line 133 of file getopt.c.

Referenced by _getopt_initialize(), exchange(), GN_getopt_internal(), and GNUNET_GETOPT_run().

◆ nextchar

char* nextchar
static

Definition at line 142 of file getopt.c.

Referenced by _getopt_initialize(), and GN_getopt_internal().

◆ ordering

enum { ... } ordering

◆ posixly_correct

char* posixly_correct
static

Definition at line 177 of file getopt.c.

Referenced by _getopt_initialize(), and GN_getopt_internal().

◆ first_nonopt

int first_nonopt
static

Definition at line 229 of file getopt.c.

Referenced by _getopt_initialize(), exchange(), and GN_getopt_internal().

◆ last_nonopt

int last_nonopt
static

Definition at line 230 of file getopt.c.

Referenced by _getopt_initialize(), exchange(), and GN_getopt_internal().