|
Packit Service |
0e769b |
/*
|
|
Packit Service |
0e769b |
* getopt.c
|
|
Packit Service |
0e769b |
*
|
|
Packit Service |
0e769b |
* getopt_long(), or at least a common subset thereof:
|
|
Packit Service |
0e769b |
*
|
|
Packit Service |
0e769b |
* - Option reordering is not supported
|
|
Packit Service |
0e769b |
* - -W foo is not supported
|
|
Packit Service |
0e769b |
* - First optstring character "-" not supported.
|
|
Packit Service |
0e769b |
*
|
|
Packit Service |
0e769b |
* This file was imported from the klibc library from hpa
|
|
Packit Service |
0e769b |
*/
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
#include <stdint.h>
|
|
Packit Service |
0e769b |
#include <unistd.h>
|
|
Packit Service |
0e769b |
#include <string.h>
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
#include "getopt.h"
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
char *optarg = NULL;
|
|
Packit Service |
0e769b |
int optind = 0, opterr = 0, optopt = 0;
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
static struct getopt_private_state {
|
|
Packit Service |
0e769b |
const char *optptr;
|
|
Packit Service |
0e769b |
const char *last_optstring;
|
|
Packit Service |
0e769b |
char *const *last_argv;
|
|
Packit Service |
0e769b |
} pvt;
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
static inline const char *option_matches(const char *arg_str,
|
|
Packit Service |
0e769b |
const char *opt_name, int smatch)
|
|
Packit Service |
0e769b |
{
|
|
Packit Service |
0e769b |
while (*arg_str != '\0' && *arg_str != '=') {
|
|
Packit Service |
0e769b |
if (*arg_str++ != *opt_name++)
|
|
Packit Service |
0e769b |
return NULL;
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
if (*opt_name && !smatch)
|
|
Packit Service |
0e769b |
return NULL;
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
return arg_str;
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
int getopt_long_only(int argc, char *const *argv, const char *optstring,
|
|
Packit Service |
0e769b |
const struct option *longopts, int *longindex)
|
|
Packit Service |
0e769b |
{
|
|
Packit Service |
0e769b |
const char *carg;
|
|
Packit Service |
0e769b |
const char *osptr;
|
|
Packit Service |
0e769b |
int opt;
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
optarg = NULL;
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
/* getopt() relies on a number of different global state
|
|
Packit Service |
0e769b |
variables, which can make this really confusing if there is
|
|
Packit Service |
0e769b |
more than one use of getopt() in the same program. This
|
|
Packit Service |
0e769b |
attempts to detect that situation by detecting if the
|
|
Packit Service |
0e769b |
"optstring" or "argv" argument have changed since last time
|
|
Packit Service |
0e769b |
we were called; if so, reinitialize the query state. */
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
if (optstring != pvt.last_optstring || argv != pvt.last_argv ||
|
|
Packit Service |
0e769b |
optind < 1 || optind > argc) {
|
|
Packit Service |
0e769b |
/* optind doesn't match the current query */
|
|
Packit Service |
0e769b |
pvt.last_optstring = optstring;
|
|
Packit Service |
0e769b |
pvt.last_argv = argv;
|
|
Packit Service |
0e769b |
optind = 1;
|
|
Packit Service |
0e769b |
pvt.optptr = NULL;
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
carg = argv[optind];
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
/* First, eliminate all non-option cases */
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
if (!carg || carg[0] != '-' || !carg[1])
|
|
Packit Service |
0e769b |
return -1;
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
if (carg[1] == '-') {
|
|
Packit Service |
0e769b |
const struct option *lo;
|
|
Packit Service |
0e769b |
const char *opt_end = NULL;
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
optind++;
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
/* Either it's a long option, or it's -- */
|
|
Packit Service |
0e769b |
if (!carg[2]) {
|
|
Packit Service |
0e769b |
/* It's -- */
|
|
Packit Service |
0e769b |
return -1;
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
for (lo = longopts; lo->name; lo++) {
|
|
Packit Service |
0e769b |
opt_end = option_matches(carg+2, lo->name, 0);
|
|
Packit Service |
0e769b |
if (opt_end)
|
|
Packit Service |
0e769b |
break;
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
/*
|
|
Packit Service |
0e769b |
* The GNU getopt_long_only() apparently allows a short match,
|
|
Packit Service |
0e769b |
* if it's unique and if we don't have a full match. Let's
|
|
Packit Service |
0e769b |
* do the same here, search and see if there is one (and only
|
|
Packit Service |
0e769b |
* one) short match.
|
|
Packit Service |
0e769b |
*/
|
|
Packit Service |
0e769b |
if (!opt_end) {
|
|
Packit Service |
0e769b |
const struct option *lo_match = NULL;
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
for (lo = longopts; lo->name; lo++) {
|
|
Packit Service |
0e769b |
const char *ret;
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
ret = option_matches(carg+2, lo->name, 1);
|
|
Packit Service |
0e769b |
if (!ret)
|
|
Packit Service |
0e769b |
continue;
|
|
Packit Service |
0e769b |
if (!opt_end) {
|
|
Packit Service |
0e769b |
opt_end = ret;
|
|
Packit Service |
0e769b |
lo_match = lo;
|
|
Packit Service |
0e769b |
} else {
|
|
Packit Service |
0e769b |
opt_end = NULL;
|
|
Packit Service |
0e769b |
break;
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
if (!opt_end)
|
|
Packit Service |
0e769b |
return '?';
|
|
Packit Service |
0e769b |
lo = lo_match;
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
if (longindex)
|
|
Packit Service |
0e769b |
*longindex = lo-longopts;
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
if (*opt_end == '=') {
|
|
Packit Service |
0e769b |
if (lo->has_arg)
|
|
Packit Service |
0e769b |
optarg = (char *)opt_end+1;
|
|
Packit Service |
0e769b |
else
|
|
Packit Service |
0e769b |
return '?';
|
|
Packit Service |
0e769b |
} else if (lo->has_arg == 1) {
|
|
Packit Service |
0e769b |
if (!(optarg = argv[optind]))
|
|
Packit Service |
0e769b |
return '?';
|
|
Packit Service |
0e769b |
optind++;
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
if (lo->flag) {
|
|
Packit Service |
0e769b |
*lo->flag = lo->val;
|
|
Packit Service |
0e769b |
return 0;
|
|
Packit Service |
0e769b |
} else {
|
|
Packit Service |
0e769b |
return lo->val;
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) {
|
|
Packit Service |
0e769b |
/* Someone frobbed optind, change to new opt. */
|
|
Packit Service |
0e769b |
pvt.optptr = carg + 1;
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
opt = *pvt.optptr++;
|
|
Packit Service |
0e769b |
|
|
Packit Service |
0e769b |
if (opt != ':' && (osptr = strchr(optstring, opt))) {
|
|
Packit Service |
0e769b |
if (osptr[1] == ':') {
|
|
Packit Service |
0e769b |
if (*pvt.optptr) {
|
|
Packit Service |
0e769b |
/* Argument-taking option with attached
|
|
Packit Service |
0e769b |
argument */
|
|
Packit Service |
0e769b |
optarg = (char *)pvt.optptr;
|
|
Packit Service |
0e769b |
optind++;
|
|
Packit Service |
0e769b |
} else {
|
|
Packit Service |
0e769b |
/* Argument-taking option with non-attached
|
|
Packit Service |
0e769b |
argument */
|
|
Packit Service |
0e769b |
if (osptr[2] == ':') {
|
|
Packit Service |
0e769b |
if (argv[optind + 1]) {
|
|
Packit Service |
0e769b |
optarg = (char *)argv[optind+1];
|
|
Packit Service |
0e769b |
optind += 2;
|
|
Packit Service |
0e769b |
} else {
|
|
Packit Service |
0e769b |
optarg = NULL;
|
|
Packit Service |
0e769b |
optind++;
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
return opt;
|
|
Packit Service |
0e769b |
} else if (argv[optind + 1]) {
|
|
Packit Service |
0e769b |
optarg = (char *)argv[optind+1];
|
|
Packit Service |
0e769b |
optind += 2;
|
|
Packit Service |
0e769b |
} else {
|
|
Packit Service |
0e769b |
/* Missing argument */
|
|
Packit Service |
0e769b |
optind++;
|
|
Packit Service |
0e769b |
return (optstring[0] == ':')
|
|
Packit Service |
0e769b |
? ':' : '?';
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
return opt;
|
|
Packit Service |
0e769b |
} else {
|
|
Packit Service |
0e769b |
/* Non-argument-taking option */
|
|
Packit Service |
0e769b |
/* pvt.optptr will remember the exact position to
|
|
Packit Service |
0e769b |
resume at */
|
|
Packit Service |
0e769b |
if (!*pvt.optptr)
|
|
Packit Service |
0e769b |
optind++;
|
|
Packit Service |
0e769b |
return opt;
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
} else {
|
|
Packit Service |
0e769b |
/* Unknown option */
|
|
Packit Service |
0e769b |
optopt = opt;
|
|
Packit Service |
0e769b |
if (!*pvt.optptr)
|
|
Packit Service |
0e769b |
optind++;
|
|
Packit Service |
0e769b |
return '?';
|
|
Packit Service |
0e769b |
}
|
|
Packit Service |
0e769b |
}
|