GNUnet  0.20.0
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 51 of file getopt.c.

◆ LOG_STRERROR

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

Definition at line 53 of file getopt.c.

◆ _

#define _ (   msgid)    (msgid)

Definition at line 63 of file getopt.c.

◆ SWAP_FLAGS

#define SWAP_FLAGS (   ch1,
  ch2 
)

Definition at line 233 of file getopt.c.

◆ NONOPTION_P

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

Enumeration Type Documentation

◆ anonymous enum

anonymous enum
Enumerator
REQUIRE_ORDER 
PERMUTE 
RETURN_IN_ORDER 

Definition at line 175 of file getopt.c.

@ REQUIRE_ORDER
Definition: getopt.c:175
@ RETURN_IN_ORDER
Definition: getopt.c:175
@ PERMUTE
Definition: getopt.c:175
static enum @72 ordering

Function Documentation

◆ getenv()

◆ my_index()

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

Definition at line 196 of file getopt.c.

197 {
198  while (*str)
199  {
200  if (*str == chr)
201  return (char *) str;
202  str++;
203  }
204  return 0;
205 }

Referenced by GN_getopt_internal().

Here is the caller graph for this function:

◆ exchange()

static void exchange ( char **  argv)
static

Definition at line 251 of file getopt.c.

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

References first_nonopt, GNoptind, last_nonopt, len, and SWAP_FLAGS.

Referenced by GN_getopt_internal().

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.

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 char * nextchar
Definition: getopt.c:143
static char * posixly_correct
Definition: getopt.c:178
char * getenv()

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

Referenced by GN_getopt_internal().

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 406 of file getopt.c.

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

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().

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 870 of file getopt.c.

875 {
876  return GN_getopt_internal (argc, argv, options, long_options, opt_index, 0);
877 }
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:406

References GN_getopt_internal(), and options.

Referenced by GNUNET_GETOPT_run().

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 119 of file getopt.c.

Referenced by GN_getopt_internal(), and GNUNET_GETOPT_run().

◆ GNoptind

int GNoptind = 1
static

Definition at line 134 of file getopt.c.

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

◆ nextchar

char* nextchar
static

Definition at line 143 of file getopt.c.

Referenced by _getopt_initialize(), and GN_getopt_internal().

◆ 

enum { ... } ordering

◆ posixly_correct

char* posixly_correct
static

Definition at line 178 of file getopt.c.

Referenced by _getopt_initialize(), and GN_getopt_internal().

◆ first_nonopt

int first_nonopt
static

Definition at line 230 of file getopt.c.

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

◆ last_nonopt

int last_nonopt
static

Definition at line 231 of file getopt.c.

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