From c77b66455762f42bb824c1aa8cc60e7f4d44bdab Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 21 Nov 2019 14:09:23 -0800 Subject: Add getopt(1). Includes new tests. --- toys/pending/getopt.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 toys/pending/getopt.c (limited to 'toys') diff --git a/toys/pending/getopt.c b/toys/pending/getopt.c new file mode 100644 index 00000000..7780cb6e --- /dev/null +++ b/toys/pending/getopt.c @@ -0,0 +1,104 @@ +/* getopt.c - Parse command-line options + * + * Copyright 2019 The Android Open Source Project + +USE_GETOPT(NEWTOY(getopt, "^(alternative)a(name)n:(options)o:(long)(longoptions)l*Tu", TOYFLAG_USR|TOYFLAG_BIN)) + +config GETOPT + bool "getopt" + default y + help + usage: getopt [OPTIONS] [--] ARG... + + Parse command-line options for use in shell scripts. + + -a Allow long options starting with a single -. + -l OPTS Specify long options. + -n NAME Command name for error messages. + -o OPTS Specify short options. + -T Test whether this is a modern getopt. + -u Output options unquoted. +*/ + +#define FOR_getopt +#include "toys.h" + +GLOBALS( + struct arg_list *l; + char *o, *n; +) + +static void out(char *s) +{ + if (FLAG(u)) printf(" %s", s); + else { + printf(" '"); + for (; *s; s++) { + if (*s == '\'') printf("'\\''"); + else putchar(*s); + } + printf("'"); + } +} + +static char *parse_long_opt(void *data, char *str, int len) +{ + struct option **lopt_ptr = data, *lopt = *lopt_ptr; + + // Trailing : or :: means this option takes a required or optional argument. + // no_argument = 0, required_argument = 1, optional_argument = 2. + for (lopt->has_arg = 0; len>0 && str[len-1] == ':'; lopt->has_arg++) len--; + if (!len || lopt->has_arg>2) return str; + + lopt->name = xstrndup(str, len); + + (*lopt_ptr)++; + return 0; +} + +void getopt_main(void) +{ + int argc = toys.optc+1; + char **argv = xzalloc(sizeof(char *)*(argc+1)); + struct option *lopts = xzalloc(sizeof(struct option)*argc), *lopt = lopts; + int i = 0, j = 0, ch; + + if (FLAG(T)) { + toys.exitval = 4; + return; + } + + comma_args(TT.l, &lopt, "bad -l", parse_long_opt); + argv[j++] = TT.n ? TT.n : "getopt"; + + // Legacy mode: don't quote output and take the first argument as OPTSTR. + if (!FLAG(o)) { + toys.optflags |= FLAG_u; + TT.o = toys.optargs[i++]; + if (!TT.o) error_exit("no OPTSTR"); + --argc; + } + + while (i