diff options
author | H. Peter Anvin <hpa@zytor.com> | 2010-07-02 17:57:17 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-07-02 17:57:17 -0700 |
commit | 9c6db1a0f333ba89961bbf92e155e9fc597f6d7b (patch) | |
tree | 3a7482091cef8c4146de2e0f01e5145de6d77ed2 | |
parent | dc07c5b57f44c8680d46b1615c69d5827b38d200 (diff) | |
download | syslinux-9c6db1a0f333ba89961bbf92e155e9fc597f6d7b.tar.gz |
com32: add getopt_long() to the library
Add getopt_long() to the library. This is code lifted straight out of
klibc.
Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r-- | com32/include/getopt.h | 22 | ||||
-rw-r--r-- | com32/lib/Makefile | 3 | ||||
-rw-r--r-- | com32/lib/getopt_long.c | 152 |
3 files changed, 176 insertions, 1 deletions
diff --git a/com32/include/getopt.h b/com32/include/getopt.h new file mode 100644 index 00000000..71c41cd9 --- /dev/null +++ b/com32/include/getopt.h @@ -0,0 +1,22 @@ +#ifndef _GETOPT_H +#define _GETOPT_H + +#include <klibc/extern.h> + +struct option { + const char *name; + int has_arg; + int *flag; + int val; +}; + +enum { + no_argument = 0, + required_argument = 1, + optional_argument = 2, +}; + +__extern int getopt_long(int, char *const *, const char *, + const struct option *, int *); + +#endif /* _GETOPT_H */ diff --git a/com32/lib/Makefile b/com32/lib/Makefile index 93643ce2..e8e89c08 100644 --- a/com32/lib/Makefile +++ b/com32/lib/Makefile @@ -11,7 +11,8 @@ LIBOBJS = \ abort.o atexit.o atoi.o atol.o atoll.o calloc.o creat.o \ ctypes.o errno.o fgetc.o fgets.o fopen.o fprintf.o fputc.o \ fclose.o putchar.o setjmp.o \ - fputs.o fread2.o fread.o free.o fwrite2.o fwrite.o getopt.o \ + fputs.o fread2.o fread.o free.o fwrite2.o fwrite.o \ + getopt.o getopt_long.o \ lrand48.o malloc.o stack.o memccpy.o memchr.o memcmp.o \ memcpy.o mempcpy.o memmem.o memmove.o memset.o memswap.o \ exit.o onexit.o \ diff --git a/com32/lib/getopt_long.c b/com32/lib/getopt_long.c new file mode 100644 index 00000000..e3d064b0 --- /dev/null +++ b/com32/lib/getopt_long.c @@ -0,0 +1,152 @@ +/* + * getopt.c + * + * getopt_long(), or at least a common subset thereof: + * + * - Option reordering is not supported + * - -W foo is not supported + * - First optstring character "-" not supported. + */ + +#include <stdint.h> +#include <unistd.h> +#include <string.h> +#include <getopt.h> + +char *optarg; +int optind, opterr, optopt; +static struct getopt_private_state { + const char *optptr; + const char *last_optstring; + char *const *last_argv; +} pvt; + +static inline const char *option_matches(const char *arg_str, + const char *opt_name) +{ + while (*arg_str != '\0' && *arg_str != '=') { + if (*arg_str++ != *opt_name++) + return NULL; + } + + if (*opt_name) + return NULL; + + return arg_str; +} + +int getopt_long(int argc, char *const *argv, const char *optstring, + const struct option *longopts, int *longindex) +{ + const char *carg; + const char *osptr; + int opt; + + /* getopt() relies on a number of different global state + variables, which can make this really confusing if there is + more than one use of getopt() in the same program. This + attempts to detect that situation by detecting if the + "optstring" or "argv" argument have changed since last time + we were called; if so, reinitialize the query state. */ + + if (optstring != pvt.last_optstring || argv != pvt.last_argv || + optind < 1 || optind > argc) { + /* optind doesn't match the current query */ + pvt.last_optstring = optstring; + pvt.last_argv = argv; + optind = 1; + pvt.optptr = NULL; + } + + carg = argv[optind]; + + /* First, eliminate all non-option cases */ + + if (!carg || carg[0] != '-' || !carg[1]) + return -1; + + if (carg[1] == '-') { + const struct option *lo; + const char *opt_end = NULL; + + optind++; + + /* Either it's a long option, or it's -- */ + if (!carg[2]) { + /* It's -- */ + return -1; + } + + for (lo = longopts; lo->name; lo++) { + if ((opt_end = option_matches(carg+2, lo->name))) + break; + } + if (!opt_end) + return '?'; + + if (longindex) + *longindex = lo-longopts; + + if (*opt_end == '=') { + if (lo->has_arg) + optarg = (char *)opt_end+1; + else + return '?'; + } else if (lo->has_arg == 1) { + if (!(optarg = argv[optind])) + return '?'; + optind++; + } + + if (lo->flag) { + *lo->flag = lo->val; + return 0; + } else { + return lo->val; + } + } + + if ((uintptr_t) (pvt.optptr - carg) > (uintptr_t) strlen(carg)) { + /* Someone frobbed optind, change to new opt. */ + pvt.optptr = carg + 1; + } + + opt = *pvt.optptr++; + + if (opt != ':' && (osptr = strchr(optstring, opt))) { + if (osptr[1] == ':') { + if (*pvt.optptr) { + /* Argument-taking option with attached + argument */ + optarg = (char *)pvt.optptr; + optind++; + } else { + /* Argument-taking option with non-attached + argument */ + if (argv[optind + 1]) { + optarg = (char *)argv[optind+1]; + optind += 2; + } else { + /* Missing argument */ + optind++; + return (optstring[0] == ':') + ? ':' : '?'; + } + } + return opt; + } else { + /* Non-argument-taking option */ + /* pvt.optptr will remember the exact position to + resume at */ + if (!*pvt.optptr) + optind++; + return opt; + } + } else { + /* Unknown option */ + optopt = opt; + if (!*pvt.optptr) + optind++; + return '?'; + } +} |