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

Referenced by GN_getopt_internal(), and GNUNET_GETOPT_run().

◆ SWAP_FLAGS

#define SWAP_FLAGS (   ch1,
  ch2 
)

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

Function Documentation

◆ getenv()

char* getenv ( )

◆ my_index()

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

Definition at line 194 of file getopt.c.

Referenced by GN_getopt_internal().

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

◆ exchange()

static void exchange ( char **  argv)
static

Definition at line 246 of file getopt.c.

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

Referenced by GN_getopt_internal().

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

310 {
311  /* Start processing options with ARGV-element 1 (since ARGV-element 0
312  * is the program name); the sequence of previously skipped
313  * non-option ARGV-elements is empty. */
314 
316 
317  nextchar = NULL;
318 
319  posixly_correct = getenv("POSIXLY_CORRECT");
320 
321  /* Determine how to handle the ordering of options and nonoptions. */
322 
323  if (optstring[0] == '-')
324  {
326  ++optstring;
327  }
328  else if (optstring[0] == '+')
329  {
331  ++optstring;
332  }
333  else if (posixly_correct != NULL)
335  else
336  ordering = PERMUTE;
337 
338  return optstring;
339 }
static int last_nonopt
Definition: getopt.c:227
static enum @83 ordering
static char * posixly_correct
Definition: getopt.c:176
static int GNoptind
Definition: getopt.c:132
static int first_nonopt
Definition: getopt.c:226
char * getenv()
static char * nextchar
Definition: getopt.c:141
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 398 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().

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

References GN_getopt_internal().

Referenced by GNUNET_GETOPT_run().

869 {
870  return GN_getopt_internal(argc, argv, options, long_options, opt_index, 0);
871 }
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:398
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 117 of file getopt.c.

Referenced by GN_getopt_internal(), and GNUNET_GETOPT_run().

◆ GNoptind

int GNoptind = 1
static

Definition at line 132 of file getopt.c.

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

◆ nextchar

char* nextchar
static

Definition at line 141 of file getopt.c.

Referenced by _getopt_initialize(), and GN_getopt_internal().

◆ ordering

enum { ... } ordering

◆ posixly_correct

char* posixly_correct
static

Definition at line 176 of file getopt.c.

Referenced by _getopt_initialize(), and GN_getopt_internal().

◆ first_nonopt

int first_nonopt
static

Definition at line 226 of file getopt.c.

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

◆ last_nonopt

int last_nonopt
static

Definition at line 227 of file getopt.c.

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