1/* getopt.c - Parse command-line options 2 * 3 * Copyright 2019 The Android Open Source Project 4 5USE_GETOPT(NEWTOY(getopt, "^a(alternative)n:(name)o:(options)l*(long)(longoptions)Tu", TOYFLAG_USR|TOYFLAG_BIN)) 6 7config GETOPT 8 bool "getopt" 9 default n 10 help 11 usage: getopt [OPTIONS] [--] ARG... 12 13 Parse command-line options for use in shell scripts. 14 15 -a Allow long options starting with a single -. 16 -l OPTS Specify long options. 17 -n NAME Command name for error messages. 18 -o OPTS Specify short options. 19 -T Test whether this is a modern getopt. 20 -u Output options unquoted. 21*/ 22 23#define FOR_getopt 24#include "toys.h" 25 26GLOBALS( 27 struct arg_list *l; 28 char *o, *n; 29) 30 31static void out(char *s) 32{ 33 if (FLAG(u)) printf(" %s", s); 34 else { 35 printf(" '"); 36 for (; *s; s++) { 37 if (*s == '\'') printf("'\\''"); 38 else putchar(*s); 39 } 40 printf("'"); 41 } 42} 43 44static char *parse_long_opt(void *data, char *str, int len) 45{ 46 struct option **lopt_ptr = data, *lopt = *lopt_ptr; 47 48 // Trailing : or :: means this option takes a required or optional argument. 49 // no_argument = 0, required_argument = 1, optional_argument = 2. 50 for (lopt->has_arg = 0; len>0 && str[len-1] == ':'; lopt->has_arg++) len--; 51 if (!len || lopt->has_arg>2) return str; 52 53 lopt->name = xstrndup(str, len); 54 55 (*lopt_ptr)++; 56 return 0; 57} 58 59void getopt_main(void) 60{ 61 int argc = toys.optc+1; 62 char **argv = xzalloc(sizeof(char *)*(argc+1)); 63 struct option *lopts = xzalloc(sizeof(struct option)*argc), *lopt = lopts; 64 int i = 0, j = 0, ch; 65 66 if (FLAG(T)) { 67 toys.exitval = 4; 68 return; 69 } 70 71 comma_args(TT.l, &lopt, "bad -l", parse_long_opt); 72 argv[j++] = TT.n ? TT.n : "getopt"; 73 74 // Legacy mode: don't quote output and take the first argument as OPTSTR. 75 if (!FLAG(o)) { 76 toys.optflags |= FLAG_u; 77 TT.o = toys.optargs[i++]; 78 if (!TT.o) error_exit("no OPTSTR"); 79 --argc; 80 } 81 82 while (i<toys.optc) argv[j++] = toys.optargs[i++]; 83 84 // BSD getopts don't honor argv[0] (for -n), so handle errors ourselves. 85 opterr = 0; 86 optind = 1; 87 while ((ch = (FLAG(a)?getopt_long_only:getopt_long)(argc, argv, TT.o, 88 lopts, &i)) != -1) { 89 if (ch == '?') { 90 fprintf(stderr, "%s: invalid option '%c'\n", argv[0], optopt); 91 toys.exitval = 1; 92 } else if (!ch) { 93 printf(" --%s", lopts[i].name); 94 if (lopts[i].has_arg) out(optarg ? optarg : ""); 95 } else { 96 printf(" -%c", ch); 97 if (optarg) out(optarg); 98 } 99 } 100 101 printf(" --"); 102 for (; optind<argc; optind++) out(argv[optind]); 103 printf("\n"); 104} 105