123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017 |
- /* Getopt for GNU.
- NOTE: getopt is now part of the C library, so if you don't know what
- "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
- before changing it!
- Copyright (C) 1987, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97
- Free Software Foundation, Inc.
- NOTE: The canonical source of this file is maintained with the GNU C Library.
- Bugs can be reported to bug-glibc@prep.ai.mit.edu.
- This program is free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 3, or (at your option) any
- later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
- USA.
- This code was heavily modified for GNUnet.
- Copyright (C) 2006, 2017 Christian Grothoff
- */
- /**
- * @file util/getopt.c
- * @brief GNU style option parsing
- *
- * TODO: get rid of statics (make reentrant) and
- * replace main GNU getopt parser with one that
- * actually fits our API.
- */
- #include "platform.h"
- #include "gnunet_util_lib.h"
- #ifdef VMS
- #include <unixlib.h>
- #if HAVE_STRING_H - 0
- #include <string.h>
- #endif
- #endif
- #define LOG(kind, ...) GNUNET_log_from (kind, "util-getopt", __VA_ARGS__)
- #define LOG_STRERROR(kind, syscall) \
- GNUNET_log_from_strerror (kind, "util-getopt", syscall)
- #ifndef _
- /* This is for other GNU distributions with internationalized messages.
- When compiling libc, the _ macro is predefined. */
- #ifdef HAVE_LIBINTL_H
- #include <libintl.h>
- #define _(msgid) gettext (msgid)
- #else
- #define _(msgid) (msgid)
- #endif
- #endif
- /* Describe the long-named options requested by the application.
- The LONG_OPTIONS argument to getopt_long or getopt_long_only is a vector
- of `struct GNoption' terminated by an element containing a name which is
- zero.
- The field `has_arg' is:
- no_argument (or 0) if the option does not take an argument,
- required_argument (or 1) if the option requires an argument,
- optional_argument (or 2) if the option takes an optional argument.
- If the field `flag' is not NULL, it points to a variable that is set
- to the value given in the field `val' when the option is found, but
- left unchanged if the option is not found.
- To have a long-named option do something other than set an `int' to
- a compiled-in constant, such as set a value from `GNoptarg', set the
- option's `flag' field to zero and its `val' field to a nonzero
- value (the equivalent single-letter option character, if there is
- one). For long options that have a zero `flag' field, `getopt'
- returns the contents of the `val' field. */
- struct GNoption
- {
- const char *name;
- /* has_arg can't be an enum because some compilers complain about
- * type mismatches in all the code that assumes it is an int. */
- int has_arg;
- int *flag;
- int val;
- };
- /* This version of `getopt' appears to the caller like standard Unix `getopt'
- but it behaves differently for the user, since it allows the user
- to intersperse the options with the other arguments.
- As `getopt' works, it permutes the elements of ARGV so that,
- when it is done, all the options precede everything else. Thus
- all application programs are extended to handle flexible argument order.
- Setting the environment variable POSIXLY_CORRECT disables permutation.
- Then the behavior is completely standard.
- GNU application programs can use a third alternative mode in which
- they can distinguish the relative order of options and other arguments. */
- /* For communication from `getopt' to the caller.
- When `getopt' finds an option that takes an argument,
- the argument value is returned here.
- Also, when `ordering' is RETURN_IN_ORDER,
- each non-option ARGV-element is returned here. */
- static char *GNoptarg = NULL;
- /* Index in ARGV of the next element to be scanned.
- This is used for communication to and from the caller
- and for communication between successive calls to `getopt'.
- On entry to `getopt', zero means this is the first call; initialize.
- When `getopt' returns -1, this is the index of the first of the
- non-option elements that the caller should itself scan.
- Otherwise, `GNoptind' communicates from one call to the next
- how much of ARGV has been scanned so far. */
- /* 1003.2 says this must be 1 before any call. */
- static int GNoptind = 1;
- /* The next char to be scanned in the option-element
- in which the last option character we returned was found.
- This allows us to pick up the scan where we left off.
- If this is zero, or a null string, it means resume the scan
- by advancing to the next ARGV-element. */
- static char *nextchar;
- /* Describe how to deal with options that follow non-option ARGV-elements.
- If the caller did not specify anything,
- the default is REQUIRE_ORDER if the environment variable
- POSIXLY_CORRECT is defined, PERMUTE otherwise.
- REQUIRE_ORDER means don't recognize them as options;
- stop option processing when the first non-option is seen.
- This is what Unix does.
- This mode of operation is selected by either setting the environment
- variable POSIXLY_CORRECT, or using `+' as the first character
- of the list of option characters.
- PERMUTE is the default. We GNUNET_CRYPTO_random_permute the contents of ARGV as we scan,
- so that eventually all the non-options are at the end. This allows options
- to be given in any order, even with programs that were not written to
- expect this.
- RETURN_IN_ORDER is an option available to programs that were written
- to expect GNoptions and other ARGV-elements in any order and that care about
- the ordering of the two. We describe each non-option ARGV-element
- as if it were the argument of an option with character code 1.
- Using `-' as the first character of the list of option characters
- selects this mode of operation.
- The special argument `--' forces an end of option-scanning regardless
- of the value of `ordering'. In the case of RETURN_IN_ORDER, only
- `--' can cause `getopt' to return -1 with `GNoptind' != ARGC. */
- static enum { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER } ordering;
- /* Value of POSIXLY_CORRECT environment variable. */
- static char *posixly_correct;
- #ifdef __GNU_LIBRARY__
- /* We want to avoid inclusion of string.h with non-GNU libraries
- because there are many ways it can cause trouble.
- On some systems, it contains special magic macros that don't work
- in GCC. */
- #include <string.h>
- #define my_index strchr
- #else
- /* Avoid depending on library functions or files
- whose names are inconsistent. */
- char *
- getenv ();
- static char *
- my_index (const char *str, int chr)
- {
- while (*str)
- {
- if (*str == chr)
- return (char *) str;
- str++;
- }
- return 0;
- }
- /* If using GCC, we can safely declare strlen this way.
- If not using GCC, it is ok not to declare it. */
- #ifdef __GNUC__
- /* Note that Motorola Delta 68k R3V7 comes with GCC but not stddef.h.
- That was relevant to code that was here before. */
- #if ! defined(__STDC__) || ! __STDC__
- /* gcc with -traditional declares the built-in strlen to return int,
- and has done so at least since version 2.4.5. -- rms. */
- extern int
- strlen (const char *);
- #endif /* not __STDC__ */
- #endif /* __GNUC__ */
- #endif /* not __GNU_LIBRARY__ */
- /* Handle permutation of arguments. */
- /* Describe the part of ARGV that contains non-options that have
- been skipped. `first_nonopt' is the index in ARGV of the first of them;
- `last_nonopt' is the index after the last of them. */
- static int first_nonopt;
- static int last_nonopt;
- #define SWAP_FLAGS(ch1, ch2)
- /* Exchange two adjacent subsequences of ARGV.
- One subsequence is elements [first_nonopt,last_nonopt)
- which contains all the non-options that have been skipped so far.
- The other is elements [last_nonopt,GNoptind), which contains all
- the options processed since those non-options were skipped.
- `first_nonopt' and `last_nonopt' are relocated so that they describe
- the new indices of the non-options in ARGV after they are moved. */
- #if defined(__STDC__) && __STDC__
- static void
- exchange (char **);
- #endif
- static void
- exchange (char **argv)
- {
- int bottom = first_nonopt;
- int middle = last_nonopt;
- int top = GNoptind;
- char *tem;
- /* Exchange the shorter segment with the far end of the longer segment.
- * That puts the shorter segment into the right place.
- * It leaves the longer segment in the right place overall,
- * but it consists of two parts that need to be swapped next. */
- while (top > middle && middle > bottom)
- {
- if (top - middle > middle - bottom)
- {
- /* Bottom segment is the short one. */
- int len = middle - bottom;
- register int i;
- /* Swap it with the top part of the top segment. */
- for (i = 0; i < len; i++)
- {
- tem = argv[bottom + i];
- argv[bottom + i] = argv[top - (middle - bottom) + i];
- argv[top - (middle - bottom) + i] = tem;
- SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
- }
- /* Exclude the moved bottom segment from further swapping. */
- top -= len;
- }
- else
- {
- /* Top segment is the short one. */
- int len = top - middle;
- register int i;
- /* Swap it with the bottom part of the bottom segment. */
- for (i = 0; i < len; i++)
- {
- tem = argv[bottom + i];
- argv[bottom + i] = argv[middle + i];
- argv[middle + i] = tem;
- SWAP_FLAGS (bottom + i, middle + i);
- }
- /* Exclude the moved top segment from further swapping. */
- bottom += len;
- }
- }
- /* Update records for the slots the non-options now occupy. */
- first_nonopt += (GNoptind - last_nonopt);
- last_nonopt = GNoptind;
- }
- /* Initialize the internal data when the first call is made. */
- #if defined(__STDC__) && __STDC__
- static const char *
- _getopt_initialize (int, char *const *, const char *);
- #endif
- static const char *
- _getopt_initialize (int argc, char *const *argv, const char *optstring)
- {
- /* Start processing options with ARGV-element 1 (since ARGV-element 0
- * is the program name); the sequence of previously skipped
- * non-option ARGV-elements is empty. */
- first_nonopt = last_nonopt = GNoptind;
- nextchar = NULL;
- posixly_correct = getenv ("POSIXLY_CORRECT");
- /* Determine how to handle the ordering of options and nonoptions. */
- if (optstring[0] == '-')
- {
- ordering = RETURN_IN_ORDER;
- ++optstring;
- }
- else if (optstring[0] == '+')
- {
- ordering = REQUIRE_ORDER;
- ++optstring;
- }
- else if (posixly_correct != NULL)
- ordering = REQUIRE_ORDER;
- else
- ordering = PERMUTE;
- return optstring;
- }
- /* Scan elements of ARGV (whose length is ARGC) for option characters
- given in OPTSTRING.
- If an element of ARGV starts with '-', and is not exactly "-" or "--",
- then it is an option element. The characters of this element
- (aside from the initial '-') are option characters. If `getopt'
- is called repeatedly, it returns successively each of the option characters
- from each of the option elements.
- If `getopt' finds another option character, it returns that character,
- updating `GNoptind' and `nextchar' so that the next call to `getopt' can
- resume the scan with the following option character or ARGV-element.
- If there are no more option characters, `getopt' returns -1.
- Then `GNoptind' is the index in ARGV of the first ARGV-element
- that is not an option. (The ARGV-elements have been permuted
- so that those that are not options now come last.)
- OPTSTRING is a string containing the legitimate option characters.
- If an option character is seen that is not listed in OPTSTRING,
- return '?' after printing an error message. If you set `GNopterr' to
- zero, the error message is suppressed but we still return '?'.
- If a char in OPTSTRING is followed by a colon, that means it wants an arg,
- so the following text in the same ARGV-element, or the text of the following
- ARGV-element, is returned in `GNoptarg'. Two colons mean an option that
- wants an optional arg; if there is text in the current ARGV-element,
- it is returned in `GNoptarg', otherwise `GNoptarg' is set to zero.
- If OPTSTRING starts with `-' or `+', it requests different methods of
- handling the non-option ARGV-elements.
- See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
- Long-named options begin with `--' instead of `-'.
- Their names may be abbreviated as long as the abbreviation is unique
- or is an exact match for some defined option. If they have an
- argument, it follows the option name in the same ARGV-element, separated
- from the option name by a `=', or else the in next ARGV-element.
- When `getopt' finds a long-named option, it returns 0 if that option's
- `flag' field is nonzero, the value of the option's `val' field
- if the `flag' field is zero.
- The elements of ARGV aren't really const, because we GNUNET_CRYPTO_random_permute them.
- But we pretend they're const in the prototype to be compatible
- with other systems.
- LONGOPTS is a vector of `struct GNoption' terminated by an
- element containing a name which is zero.
- LONGIND returns the index in LONGOPT of the long-named option found.
- It is only valid when a long-named option has been found by the most
- recent call.
- If LONG_ONLY is nonzero, '-' as well as '--' can introduce
- long-named options. */
- static int
- GN_getopt_internal (int argc,
- char *const *argv,
- const char *optstring,
- const struct GNoption *longopts,
- int *longind,
- int long_only)
- {
- static int __getopt_initialized = 0;
- static int GNopterr = 1;
- GNoptarg = NULL;
- if ((GNoptind == 0) || ! __getopt_initialized)
- {
- if (GNoptind == 0)
- GNoptind = 1; /* Don't scan ARGV[0], the program name. */
- optstring = _getopt_initialize (argc, argv, optstring);
- __getopt_initialized = 1;
- }
- /* Test whether ARGV[GNoptind] points to a non-option argument.
- * Either it does not have option syntax, or there is an environment flag
- * from the shell indicating it is not an option. The later information
- * is only used when the used in the GNU libc. */
- #define NONOPTION_P (argv[GNoptind][0] != '-' || argv[GNoptind][1] == '\0')
- if ((nextchar == NULL) || (*nextchar == '\0'))
- {
- /* Advance to the next ARGV-element. */
- /* Give FIRST_NONOPT & LAST_NONOPT rational values if GNoptind has been
- * moved back by the user (who may also have changed the arguments). */
- if (last_nonopt > GNoptind)
- last_nonopt = GNoptind;
- if (first_nonopt > GNoptind)
- first_nonopt = GNoptind;
- if (ordering == PERMUTE)
- {
- /* If we have just processed some options following some non-options,
- * exchange them so that the options come first. */
- if ((first_nonopt != last_nonopt) && (last_nonopt != GNoptind) )
- exchange ((char **) argv);
- else if (last_nonopt != GNoptind)
- first_nonopt = GNoptind;
- /* Skip any additional non-options
- * and extend the range of non-options previously skipped. */
- while (GNoptind < argc && NONOPTION_P)
- GNoptind++;
- last_nonopt = GNoptind;
- }
- /* The special ARGV-element `--' means premature end of options.
- * Skip it like a null option,
- * then exchange with previous non-options as if it were an option,
- * then skip everything else like a non-option. */
- if ((GNoptind != argc) && ! strcmp (argv[GNoptind], "--"))
- {
- GNoptind++;
- if ((first_nonopt != last_nonopt) && (last_nonopt != GNoptind) )
- exchange ((char **) argv);
- else if (first_nonopt == last_nonopt)
- first_nonopt = GNoptind;
- last_nonopt = argc;
- GNoptind = argc;
- }
- /* If we have done all the ARGV-elements, stop the scan
- * and back over any non-options that we skipped and permuted. */
- if (GNoptind == argc)
- {
- /* Set the next-arg-index to point at the non-options
- * that we previously skipped, so the caller will digest them. */
- if (first_nonopt != last_nonopt)
- GNoptind = first_nonopt;
- return -1;
- }
- /* If we have come to a non-option and did not permute it,
- * either stop the scan or describe it to the caller and pass it by. */
- if (NONOPTION_P)
- {
- if (ordering == REQUIRE_ORDER)
- return -1;
- GNoptarg = argv[GNoptind++];
- return 1;
- }
- /* We have found another option-ARGV-element.
- * Skip the initial punctuation. */
- nextchar =
- (argv[GNoptind] + 1 + (longopts != NULL && argv[GNoptind][1] == '-'));
- }
- /* Decode the current option-ARGV-element. */
- /* Check whether the ARGV-element is a long option.
- *
- * If long_only and the ARGV-element has the form "-f", where f is
- * a valid short option, don't consider it an abbreviated form of
- * a long option that starts with f. Otherwise there would be no
- * way to give the -f short option.
- *
- * On the other hand, if there's a long option "fubar" and
- * the ARGV-element is "-fu", do consider that an abbreviation of
- * the long option, just like "--fu", and not "-f" with arg "u".
- *
- * This distinction seems to be the most useful approach. */if ((longopts != NULL) &&
- ((argv[GNoptind][1] == '-') ||
- (long_only &&
- (argv[GNoptind][2] || ! my_index (optstring, argv[GNoptind][1])))))
- {
- char *nameend;
- const struct GNoption *p;
- const struct GNoption *pfound = NULL;
- int exact = 0;
- int ambig = 0;
- int indfound = -1;
- int option_index;
- for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
- /* Do nothing. */;
- /* Test all long options for either exact match
- * or abbreviated matches. */
- for (p = longopts, option_index = 0; p->name; p++, option_index++)
- if (! strncmp (p->name, nextchar, nameend - nextchar))
- {
- if ((unsigned int) (nameend - nextchar) ==
- (unsigned int) strlen (p->name))
- {
- /* Exact match found. */
- pfound = p;
- indfound = option_index;
- exact = 1;
- break;
- }
- else if (pfound == NULL)
- {
- /* First nonexact match found. */
- pfound = p;
- indfound = option_index;
- }
- else
- /* Second or later nonexact match found. */
- ambig = 1;
- }
- if (ambig && ! exact)
- {
- if (GNopterr)
- fprintf (stderr,
- _ ("%s: option `%s' is ambiguous\n"),
- argv[0],
- argv[GNoptind]);
- nextchar += strlen (nextchar);
- GNoptind++;
- return '?';
- }
- if (pfound != NULL)
- {
- option_index = indfound;
- GNoptind++;
- if (*nameend)
- {
- /* Don't test has_arg with >, because some C compilers don't
- * allow it to be used on enums. */
- if (pfound->has_arg)
- GNoptarg = nameend + 1;
- else
- {
- if (GNopterr)
- {
- if (argv[GNoptind - 1][1] == '-')
- /* --option */
- fprintf (stderr,
- _ ("%s: option `--%s' does not allow an argument\n"),
- argv[0],
- pfound->name);
- else
- /* +option or -option */
- fprintf (stderr,
- _ ("%s: option `%c%s' does not allow an argument\n"),
- argv[0],
- argv[GNoptind - 1][0],
- pfound->name);
- }
- nextchar += strlen (nextchar);
- return '?';
- }
- }
- else if (pfound->has_arg == 1)
- {
- if (GNoptind < argc)
- {
- GNoptarg = argv[GNoptind++];
- }
- else
- {
- if (GNopterr)
- {
- fprintf (stderr,
- _ ("%s: option `%s' requires an argument\n"),
- argv[0],
- argv[GNoptind - 1]);
- }
- nextchar += strlen (nextchar);
- return (optstring[0] == ':') ? ':' : '?';
- }
- }
- nextchar += strlen (nextchar);
- if (longind != NULL)
- *longind = option_index;
- if (pfound->flag)
- {
- *(pfound->flag) = pfound->val;
- return 0;
- }
- return pfound->val;
- }
- /* Can't find it as a long option. If this is not getopt_long_only,
- * or the option starts with '--' or is not a valid short
- * option, then it's an error.
- * Otherwise interpret it as a short option. */
- if (! long_only || (argv[GNoptind][1] == '-') ||
- (my_index (optstring, *nextchar) == NULL) )
- {
- if (GNopterr)
- {
- if (argv[GNoptind][1] == '-')
- /* --option */
- fprintf (stderr,
- _ ("%s: unrecognized option `--%s'\n"),
- argv[0],
- nextchar);
- else
- /* +option or -option */
- fprintf (stderr,
- _ ("%s: unrecognized option `%c%s'\n"),
- argv[0],
- argv[GNoptind][0],
- nextchar);
- }
- nextchar = (char *) "";
- GNoptind++;
- return '?';
- }
- }
- /* Look at and handle the next short option-character. */
- {
- char c = *nextchar++;
- char *temp = my_index (optstring, c);
- /* Increment `GNoptind' when we start to process its last character. */
- if (*nextchar == '\0')
- ++GNoptind;
- if ((temp == NULL) || (c == ':'))
- {
- if (GNopterr)
- {
- if (posixly_correct)
- /* 1003.2 specifies the format of this message. */
- fprintf (stderr, _ ("%s: illegal option -- %c\n"), argv[0], c);
- else
- fprintf (stderr, _ ("%s: invalid option -- %c\n"), argv[0], c);
- }
- return '?';
- }
- /* Convenience. Treat POSIX -W foo same as long option --foo */
- if ((temp[0] == 'W') && (temp[1] == ';'))
- {
- char *nameend;
- const struct GNoption *p;
- const struct GNoption *pfound = NULL;
- int exact = 0;
- int ambig = 0;
- int indfound = 0;
- int option_index;
- /* This is an option that requires an argument. */
- if (*nextchar != '\0')
- {
- GNoptarg = nextchar;
- /* If we end this ARGV-element by taking the rest as an arg,
- * we must advance to the next element now. */
- GNoptind++;
- }
- else if (GNoptind == argc)
- {
- if (GNopterr)
- {
- /* 1003.2 specifies the format of this message. */
- fprintf (stderr,
- _ ("%s: option requires an argument -- %c\n"),
- argv[0],
- c);
- }
- if (optstring[0] == ':')
- c = ':';
- else
- c = '?';
- return c;
- }
- else
- /* We already incremented `GNoptind' once;
- * increment it again when taking next ARGV-elt as argument. */
- GNoptarg = argv[GNoptind++];
- /* GNoptarg is now the argument, see if it's in the
- * table of longopts. */
- for (nextchar = nameend = GNoptarg; *nameend && *nameend != '=';
- nameend++)
- /* Do nothing. */;
- /* Test all long options for either exact match
- * or abbreviated matches. */
- if (longopts != NULL)
- for (p = longopts, option_index = 0; p->name; p++, option_index++)
- if (! strncmp (p->name, nextchar, nameend - nextchar))
- {
- if ((unsigned int) (nameend - nextchar) == strlen (p->name))
- {
- /* Exact match found. */
- pfound = p;
- indfound = option_index;
- exact = 1;
- break;
- }
- else if (pfound == NULL)
- {
- /* First nonexact match found. */
- pfound = p;
- indfound = option_index;
- }
- else
- /* Second or later nonexact match found. */
- ambig = 1;
- }
- if (ambig && ! exact)
- {
- if (GNopterr)
- fprintf (stderr,
- _ ("%s: option `-W %s' is ambiguous\n"),
- argv[0],
- argv[GNoptind]);
- nextchar += strlen (nextchar);
- GNoptind++;
- return '?';
- }
- if (pfound != NULL)
- {
- option_index = indfound;
- if (*nameend)
- {
- /* Don't test has_arg with >, because some C compilers don't
- * allow it to be used on enums. */
- if (pfound->has_arg)
- GNoptarg = nameend + 1;
- else
- {
- if (GNopterr)
- fprintf (stderr,
- _ ("%s: option `-W %s' does not allow an argument\n"),
- argv[0],
- pfound->name);
- nextchar += strlen (nextchar);
- return '?';
- }
- }
- else if (pfound->has_arg == 1)
- {
- if (GNoptind < argc)
- GNoptarg = argv[GNoptind++];
- else
- {
- if (GNopterr)
- fprintf (stderr,
- _ ("%s: option `%s' requires an argument\n"),
- argv[0],
- argv[GNoptind - 1]);
- nextchar += strlen (nextchar);
- return optstring[0] == ':' ? ':' : '?';
- }
- }
- nextchar += strlen (nextchar);
- if (longind != NULL)
- *longind = option_index;
- if (pfound->flag)
- {
- *(pfound->flag) = pfound->val;
- return 0;
- }
- return pfound->val;
- }
- nextchar = NULL;
- return 'W'; /* Let the application handle it. */
- }
- if (temp[1] == ':')
- {
- if (temp[2] == ':')
- {
- /* This is an option that accepts an argument optionally. */
- if (*nextchar != '\0')
- {
- GNoptarg = nextchar;
- GNoptind++;
- }
- else
- GNoptarg = NULL;
- nextchar = NULL;
- }
- else
- {
- /* This is an option that requires an argument. */
- if (*nextchar != '\0')
- {
- GNoptarg = nextchar;
- /* If we end this ARGV-element by taking the rest as an arg,
- * we must advance to the next element now. */
- GNoptind++;
- }
- else if (GNoptind == argc)
- {
- if (GNopterr)
- {
- /* 1003.2 specifies the format of this message. */
- fprintf (stderr,
- _ ("%s: option requires an argument -- %c\n"),
- argv[0],
- c);
- }
- if (optstring[0] == ':')
- c = ':';
- else
- c = '?';
- }
- else
- /* We already incremented `GNoptind' once;
- * increment it again when taking next ARGV-elt as argument. */
- GNoptarg = argv[GNoptind++];
- nextchar = NULL;
- }
- }
- return c;
- }
- }
- static int
- GNgetopt_long (int argc,
- char *const *argv,
- const char *options,
- const struct GNoption *long_options,
- int *opt_index)
- {
- return GN_getopt_internal (argc, argv, options, long_options, opt_index, 0);
- }
- /* ******************** now the GNUnet specific modifications... ********************* */
- /**
- * Parse the command line.
- *
- * @param binaryOptions Name of application with option summary
- * @param allOptions defined options and handlers
- * @param argc number of arguments
- * @param argv actual arguments
- * @return index into argv with first non-option
- * argument, or #GNUNET_SYSERR on error
- */
- int
- GNUNET_GETOPT_run (const char *binaryOptions,
- const struct GNUNET_GETOPT_CommandLineOption *allOptions,
- unsigned int argc,
- char *const *argv)
- {
- struct GNoption *long_options;
- struct GNUNET_GETOPT_CommandLineProcessorContext clpc;
- int count;
- char *shorts;
- int spos;
- int cont;
- uint8_t *seen;
- unsigned int optmatch = 0;
- const char *have_exclusive = NULL;
- GNUNET_assert (argc > 0);
- GNoptind = 0;
- clpc.binaryName = argv[0];
- clpc.binaryOptions = binaryOptions;
- clpc.allOptions = allOptions;
- clpc.argv = argv;
- clpc.argc = argc;
- for (count = 0; NULL != allOptions[count].name; count++)
- ;
- /* transform our option representation into the format
- used by the GNU getopt copylib */
- long_options = GNUNET_new_array (count + 1, struct GNoption);
- seen = GNUNET_new_array (count, uint8_t);
- shorts = GNUNET_malloc (count * 2 + 1);
- spos = 0;
- for (unsigned i = 0; i < count; i++)
- {
- long_options[i].name = allOptions[i].name;
- long_options[i].has_arg = allOptions[i].require_argument;
- long_options[i].flag = NULL;
- long_options[i].val = allOptions[i].shortName;
- shorts[spos++] = allOptions[i].shortName;
- if (allOptions[i].require_argument != 0)
- shorts[spos++] = ':';
- }
- long_options[count].name = NULL;
- long_options[count].has_arg = 0;
- long_options[count].flag = NULL;
- long_options[count].val = '\0';
- shorts[spos] = '\0';
- cont = GNUNET_OK;
- /* main getopt loop */
- while (1)
- {
- int option_index = 0;
- unsigned int i;
- int c;
- c = GNgetopt_long (argc, argv, shorts, long_options, &option_index);
- if (c == GNUNET_SYSERR)
- break; /* No more flags to process */
- /* Check which of our program's options was given by the user */
- for (i = 0; i < count; i++)
- {
- clpc.currentArgument = GNoptind - 1;
- if ((char) c == allOptions[i].shortName)
- {
- optmatch++;
- if (allOptions[i].option_exclusive)
- have_exclusive = allOptions[i].name;
- if (GNUNET_OK == cont)
- {
- /* parse the option using the option-specific processor */
- cont = allOptions[i].processor (&clpc,
- allOptions[i].scls,
- allOptions[i].name,
- GNoptarg);
- }
- seen[i] = 1;
- break;
- }
- }
- if (i == count)
- {
- fprintf (stderr, _ ("Use %s to get a list of options.\n"), "--help");
- cont = GNUNET_SYSERR;
- }
- }
- GNUNET_free (shorts);
- GNUNET_free (long_options);
- /* check that if any option that was marked as exclusive
- is the only option that was provided */
- if ((NULL != have_exclusive) && (optmatch > 1))
- {
- fprintf (stderr,
- _ ("Option `%s' can't be used with other options.\n"),
- have_exclusive);
- cont = GNUNET_SYSERR;
- }
- if (GNUNET_YES == cont)
- {
- /* check that all mandatory options are present */
- for (count = 0; NULL != allOptions[count].name; count++)
- {
- if ((0 == seen[count]) && (allOptions[count].option_mandatory))
- {
- fprintf (stderr,
- _ ("Missing mandatory option `%s'.\n"),
- allOptions[count].name);
- cont = GNUNET_SYSERR;
- }
- }
- }
- GNUNET_free (seen);
- /* call cleaners, if available */
- for (unsigned int i = 0; NULL != allOptions[i].name; i++)
- if (NULL != allOptions[i].cleaner)
- allOptions[i].cleaner (allOptions[i].scls);
- if (GNUNET_OK != cont)
- return cont;
- return GNoptind;
- }
- /* end of getopt.c */
|