GNUnet  0.10.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 68 of file getopt.c.

Referenced by GN_getopt_internal(), and GNUNET_GETOPT_run().

◆ SWAP_FLAGS

#define SWAP_FLAGS (   ch1,
  ch2 
)

Definition at line 236 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 180 of file getopt.c.

Function Documentation

◆ getenv()

char* getenv ( )

◆ my_index()

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

Definition at line 201 of file getopt.c.

Referenced by GN_getopt_internal().

202 {
203  while (*str)
204  {
205  if (*str == chr)
206  return (char *) str;
207  str++;
208  }
209  return 0;
210 }
Here is the caller graph for this function:

◆ exchange()

static void exchange ( char **  argv)
static

Definition at line 253 of file getopt.c.

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

Referenced by GN_getopt_internal().

254 {
255  int bottom = first_nonopt;
256  int middle = last_nonopt;
257  int top = GNoptind;
258  char *tem;
259 
260  /* Exchange the shorter segment with the far end of the longer segment.
261  * That puts the shorter segment into the right place.
262  * It leaves the longer segment in the right place overall,
263  * but it consists of two parts that need to be swapped next. */
264 
265  while (top > middle && middle > bottom)
266  {
267  if (top - middle > middle - bottom)
268  {
269  /* Bottom segment is the short one. */
270  int len = middle - bottom;
271  register int i;
272 
273  /* Swap it with the top part of the top segment. */
274  for (i = 0; i < len; i++)
275  {
276  tem = argv[bottom + i];
277  argv[bottom + i] = argv[top - (middle - bottom) + i];
278  argv[top - (middle - bottom) + i] = tem;
279  SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
280  }
281  /* Exclude the moved bottom segment from further swapping. */
282  top -= len;
283  }
284  else
285  {
286  /* Top segment is the short one. */
287  int len = top - middle;
288  register int i;
289 
290  /* Swap it with the bottom part of the bottom segment. */
291  for (i = 0; i < len; i++)
292  {
293  tem = argv[bottom + i];
294  argv[bottom + i] = argv[middle + i];
295  argv[middle + i] = tem;
296  SWAP_FLAGS (bottom + i, middle + i);
297  }
298  /* Exclude the moved top segment from further swapping. */
299  bottom += len;
300  }
301  }
302 
303  /* Update records for the slots the non-options now occupy. */
304 
307 }
#define SWAP_FLAGS(ch1, ch2)
Definition: getopt.c:236
static int last_nonopt
Definition: getopt.c:234
struct GNUNET_ATS_TEST_Topology * top
Definition: ats-testing.c:53
static int GNoptind
Definition: getopt.c:139
static int first_nonopt
Definition: getopt.c:233
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 316 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().

317 {
318  /* Start processing options with ARGV-element 1 (since ARGV-element 0
319  * is the program name); the sequence of previously skipped
320  * non-option ARGV-elements is empty. */
321 
323 
324  nextchar = NULL;
325 
326  posixly_correct = getenv ("POSIXLY_CORRECT");
327 
328  /* Determine how to handle the ordering of options and nonoptions. */
329 
330  if (optstring[0] == '-')
331  {
333  ++optstring;
334  }
335  else if (optstring[0] == '+')
336  {
338  ++optstring;
339  }
340  else if (posixly_correct != NULL)
342  else
343  ordering = PERMUTE;
344 
345  return optstring;
346 }
static int last_nonopt
Definition: getopt.c:234
static enum @83 ordering
static char * posixly_correct
Definition: getopt.c:183
static int GNoptind
Definition: getopt.c:139
static int first_nonopt
Definition: getopt.c:233
char * getenv()
static char * nextchar
Definition: getopt.c:148
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, FPRINTF, 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 
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. */
521 
522  if (longopts != NULL &&
523  (argv[GNoptind][1] == '-' ||
524  (long_only &&
525  (argv[GNoptind][2] || ! my_index (optstring, argv[GNoptind][1])))))
526  {
527  char *nameend;
528  const struct GNoption *p;
529  const struct GNoption *pfound = NULL;
530  int exact = 0;
531  int ambig = 0;
532  int indfound = -1;
533  int option_index;
534 
535  for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
536  /* Do nothing. */;
537 
538  /* Test all long options for either exact match
539  * or abbreviated matches. */
540  for (p = longopts, option_index = 0; p->name; p++, option_index++)
541  if (! strncmp (p->name, nextchar, nameend - nextchar))
542  {
543  if ((unsigned int) (nameend - nextchar) ==
544  (unsigned int) strlen (p->name))
545  {
546  /* Exact match found. */
547  pfound = p;
548  indfound = option_index;
549  exact = 1;
550  break;
551  }
552  else if (pfound == NULL)
553  {
554  /* First nonexact match found. */
555  pfound = p;
556  indfound = option_index;
557  }
558  else
559  /* Second or later nonexact match found. */
560  ambig = 1;
561  }
562 
563  if (ambig && ! exact)
564  {
565  if (GNopterr)
566  FPRINTF (stderr,
567  _ ("%s: option `%s' is ambiguous\n"),
568  argv[0],
569  argv[GNoptind]);
570  nextchar += strlen (nextchar);
571  GNoptind++;
572  return '?';
573  }
574 
575  if (pfound != NULL)
576  {
577  option_index = indfound;
578  GNoptind++;
579  if (*nameend)
580  {
581  /* Don't test has_arg with >, because some C compilers don't
582  * allow it to be used on enums. */
583  if (pfound->has_arg)
584  GNoptarg = nameend + 1;
585  else
586  {
587  if (GNopterr)
588  {
589  if (argv[GNoptind - 1][1] == '-')
590  /* --option */
591  FPRINTF (stderr,
592  _ ("%s: option `--%s' does not allow an argument\n"),
593  argv[0],
594  pfound->name);
595  else
596  /* +option or -option */
597  FPRINTF (stderr,
598  _ ("%s: option `%c%s' does not allow an argument\n"),
599  argv[0],
600  argv[GNoptind - 1][0],
601  pfound->name);
602  }
603  nextchar += strlen (nextchar);
604  return '?';
605  }
606  }
607  else if (pfound->has_arg == 1)
608  {
609  if (GNoptind < argc)
610  {
611  GNoptarg = argv[GNoptind++];
612  }
613  else
614  {
615  if (GNopterr)
616  {
617  FPRINTF (stderr,
618  _ ("%s: option `%s' requires an argument\n"),
619  argv[0],
620  argv[GNoptind - 1]);
621  }
622  nextchar += strlen (nextchar);
623  return (optstring[0] == ':') ? ':' : '?';
624  }
625  }
626  nextchar += strlen (nextchar);
627  if (longind != NULL)
628  *longind = option_index;
629  if (pfound->flag)
630  {
631  *(pfound->flag) = pfound->val;
632  return 0;
633  }
634  return pfound->val;
635  }
636 
637  /* Can't find it as a long option. If this is not getopt_long_only,
638  * or the option starts with '--' or is not a valid short
639  * option, then it's an error.
640  * Otherwise interpret it as a short option. */
641  if (! long_only || argv[GNoptind][1] == '-' ||
642  my_index (optstring, *nextchar) == NULL)
643  {
644  if (GNopterr)
645  {
646  if (argv[GNoptind][1] == '-')
647  /* --option */
648  FPRINTF (stderr,
649  _ ("%s: unrecognized option `--%s'\n"),
650  argv[0],
651  nextchar);
652  else
653  /* +option or -option */
654  FPRINTF (stderr,
655  _ ("%s: unrecognized option `%c%s'\n"),
656  argv[0],
657  argv[GNoptind][0],
658  nextchar);
659  }
660  nextchar = (char *) "";
661  GNoptind++;
662  return '?';
663  }
664  }
665 
666  /* Look at and handle the next short option-character. */
667 
668  {
669  char c = *nextchar++;
670  char *temp = my_index (optstring, c);
671 
672  /* Increment `GNoptind' when we start to process its last character. */
673  if (*nextchar == '\0')
674  ++GNoptind;
675 
676  if (temp == NULL || c == ':')
677  {
678  if (GNopterr)
679  {
680  if (posixly_correct)
681  /* 1003.2 specifies the format of this message. */
682  FPRINTF (stderr, _ ("%s: illegal option -- %c\n"), argv[0], c);
683  else
684  FPRINTF (stderr, _ ("%s: invalid option -- %c\n"), argv[0], c);
685  }
686  return '?';
687  }
688  /* Convenience. Treat POSIX -W foo same as long option --foo */
689  if (temp[0] == 'W' && temp[1] == ';')
690  {
691  char *nameend;
692  const struct GNoption *p;
693  const struct GNoption *pfound = NULL;
694  int exact = 0;
695  int ambig = 0;
696  int indfound = 0;
697  int option_index;
698 
699  /* This is an option that requires an argument. */
700  if (*nextchar != '\0')
701  {
702  GNoptarg = nextchar;
703  /* If we end this ARGV-element by taking the rest as an arg,
704  * we must advance to the next element now. */
705  GNoptind++;
706  }
707  else if (GNoptind == argc)
708  {
709  if (GNopterr)
710  {
711  /* 1003.2 specifies the format of this message. */
712  FPRINTF (stderr,
713  _ ("%s: option requires an argument -- %c\n"),
714  argv[0],
715  c);
716  }
717  if (optstring[0] == ':')
718  c = ':';
719  else
720  c = '?';
721  return c;
722  }
723  else
724  /* We already incremented `GNoptind' once;
725  * increment it again when taking next ARGV-elt as argument. */
726  GNoptarg = argv[GNoptind++];
727 
728  /* GNoptarg is now the argument, see if it's in the
729  * table of longopts. */
730 
731  for (nextchar = nameend = GNoptarg; *nameend && *nameend != '=';
732  nameend++)
733  /* Do nothing. */;
734 
735  /* Test all long options for either exact match
736  * or abbreviated matches. */
737  if (longopts != NULL)
738  for (p = longopts, option_index = 0; p->name; p++, option_index++)
739  if (! strncmp (p->name, nextchar, nameend - nextchar))
740  {
741  if ((unsigned int) (nameend - nextchar) == strlen (p->name))
742  {
743  /* Exact match found. */
744  pfound = p;
745  indfound = option_index;
746  exact = 1;
747  break;
748  }
749  else if (pfound == NULL)
750  {
751  /* First nonexact match found. */
752  pfound = p;
753  indfound = option_index;
754  }
755  else
756  /* Second or later nonexact match found. */
757  ambig = 1;
758  }
759  if (ambig && ! exact)
760  {
761  if (GNopterr)
762  FPRINTF (stderr,
763  _ ("%s: option `-W %s' is ambiguous\n"),
764  argv[0],
765  argv[GNoptind]);
766  nextchar += strlen (nextchar);
767  GNoptind++;
768  return '?';
769  }
770  if (pfound != NULL)
771  {
772  option_index = indfound;
773  if (*nameend)
774  {
775  /* Don't test has_arg with >, because some C compilers don't
776  * allow it to be used on enums. */
777  if (pfound->has_arg)
778  GNoptarg = nameend + 1;
779  else
780  {
781  if (GNopterr)
782  FPRINTF (stderr,
783  _ ("%s: option `-W %s' does not allow an argument\n"),
784  argv[0],
785  pfound->name);
786 
787  nextchar += strlen (nextchar);
788  return '?';
789  }
790  }
791  else if (pfound->has_arg == 1)
792  {
793  if (GNoptind < argc)
794  GNoptarg = argv[GNoptind++];
795  else
796  {
797  if (GNopterr)
798  FPRINTF (stderr,
799  _ ("%s: option `%s' requires an argument\n"),
800  argv[0],
801  argv[GNoptind - 1]);
802  nextchar += strlen (nextchar);
803  return optstring[0] == ':' ? ':' : '?';
804  }
805  }
806  nextchar += strlen (nextchar);
807  if (longind != NULL)
808  *longind = option_index;
809  if (pfound->flag)
810  {
811  *(pfound->flag) = pfound->val;
812  return 0;
813  }
814  return pfound->val;
815  }
816  nextchar = NULL;
817  return 'W'; /* Let the application handle it. */
818  }
819  if (temp[1] == ':')
820  {
821  if (temp[2] == ':')
822  {
823  /* This is an option that accepts an argument optionally. */
824  if (*nextchar != '\0')
825  {
826  GNoptarg = nextchar;
827  GNoptind++;
828  }
829  else
830  GNoptarg = NULL;
831  nextchar = NULL;
832  }
833  else
834  {
835  /* This is an option that requires an argument. */
836  if (*nextchar != '\0')
837  {
838  GNoptarg = nextchar;
839  /* If we end this ARGV-element by taking the rest as an arg,
840  * we must advance to the next element now. */
841  GNoptind++;
842  }
843  else if (GNoptind == argc)
844  {
845  if (GNopterr)
846  {
847  /* 1003.2 specifies the format of this message. */
848  FPRINTF (stderr,
849  _ ("%s: option requires an argument -- %c\n"),
850  argv[0],
851  c);
852  }
853  if (optstring[0] == ':')
854  c = ':';
855  else
856  c = '?';
857  }
858  else
859  /* We already incremented `GNoptind' once;
860  * increment it again when taking next ARGV-elt as argument. */
861  GNoptarg = argv[GNoptind++];
862  nextchar = NULL;
863  }
864  }
865  return c;
866  }
867 }
static int last_nonopt
Definition: getopt.c:234
int has_arg
Definition: getopt.c:98
static char * GNoptarg
Definition: getopt.c:124
#define FPRINTF
Definition: plibc.h:683
static const char * _getopt_initialize(int argc, char *const *argv, const char *optstring)
Definition: getopt.c:316
static enum @83 ordering
static void exchange(char **argv)
Definition: getopt.c:253
#define _(msgid)
Definition: getopt.c:68
const char * name
Definition: getopt.c:95
static char * posixly_correct
Definition: getopt.c:183
static int GNoptind
Definition: getopt.c:139
int val
Definition: getopt.c:100
static struct GNUNET_OS_Process * p
Helper process we started.
Definition: gnunet-qr.c:59
static int first_nonopt
Definition: getopt.c:233
static char * nextchar
Definition: getopt.c:148
static char * my_index(const char *str, int chr)
Definition: getopt.c:201
int * flag
Definition: getopt.c:99
#define NONOPTION_P
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 871 of file getopt.c.

References GN_getopt_internal().

Referenced by GNUNET_GETOPT_run().

876 {
877  return GN_getopt_internal (argc, argv, options, long_options, opt_index, 0);
878 }
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 124 of file getopt.c.

Referenced by GN_getopt_internal(), and GNUNET_GETOPT_run().

◆ GNoptind

int GNoptind = 1
static

Definition at line 139 of file getopt.c.

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

◆ nextchar

char* nextchar
static

Definition at line 148 of file getopt.c.

Referenced by _getopt_initialize(), and GN_getopt_internal().

◆ ordering

enum { ... } ordering

◆ posixly_correct

char* posixly_correct
static

Definition at line 183 of file getopt.c.

Referenced by _getopt_initialize(), and GN_getopt_internal().

◆ first_nonopt

int first_nonopt
static

Definition at line 233 of file getopt.c.

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

◆ last_nonopt

int last_nonopt
static

Definition at line 234 of file getopt.c.

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