From: git Date: Mon, 20 Apr 2026 16:30:56 +0000 (-0400) Subject: getopt_long: add program name to warnx X-Git-Url: https://git.datadissipation.net/?a=commitdiff_plain;h=cd126c30bbe33208cfa4d9922a97ac14e3139270;p=single-header-libcext.git getopt_long: add program name to warnx formatting overhaul --- diff --git a/asprintf.h b/asprintf.h index fc66ba5..ddce911 100644 --- a/asprintf.h +++ b/asprintf.h @@ -27,48 +27,37 @@ /* https://git.datadissipation.net */ #ifndef ASPRINTF_H_ - #define ASPRINTF_H_ 1 + #define ASPRINTF_H_ 1 -#ifdef ASPRINTF_INCLUDE_LIBC + #ifdef ASPRINTF_INCLUDE_LIBC #include #include #include -#endif /* ASPRINTF_INCLUDE_LIBC */ + #endif /* ASPRINTF_INCLUDE_LIBC */ -#ifndef HAVE_ASPRINTF - #define HAVE_ASPRINTF 1 - #define asprintf i_asprintf_ - #define vasprintf i_vasprintf_ - int i_vasprintf_(char **strp, const char *fmt, va_list ap); - int i_asprintf_(char **strp, const char *fmt, ...); -#endif /* !HAVE_ASPRINTF */ + #ifndef HAVE_ASPRINTF + #define HAVE_ASPRINTF 1 + #define asprintf i_asprintf_ + #define vasprintf i_vasprintf_ +int i_vasprintf_(char **strp, const char *fmt, va_list ap); +int i_asprintf_(char **strp, const char *fmt, ...); + #endif /* !HAVE_ASPRINTF */ -#ifdef ASPRINTF_IMPLEMENTATION + #ifdef ASPRINTF_IMPLEMENTATION int i_vasprintf_(char **strp, const char *fmt, va_list ap) { - int size, ret; - va_list tp; + int size; + va_list tp; va_copy(tp, ap); size = vsnprintf(NULL, 0, fmt, tp); va_end(tp); - if (size < 0) { + if (size < 0 || !(*strp = malloc(size + 1))) return -1; - } - *strp = malloc(size + 1); - if (*strp == NULL) { - return -1; - } - - ret = vsnprintf(*strp, size + 1, fmt, ap); - if (ret < 0) { - free(*strp); - return -1; - } - return ret; + return vsnprintf(*strp, size + 1, fmt, ap); } int @@ -83,5 +72,5 @@ i_asprintf_(char **strp, const char *fmt, ...) return ret; } -#endif /* ASPRINTF_IMPLEMENTATION */ + #endif /* ASPRINTF_IMPLEMENTATION */ #endif /* !ASPRINTF_H_ */ diff --git a/getopt_long.h b/getopt_long.h index 41f59de..4778009 100644 --- a/getopt_long.h +++ b/getopt_long.h @@ -78,7 +78,7 @@ /* https://git.datadissipation.net */ #ifndef GETOPT_LONG_H_ - #define GETOPT_LONG_H_ 1 + #define GETOPT_LONG_H_ 1 #ifdef GETOPT_LONG_INCLUDE_LIBC #include @@ -88,37 +88,37 @@ #endif /* GETOPT_LONG_INCLUDE_LIBC */ #ifndef HAVE_GETOPT_LONG - #define HAVE_GETOPT_LONG 1 - - #define no_argument 0 - #define required_argument 1 - #define optional_argument 2 - - /* - * structs are in their own namespace, so this should be OK - * the worst it can do is make compiler messages worse - */ - #define option i_option_ - - #define optarg i_optarg_ - #define suboptarg i_suboptarg_ - #define optind i_optind_ - #define opterr i_opterr_ - #define optopt i_optopt_ - #define optreset i_optreset_ - - #define getopt i_getopt_ - #define getsubopt i_getsubopt_ - #define getopt_long i_getopt_long_ - #define getopt_long_only i_getopt_long_only_ + #define HAVE_GETOPT_LONG 1 + + #define no_argument 0 + #define required_argument 1 + #define optional_argument 2 + +/* + * structs are in their own namespace, so this should be OK + * the worst it can do is make compiler messages worse + */ + #define option i_option_ + + #define optarg i_optarg_ + #define suboptarg i_suboptarg_ + #define optind i_optind_ + #define opterr i_opterr_ + #define optopt i_optopt_ + #define optreset i_optreset_ + + #define getopt i_getopt_ + #define getsubopt i_getsubopt_ + #define getopt_long i_getopt_long_ + #define getopt_long_only i_getopt_long_only_ #ifndef GETOPT_LONG_IMPLEMENTATION - extern char *i_optarg_; - extern char *i_suboptarg_; - extern int i_optind_, i_opterr_, i_optopt_, i_optreset_; +extern char *i_optarg_; +extern char *i_suboptarg_; +extern int i_optind_, i_opterr_, i_optopt_, i_optreset_; #endif /* !GETOPT_LONG_IMPLEMENTATION */ - struct i_option_ { +struct i_option_ { const char *name; /* * one of no_argument, required_argument, and optional_argument: @@ -129,226 +129,221 @@ int *flag; /* if flag not NULL, value to set *flag to; else return value */ int val; - }; +}; - int i_getopt_(int argc, char * const *argv, const char *optstring); - int i_getsubopt_(char **optionp, char * const *tokens, char **valuep); - int i_getopt_long_(int argc, char * const *argv, const char *optstring, - const struct option *longopts, int *longindex); - int i_getopt_long_only_(int argc, char * const *argv, const char *optstring, - const struct option *longopts, int *longindex); +int i_getopt_(int argc, char * const *argv, const char *optstring); +int i_getsubopt_(char **optionp, char * const *tokens, char **valuep); +int i_getopt_long_(int argc, char * const *argv, const char *optstring, + const struct option *longopts, int *longindex); +int i_getopt_long_only_(int argc, char * const *argv, const char *optstring, + const struct option *longopts, int *longindex); #endif /* !HAVE_GETOPT_LONG */ - + #ifdef GETOPT_LONG_IMPLEMENTATION #define I_PRINT_ERROR_ ((i_opterr_) && (*options != ':')) - #define I_FLAG_PERMUTE_ 0x01 /* permute non-options to the end of argv */ - #define I_FLAG_ALLARGS_ 0x02 /* treat non-options as args to option "-1" */ - #define I_FLAG_LONGONLY_ 0x04 /* operate as getopt_long_only */ - - /* return values */ - #define I_BADCH_ (int)'?' - #define I_BADARG_ ((*options == ':') ? (int)':' : (int)'?') - #define I_INORDER_ (int)1 - - #define I_EMSG_ "" - - int i_opterr_ = 1; /* if error message should be printed */ - int i_optind_ = 1; /* index into parent argv vector */ - int i_optopt_ = '?'; /* character checked for validity */ - int i_optreset_; /* reset getopt */ - char *i_optarg_; /* argument associated with option */ - char *i_suboptarg_; /* argument associated with suboption */ - - /* XXX: set optreset to 1 rather than these two */ - static int i_nonopt_start_ = -1; /* first non option argument (for permute) */ - static int i_nonopt_end_ = -1; /* first option after non options (for permute) */ - static char *i_place_ = I_EMSG_; /* option letter processing */ - - /* Error messages */ - static const char i_recargchar_[] = "option requires an argument -- %c"; - static const char i_recargstring_[] = "option requires an argument -- %s"; - static const char i_ambig_[] = "i_ambig_uous option -- %.*s"; - static const char i_noarg_[] = "option doesn't take an argument -- %.*s"; - static const char i_illoptchar_[] = "unknown option -- %c"; - static const char i_illoptstring_[] = "unknown option -- %s"; - - static void i_warnx_(const char *, ...); - static int i_getopt_internal_(int, char * const *, const char *, - const struct option *, int *, int); - static int i_parse_long_options__(char * const *, const char *, - const struct option *, int *, int); - static int i_gcd_(int, int); - static void i_permute_args_(int, int, int, char * const *); - - /* - * Own warnx() for portability - */ - void - i_warnx_(const char *fmt, ...) - { - va_list args; - - /* Linux "program_invocation_short_name" is a GNU extension, so we don't use it */ - #if defined(__APPLE__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - #define I_GET_PROG_NAME_() getprogname() - #else - #define I_GET_PROG_NAME_() "warnx" - #endif - - va_start(args, fmt); - fprintf(stderr, "%s: ", I_GET_PROG_NAME_()); - vfprintf(stderr, fmt, args); - fputc('\n', stderr); - va_end(args); - } - - /* - * Compute the greatest common divisor of a and b. - */ - static int - i_gcd_(int a, int b) - { - int c; - - c = a % b; - while (c != 0) { - a = b; - b = c; - c = a % b; - } - - return (b); - } - - /* - * Exchange the block from nonopt_start to nonopt_end with the block - * from nonopt_end to opt_end (keeping the same order of arguments - * in each block). - */ - static void - i_permute_args_(int panonopt_start, int panonopt_end, int opt_end, - char * const *nargv) - { - int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; - char *swap; - - /* - * compute lengths of blocks and number and size of cycles - */ - nnonopts = panonopt_end - panonopt_start; - nopts = opt_end - panonopt_end; - ncycle = i_gcd_(nnonopts, nopts); - cyclelen = (opt_end - panonopt_start) / ncycle; - - for (i = 0; i < ncycle; i++) { + #define I_FLAG_PERMUTE_ 0x01 /* permute non-options to the end of argv */ + #define I_FLAG_ALLARGS_ 0x02 /* treat non-options as args to option "-1" */ + #define I_FLAG_LONGONLY_ 0x04 /* operate as getopt_long_only */ + +/* return values */ + #define I_BADCH_ (int) '?' + #define I_BADARG_ ((*options == ':') ? (int) ':' : (int) '?') + #define I_INORDER_ (int) 1 + + #define I_EMSG_ "" + +int i_opterr_ = 1; /* if error message should be printed */ +int i_optind_ = 1; /* index into parent argv vector */ +int i_optopt_ = '?'; /* character checked for validity */ +int i_optreset_; /* reset getopt */ +char *i_optarg_; /* argument associated with option */ +char *i_suboptarg_; /* argument associated with suboption */ + +/* XXX: set optreset to 1 rather than these two */ +static int i_nonopt_start_ = -1; /* first non option argument (for permute) */ +static int i_nonopt_end_ = -1; /* first option after non options (for permute) */ +static char *i_place_ = I_EMSG_; /* option letter processing */ +static char *i_progname_; /* program name == argv[0] */ + +/* Error messages */ +static const char i_recargchar_[] = "option requires an argument -- %c"; +static const char i_recargstring_[] = "option requires an argument -- %s"; +static const char i_ambig_[] = "i_ambig_uous option -- %.*s"; +static const char i_noarg_[] = "option doesn't take an argument -- %.*s"; +static const char i_illoptchar_[] = "unknown option -- %c"; +static const char i_illoptstring_[] = "unknown option -- %s"; + +static void i_warnx_(const char *, ...); +static int i_getopt_internal_(int, char * const *, const char *, + const struct option *, int *, int); +static int i_parse_long_options__(char * const *, const char *, + const struct option *, int *, int); +static int i_gcd_(int, int); +static void i_permute_args_(int, int, int, char * const *); + +/* + * Own warnx() for portability + */ +void +i_warnx_(const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + fprintf(stderr, "%s: ", i_progname_); + vfprintf(stderr, fmt, args); + fputc('\n', stderr); + va_end(args); +} + +/* + * Compute the greatest common divisor of a and b. + */ +static int +i_gcd_(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +i_permute_args_(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = i_gcd_(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { cstart = panonopt_end+i; pos = cstart; for (j = 0; j < cyclelen; j++) { - if (pos >= panonopt_end) - pos -= nnonopts; - else - pos += nopts; - swap = nargv[pos]; - /* LINTED const cast */ - ((char **) nargv)[pos] = nargv[cstart]; - /* LINTED const cast */ - ((char **)nargv)[cstart] = swap; - } - } - } - - /* - * i_parse_long_options__ -- - * Parse long options in argc/argv argument vector. - * Returns -1 if short_too is set and the option does not match long_options. - */ - static int - i_parse_long_options__(char * const *nargv, const char *options, - const struct option *long_options, int *idx, int short_too) - { - char *current_argv, *has_equal; - size_t current_argv_len; - int i, match; - - current_argv = i_place_; - match = -1; - - i_optind_++; - - if ((has_equal = strchr(current_argv, '=')) != NULL) { - /* argument found (--option=arg) */ - current_argv_len = has_equal - current_argv; - has_equal++; - } else { - current_argv_len = strlen(current_argv); - } - for (i = 0; long_options[i].name; i++) { - /* find matching long option */ - if (strncmp(current_argv, long_options[i].name, - current_argv_len)) - continue; - - if (strlen(long_options[i].name) == current_argv_len) { - /* exact match */ - match = i; - break; - } - /* - * If this is a known short option, don't allow - * a partial match of a single character. - */ - if (short_too && current_argv_len == 1) - continue; - - if (match == -1) { /* partial match */ - match = i; - } else { - /* ambiguous abbreviation */ - if (I_PRINT_ERROR_) - i_warnx_(i_ambig_, (int)current_argv_len, - current_argv); - i_optopt_ = 0; - return (I_BADCH_); - } - } - if (match != -1) { /* option found */ - if (long_options[match].has_arg == no_argument - && has_equal) { - if (I_PRINT_ERROR_) - i_warnx_(i_noarg_, (int)current_argv_len, - current_argv); - /* - * XXX: GNU sets optopt to val regardless of flag - */ - if (long_options[match].flag == NULL) - i_optopt_ = long_options[match].val; - else - i_optopt_ = 0; - return (I_BADARG_); - } - if (long_options[match].has_arg == required_argument || - long_options[match].has_arg == optional_argument) { - if (has_equal) - i_optarg_ = has_equal; - else if (long_options[match].has_arg == - required_argument) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **) nargv)[cstart] = swap; + } + } +} + +/* + * i_parse_long_options__ -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int +i_parse_long_options__(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int + short_too) +{ + char *current_argv, *has_equal; + size_t current_argv_len; + int i, match; + + current_argv = i_place_; + match = -1; + + i_optind_++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else { + current_argv_len = strlen(current_argv); + } + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) { /* partial match */ + match = i; + } else { + /* ambiguous abbreviation */ + if (I_PRINT_ERROR_) + i_warnx_(i_ambig_, (int) current_argv_len, + current_argv); + i_optopt_ = 0; + return (I_BADCH_); + } + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (I_PRINT_ERROR_) + i_warnx_(i_noarg_, (int) current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + i_optopt_ = long_options[match].val; + else + i_optopt_ = 0; + return (I_BADARG_); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal){ + i_optarg_ = has_equal; + } else if (long_options[match].has_arg == + required_argument) { /* * optional argument doesn't use next nargv */ - i_optarg_ = nargv[i_optind_++]; - } - } - if ((long_options[match].has_arg == required_argument) - && (i_optarg_ == NULL)) { + i_optarg_ = nargv[i_optind_++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (i_optarg_ == NULL)) { /* * Missing argument; leading ':' indicates no error * should be generated. */ if (I_PRINT_ERROR_) i_warnx_(i_recargstring_, - current_argv); + current_argv); /* * XXX: GNU sets optopt to val regardless of flag */ @@ -358,308 +353,314 @@ i_optopt_ = 0; --i_optind_; return (I_BADARG_); - } - } else { /* unknown option */ - if (short_too) { - --i_optind_; - return (-1); - } - if (I_PRINT_ERROR_) - i_warnx_(i_illoptstring_, current_argv); - i_optopt_ = 0; - return (I_BADCH_); - } - if (idx) - *idx = match; - if (long_options[match].flag) { - *long_options[match].flag = long_options[match].val; - return (0); - } else - return (long_options[match].val); - } - - /* - * i_getopt_internal_ -- - * Parse argc/argv argument vector. Called by user level routines. - */ - static int - i_getopt_internal_(int nargc, char *const *nargv, const char *options, - const struct option *long_options, int *idx, int flags) - { - char *oli; /* option letter list index */ - int optchar, short_too; - static int posix_me_harder = -1; - - if (options == NULL) - return (-1); - - /* - * XXX Some GNU programs (like cvs) set optind to 0 instead of - * XXX using optreset. Work around this braindamage. - */ - if (i_optind_ == 0) - i_optind_ = i_optreset_ = 1; - - /* - * Disable GNU extensions if POSIXLY_CORRECT is set or options - * string begins with a '+'. - */ - if (posix_me_harder == -1 || i_optreset_) - posix_me_harder = (getenv("POSIXLY_CORRECT") != NULL); - if (*options == '-') - flags |= I_FLAG_ALLARGS_; - else if (posix_me_harder || *options == '+') - flags &= ~I_FLAG_PERMUTE_; - if (*options == '+' || *options == '-') - options++; - - i_optarg_ = NULL; - if (i_optreset_) - i_nonopt_start_ = i_nonopt_end_ = -1; - start: - if (i_optreset_ || !*i_place_) { /* update scanning pointer */ - i_optreset_ = 0; - if (i_optind_ >= nargc) { /* end of argument vector */ - i_place_ = I_EMSG_; - if (i_nonopt_end_ != -1) { - /* do permutation, if we have to */ - i_permute_args_(i_nonopt_start_, i_nonopt_end_, - i_optind_, nargv); - i_optind_ -= i_nonopt_end_ - i_nonopt_start_; - } else if (i_nonopt_start_ != -1) { - /* - * If we skipped non-options, set optind - * to the first of them. - */ - i_optind_ = i_nonopt_start_; - } - i_nonopt_start_ = i_nonopt_end_ = -1; - return (-1); - } - if (*(i_place_ = nargv[i_optind_]) != '-' || - (i_place_[1] == '\0' && strchr(options, '-') == NULL)) { - i_place_ = I_EMSG_; /* found non-option */ - if (flags & I_FLAG_ALLARGS_) { - /* - * GNU extension: - * return non-option as argument to option 1 - */ - i_optarg_ = nargv[i_optind_++]; - return (I_INORDER_); - } - if (!(flags & I_FLAG_PERMUTE_)) { + } + } else { /* unknown option */ + if (short_too) { + --i_optind_; + return (-1); + } + if (I_PRINT_ERROR_) + i_warnx_(i_illoptstring_, current_argv); + i_optopt_ = 0; + return (I_BADCH_); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else { + return (long_options[match].val); + } +} + +/* + * i_getopt_internal_ -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +i_getopt_internal_(int nargc, char *const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) +{ + char *oli; /* option letter list index */ + int optchar, short_too; + static int posix_me_harder = -1; + + i_progname_ = nargv[0]; + + if (options == NULL) + return (-1); + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (i_optind_ == 0) + i_optind_ = i_optreset_ = 1; + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + */ + if (posix_me_harder == -1 || i_optreset_) + posix_me_harder = (getenv("POSIXLY_CORRECT") != NULL); + if (*options == '-') + flags |= I_FLAG_ALLARGS_; + else if (posix_me_harder || *options == '+') + flags &= ~I_FLAG_PERMUTE_; + if (*options == '+' || *options == '-') + options++; + + i_optarg_ = NULL; + if (i_optreset_) + i_nonopt_start_ = i_nonopt_end_ = -1; +start: + if (i_optreset_ || !*i_place_) { /* update scanning pointer */ + i_optreset_ = 0; + if (i_optind_ >= nargc) { /* end of argument vector */ + i_place_ = I_EMSG_; + if (i_nonopt_end_ != -1) { + /* do permutation, if we have to */ + i_permute_args_(i_nonopt_start_, i_nonopt_end_, + i_optind_, nargv); + i_optind_ -= i_nonopt_end_ - i_nonopt_start_; + } else if (i_nonopt_start_ != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + i_optind_ = i_nonopt_start_; + } + i_nonopt_start_ = i_nonopt_end_ = -1; + return (-1); + } + if (*(i_place_ = nargv[i_optind_]) != '-' || + (i_place_[1] == '\0' && strchr(options, '-') == NULL)) { + i_place_ = I_EMSG_; /* found non-option */ + if (flags & I_FLAG_ALLARGS_) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + i_optarg_ = nargv[i_optind_++]; + return (I_INORDER_); + } + if (!(flags & I_FLAG_PERMUTE_)) { /* * If no permutation wanted, stop parsing * at first non-option. */ return (-1); - } - /* do permutation */ - if (i_nonopt_start_ == -1) { - i_nonopt_start_ = i_optind_; - } else if (i_nonopt_end_ != -1) { - i_permute_args_(i_nonopt_start_, i_nonopt_end_, - i_optind_, nargv); - i_nonopt_start_ = i_optind_ - - (i_nonopt_end_ - i_nonopt_start_); - i_nonopt_end_ = -1; - } - i_optind_++; - /* process next argument */ - goto start; - } - if (i_nonopt_start_ != -1 && i_nonopt_end_ == -1) - i_nonopt_end_ = i_optind_; - - /* - * If we have "-" do nothing, if "--" we are done. - */ - if (i_place_[1] != '\0' && *++i_place_ == '-' && i_place_[1] == '\0') { - i_optind_++; - i_place_ = I_EMSG_; - /* - * We found an option (--), so if we skipped - * non-options, we have to permute. - */ - if (i_nonopt_end_ != -1) { - i_permute_args_(i_nonopt_start_, i_nonopt_end_, - i_optind_, nargv); - i_optind_ -= i_nonopt_end_ - i_nonopt_start_; - } - i_nonopt_start_ = i_nonopt_end_ = -1; - return (-1); - } - } - - /* - * Check long options if: - * 1) we were passed some - * 2) the arg is not just "-" - * 3) either the arg starts with -- we are i_getopt_long_only() - */ - if (long_options != NULL && i_place_ != nargv[i_optind_] && - (*i_place_ == '-' || (flags & I_FLAG_LONGONLY_))) { - short_too = 0; - if (*i_place_ == '-') - i_place_++; /* --foo long option */ - else if (*i_place_ != ':' - && strchr(options, *i_place_) != NULL) - short_too = 1; /* could be short option too */ - - optchar = i_parse_long_options__(nargv, options, long_options, - idx, short_too); - if (optchar != -1) { - i_place_ = I_EMSG_; - return (optchar); - } - } - - if ((optchar = (int)*i_place_++) == (int)':' || - (optchar == (int)'-' && *i_place_ != '\0') || + } + /* do permutation */ + if (i_nonopt_start_ == -1) { + i_nonopt_start_ = i_optind_; + } else if (i_nonopt_end_ != -1) { + i_permute_args_(i_nonopt_start_, i_nonopt_end_, + i_optind_, nargv); + i_nonopt_start_ = i_optind_ - + (i_nonopt_end_ - + i_nonopt_start_); + i_nonopt_end_ = -1; + } + i_optind_++; + /* process next argument */ + goto start; + } + if (i_nonopt_start_ != -1 && i_nonopt_end_ == -1) + i_nonopt_end_ = i_optind_; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (i_place_[1] != '\0' && *++i_place_ == '-' && i_place_[1] == + '\0') { + i_optind_++; + i_place_ = I_EMSG_; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (i_nonopt_end_ != -1) { + i_permute_args_(i_nonopt_start_, i_nonopt_end_, + i_optind_, nargv); + i_optind_ -= i_nonopt_end_ - i_nonopt_start_; + } + i_nonopt_start_ = i_nonopt_end_ = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are i_getopt_long_only() + */ + if (long_options != NULL && i_place_ != nargv[i_optind_] && + (*i_place_ == '-' || (flags & I_FLAG_LONGONLY_))) { + short_too = 0; + if (*i_place_ == '-') + i_place_++; /* --foo long option */ + else if (*i_place_ != ':' + && strchr(options, *i_place_) != NULL) + short_too = 1; /* could be short option too */ + + optchar = i_parse_long_options__(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + i_place_ = I_EMSG_; + return (optchar); + } + } + + if ((optchar = (int) *i_place_++) == (int) ':' || + (optchar == (int) '-' && *i_place_ != '\0') || (oli = strchr(options, optchar)) == NULL) { - /* - * If the user specified "-" and '-' isn't listed in - * options, return -1 (non-option) as per POSIX. - * Otherwise, it is an unknown option character (or ':'). - */ - if (optchar == (int)'-' && *i_place_ == '\0') - return (-1); - if (!*i_place_) - ++i_optind_; - if (I_PRINT_ERROR_) - i_warnx_(i_illoptchar_, optchar); - i_optopt_ = optchar; - return (I_BADCH_); - } - if (long_options != NULL && optchar == 'W' && oli[1] == ';') { - /* -W long-option */ - if (*i_place_) { /* no space */ - /* NOTHING */; - } else if (++i_optind_ >= nargc) { /* no arg */ - i_place_ = I_EMSG_; - if (I_PRINT_ERROR_) - i_warnx_(i_recargchar_, optchar); - i_optopt_ = optchar; - return (I_BADARG_); - } else { /* white space */ - i_place_ = nargv[i_optind_]; - } - optchar = i_parse_long_options__(nargv, options, long_options, - idx, 0); - i_place_ = I_EMSG_; - return (optchar); - } - if (*++oli != ':') { /* doesn't take argument */ - if (!*i_place_) - ++i_optind_; - } else { /* takes (optional) argument */ - i_optarg_ = NULL; - if (*i_place_) /* no white space */ - i_optarg_ = i_place_; - else if (oli[1] != ':') { /* arg not optional */ - if (++i_optind_ >= nargc) { /* no arg */ - i_place_ = I_EMSG_; - if (I_PRINT_ERROR_) - i_warnx_(i_recargchar_, optchar); - i_optopt_ = optchar; - return (I_BADARG_); - } else { - i_optarg_ = nargv[i_optind_]; - } - } - i_place_ = I_EMSG_; - ++i_optind_; - } - /* dump back option letter */ - return (optchar); - } - - int - i_getsubopt_(char **optionp, char * const *tokens, char **valuep) - { - int cnt; - char *p; - - i_suboptarg_ = *valuep = NULL; - - if (!optionp || !*optionp) - return(-1); - - /* skip leading white-space, commas */ - for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); - - if (!*p) { - *optionp = p; - return(-1); - } - - /* save the start of the token, and skip the rest of the token. */ - for (i_suboptarg_ = p; - *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';); - - if (*p) { - /* - * If there's an equals sign, set the value pointer, and - * skip over the value part of the token. Terminate the - * token. - */ - if (*p == '=') { - *p = '\0'; - for (*valuep = ++p; - *p && *p != ',' && *p != ' ' && *p != '\t'; ++p); - if (*p) - *p++ = '\0'; - } else { - *p++ = '\0'; - } - /* Skip any whitespace or commas after this token. */ - for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p); - } - - /* set optionp for next round. */ - *optionp = p; - - for (cnt = 0; *tokens; ++tokens, ++cnt) - if (!strcmp(i_suboptarg_, *tokens)) - return(cnt); - return(-1); - } - - int - i_getopt_(int argc, char * const *argv, const char *optstring) - { - #ifdef GETOPT_PERMUTE_ARGS - return (i_getopt_internal_(argc, argv, optstring, NULL, NULL, - I_FLAG_PERMUTE_)); - #else - return (i_getopt_internal_(argc, argv, optstring, NULL, NULL, 0)); - #endif - } - - int - i_getopt_long_(int argc, char * const *argv, const char *optstring, - const struct option *longopts, int *longindex) - { - #ifdef GETOPT_LONG_PERMUTE_ARGS - return (i_getopt_internal_(argc, argv, optstring, longopts, longindex, - I_FLAG_PERMUTE_)); - #else - return (i_getopt_internal_(argc, argv, optstring, longopts, longindex, 0)); - #endif - - } - - int - i_getopt_long_only_(int argc, char * const *argv, const char *optstring, - const struct option *longopts, int *longindex) - { - #ifdef GETOPT_LONG_ONLY_PERMUTE_ARGS - return (i_getopt_internal_(argc, argv, optstring, longopts, longindex, - I_FLAG_PERMUTE_ | I_FLAG_LONGONLY_)); - #else - return (i_getopt_internal_(argc, argv, optstring, longopts, longindex, - I_FLAG_LONGONLY_)); - #endif - } + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int) '-' && *i_place_ == '\0') + return (-1); + if (!*i_place_) + ++i_optind_; + if (I_PRINT_ERROR_) + i_warnx_(i_illoptchar_, optchar); + i_optopt_ = optchar; + return (I_BADCH_); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*i_place_) { /* no space */ + /* NOTHING */ + ; + } else if (++i_optind_ >= nargc) { /* no arg */ + i_place_ = I_EMSG_; + if (I_PRINT_ERROR_) + i_warnx_(i_recargchar_, optchar); + i_optopt_ = optchar; + return (I_BADARG_); + } else { /* white space */ + i_place_ = nargv[i_optind_]; + } + optchar = i_parse_long_options__(nargv, options, long_options, + idx, 0); + i_place_ = I_EMSG_; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*i_place_) + ++i_optind_; + } else { /* takes (optional) argument */ + i_optarg_ = NULL; + if (*i_place_){ /* no white space */ + i_optarg_ = i_place_; + } else if (oli[1] != ':'){ /* arg not optional */ + if (++i_optind_ >= nargc) { /* no arg */ + i_place_ = I_EMSG_; + if (I_PRINT_ERROR_) + i_warnx_(i_recargchar_, optchar); + i_optopt_ = optchar; + return (I_BADARG_); + } else { + i_optarg_ = nargv[i_optind_]; + } + } + i_place_ = I_EMSG_; + ++i_optind_; + } + /* dump back option letter */ + return (optchar); +} + +int +i_getsubopt_(char **optionp, char * const *tokens, char **valuep) +{ + int cnt; + char *p; + + i_suboptarg_ = *valuep = NULL; + + if (!optionp || !*optionp) + return (-1); + + /* skip leading white-space, commas */ + for (p = *optionp; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p) ; + + if (!*p) { + *optionp = p; + return (-1); + } + + /* save the start of the token, and skip the rest of the token. */ + for (i_suboptarg_ = p; + *++p && *p != ',' && *p != '=' && *p != ' ' && *p != '\t';) ; + + if (*p) { + /* + * If there's an equals sign, set the value pointer, and + * skip over the value part of the token. Terminate the + * token. + */ + if (*p == '=') { + *p = '\0'; + for (*valuep = ++p; + *p && *p != ',' && *p != ' ' && *p != '\t'; ++p) ; + if (*p) + *p++ = '\0'; + } else { + *p++ = '\0'; + } + /* Skip any whitespace or commas after this token. */ + for (; *p && (*p == ',' || *p == ' ' || *p == '\t'); ++p) ; + } + + /* set optionp for next round. */ + *optionp = p; + + for (cnt = 0; *tokens; ++tokens, ++cnt) + if (!strcmp(i_suboptarg_, *tokens)) + return (cnt); + return (-1); +} + +int +i_getopt_(int argc, char * const *argv, const char *optstring) +{ +#ifdef GETOPT_PERMUTE_ARGS + return (i_getopt_internal_(argc, argv, optstring, NULL, NULL, + I_FLAG_PERMUTE_)); +#else + return (i_getopt_internal_(argc, argv, optstring, NULL, NULL, 0)); +#endif +} + +int +i_getopt_long_(int argc, char * const *argv, const char *optstring, + const struct option *longopts, int *longindex) +{ +#ifdef GETOPT_LONG_PERMUTE_ARGS + return (i_getopt_internal_(argc, argv, optstring, longopts, longindex, + I_FLAG_PERMUTE_)); +#else + return (i_getopt_internal_(argc, argv, optstring, longopts, longindex, 0 + )); +#endif +} + +int +i_getopt_long_only_(int argc, char * const *argv, const char *optstring, + const struct option *longopts, int *longindex) +{ +#ifdef GETOPT_LONG_ONLY_PERMUTE_ARGS + return (i_getopt_internal_(argc, argv, optstring, longopts, longindex, + I_FLAG_PERMUTE_ | I_FLAG_LONGONLY_)); +#else + return (i_getopt_internal_(argc, argv, optstring, longopts, longindex, + I_FLAG_LONGONLY_)); +#endif +} #endif /* GETOPT_LONG_IMPLEMENTATION */ #endif /* !GETOPT_LONG_H_ */