123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- /* getopt.c - Parse command-line options
- *
- * Copyright 2019 The Android Open Source Project
- USE_GETOPT(NEWTOY(getopt, "^a(alternative)n:(name)o:(options)l*(long)(longoptions)Tu", TOYFLAG_USR|TOYFLAG_BIN))
- config GETOPT
- bool "getopt"
- default n
- 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<toys.optc) argv[j++] = toys.optargs[i++];
- // BSD getopts don't honor argv[0] (for -n), so handle errors ourselves.
- opterr = 0;
- optind = 1;
- while ((ch = (FLAG(a)?getopt_long_only:getopt_long)(argc, argv, TT.o,
- lopts, &i)) != -1) {
- if (ch == '?') {
- fprintf(stderr, "%s: invalid option '%c'\n", argv[0], optopt);
- toys.exitval = 1;
- } else if (!ch) {
- printf(" --%s", lopts[i].name);
- if (lopts[i].has_arg) out(optarg ? optarg : "");
- } else {
- printf(" -%c", ch);
- if (optarg) out(optarg);
- }
- }
- printf(" --");
- for (; optind<argc; optind++) out(argv[optind]);
- printf("\n");
- }
|