1*cf5a6c84SAndroid Build Coastguard Worker /* getopt.c - Parse command-line options
2*cf5a6c84SAndroid Build Coastguard Worker *
3*cf5a6c84SAndroid Build Coastguard Worker * Copyright 2019 The Android Open Source Project
4*cf5a6c84SAndroid Build Coastguard Worker *
5*cf5a6c84SAndroid Build Coastguard Worker * See https://man7.org/linux/man-pages/man1/getopt.1.html
6*cf5a6c84SAndroid Build Coastguard Worker
7*cf5a6c84SAndroid Build Coastguard Worker USE_GETOPT(NEWTOY(getopt, "^a(alternative)n:(name)o:(options)l*(long)(longoptions)Tu", TOYFLAG_USR|TOYFLAG_BIN))
8*cf5a6c84SAndroid Build Coastguard Worker
9*cf5a6c84SAndroid Build Coastguard Worker config GETOPT
10*cf5a6c84SAndroid Build Coastguard Worker bool "getopt"
11*cf5a6c84SAndroid Build Coastguard Worker default y
12*cf5a6c84SAndroid Build Coastguard Worker help
13*cf5a6c84SAndroid Build Coastguard Worker usage: getopt [-aTu] [-lo OPTIONS] [-n NAME] [OPTIONS] ARG...
14*cf5a6c84SAndroid Build Coastguard Worker
15*cf5a6c84SAndroid Build Coastguard Worker Outputs command line with recognized OPTIONS character arguments moved to
16*cf5a6c84SAndroid Build Coastguard Worker front, then "--", then non-option arguments. Returns 1 if unknown options.
17*cf5a6c84SAndroid Build Coastguard Worker OPTIONS followed by : take an argument, or :: for optional arguments (which
18*cf5a6c84SAndroid Build Coastguard Worker must be attached, ala -xblah or --long=blah).
19*cf5a6c84SAndroid Build Coastguard Worker
20*cf5a6c84SAndroid Build Coastguard Worker -a Allow long options starting with a single -
21*cf5a6c84SAndroid Build Coastguard Worker -l Long OPTIONS (repeated or comma separated)
22*cf5a6c84SAndroid Build Coastguard Worker -n Command NAME for error messages
23*cf5a6c84SAndroid Build Coastguard Worker -o Short OPTIONS (instead of using first argument)
24*cf5a6c84SAndroid Build Coastguard Worker -T Test whether this is a modern getopt
25*cf5a6c84SAndroid Build Coastguard Worker -u Unquoted output (default if no other options set)
26*cf5a6c84SAndroid Build Coastguard Worker
27*cf5a6c84SAndroid Build Coastguard Worker Example:
28*cf5a6c84SAndroid Build Coastguard Worker $ getopt -l long:,arg:: abc command --long -b there --arg
29*cf5a6c84SAndroid Build Coastguard Worker --long '-b' --arg '' -- 'command' 'there'
30*cf5a6c84SAndroid Build Coastguard Worker */
31*cf5a6c84SAndroid Build Coastguard Worker
32*cf5a6c84SAndroid Build Coastguard Worker #define FOR_getopt
33*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
34*cf5a6c84SAndroid Build Coastguard Worker #include <getopt.h> // Everything else uses lib/args.c
35*cf5a6c84SAndroid Build Coastguard Worker
36*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
37*cf5a6c84SAndroid Build Coastguard Worker struct arg_list *l;
38*cf5a6c84SAndroid Build Coastguard Worker char *o, *n;
39*cf5a6c84SAndroid Build Coastguard Worker )
40*cf5a6c84SAndroid Build Coastguard Worker
out(char * s)41*cf5a6c84SAndroid Build Coastguard Worker static void out(char *s)
42*cf5a6c84SAndroid Build Coastguard Worker {
43*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(u)) xprintf(" %s", s);
44*cf5a6c84SAndroid Build Coastguard Worker else {
45*cf5a6c84SAndroid Build Coastguard Worker xputsn(" '");
46*cf5a6c84SAndroid Build Coastguard Worker for (; *s; s++) {
47*cf5a6c84SAndroid Build Coastguard Worker if (*s == '\'') xputsn("'\\''");
48*cf5a6c84SAndroid Build Coastguard Worker else putchar(*s);
49*cf5a6c84SAndroid Build Coastguard Worker }
50*cf5a6c84SAndroid Build Coastguard Worker putchar('\'');
51*cf5a6c84SAndroid Build Coastguard Worker }
52*cf5a6c84SAndroid Build Coastguard Worker }
53*cf5a6c84SAndroid Build Coastguard Worker
parse_long_opt(void * data,char * str,int len)54*cf5a6c84SAndroid Build Coastguard Worker static char *parse_long_opt(void *data, char *str, int len)
55*cf5a6c84SAndroid Build Coastguard Worker {
56*cf5a6c84SAndroid Build Coastguard Worker struct option **lopt_ptr = data, *lopt = *lopt_ptr;
57*cf5a6c84SAndroid Build Coastguard Worker
58*cf5a6c84SAndroid Build Coastguard Worker // Trailing : or :: means this option takes a required or optional argument.
59*cf5a6c84SAndroid Build Coastguard Worker // no_argument = 0, required_argument = 1, optional_argument = 2.
60*cf5a6c84SAndroid Build Coastguard Worker for (lopt->has_arg = 0; len>0 && str[len-1] == ':'; lopt->has_arg++) len--;
61*cf5a6c84SAndroid Build Coastguard Worker if (!len || lopt->has_arg>2) return str;
62*cf5a6c84SAndroid Build Coastguard Worker
63*cf5a6c84SAndroid Build Coastguard Worker lopt->name = xstrndup(str, len);
64*cf5a6c84SAndroid Build Coastguard Worker (*lopt_ptr)++;
65*cf5a6c84SAndroid Build Coastguard Worker
66*cf5a6c84SAndroid Build Coastguard Worker return 0;
67*cf5a6c84SAndroid Build Coastguard Worker }
68*cf5a6c84SAndroid Build Coastguard Worker
getopt_main(void)69*cf5a6c84SAndroid Build Coastguard Worker void getopt_main(void)
70*cf5a6c84SAndroid Build Coastguard Worker {
71*cf5a6c84SAndroid Build Coastguard Worker int argc = toys.optc+1, i = 0, j = 0, ch;
72*cf5a6c84SAndroid Build Coastguard Worker char **argv = xzalloc(sizeof(char *)*(argc+1));
73*cf5a6c84SAndroid Build Coastguard Worker struct option *lopts = xzalloc(sizeof(struct option)*argc), *lopt = lopts;
74*cf5a6c84SAndroid Build Coastguard Worker
75*cf5a6c84SAndroid Build Coastguard Worker if (FLAG(T)) {
76*cf5a6c84SAndroid Build Coastguard Worker toys.exitval = 4;
77*cf5a6c84SAndroid Build Coastguard Worker return;
78*cf5a6c84SAndroid Build Coastguard Worker }
79*cf5a6c84SAndroid Build Coastguard Worker
80*cf5a6c84SAndroid Build Coastguard Worker comma_args(TT.l, &lopt, "bad -l", parse_long_opt);
81*cf5a6c84SAndroid Build Coastguard Worker argv[j++] = TT.n ? : "getopt";
82*cf5a6c84SAndroid Build Coastguard Worker
83*cf5a6c84SAndroid Build Coastguard Worker if (!FLAG(o)) {
84*cf5a6c84SAndroid Build Coastguard Worker TT.o = toys.optargs[i++];
85*cf5a6c84SAndroid Build Coastguard Worker argc--;
86*cf5a6c84SAndroid Build Coastguard Worker }
87*cf5a6c84SAndroid Build Coastguard Worker if (!TT.o) error_exit("no OPTSTR");
88*cf5a6c84SAndroid Build Coastguard Worker if (!toys.optflags) toys.optflags = FLAG_u;
89*cf5a6c84SAndroid Build Coastguard Worker
90*cf5a6c84SAndroid Build Coastguard Worker while (i<toys.optc) argv[j++] = toys.optargs[i++];
91*cf5a6c84SAndroid Build Coastguard Worker
92*cf5a6c84SAndroid Build Coastguard Worker // BSD getopt doesn't honor argv[0] (for -n), so handle errors ourselves.
93*cf5a6c84SAndroid Build Coastguard Worker opterr = 0;
94*cf5a6c84SAndroid Build Coastguard Worker optind = 1;
95*cf5a6c84SAndroid Build Coastguard Worker while ((ch = (FLAG(a) ? getopt_long_only : getopt_long)(argc, argv, TT.o,
96*cf5a6c84SAndroid Build Coastguard Worker lopts, &i)) != -1) {
97*cf5a6c84SAndroid Build Coastguard Worker if (ch == '?') {
98*cf5a6c84SAndroid Build Coastguard Worker fprintf(stderr, "%s: invalid option '%c'\n", *argv, optopt);
99*cf5a6c84SAndroid Build Coastguard Worker toys.exitval = 1;
100*cf5a6c84SAndroid Build Coastguard Worker } else if (!ch) {
101*cf5a6c84SAndroid Build Coastguard Worker xprintf(" --%s", lopts[i].name);
102*cf5a6c84SAndroid Build Coastguard Worker if (lopts[i].has_arg) out(optarg ? : "");
103*cf5a6c84SAndroid Build Coastguard Worker } else {
104*cf5a6c84SAndroid Build Coastguard Worker xprintf(" -%c", ch);
105*cf5a6c84SAndroid Build Coastguard Worker if (optarg) out(optarg);
106*cf5a6c84SAndroid Build Coastguard Worker }
107*cf5a6c84SAndroid Build Coastguard Worker }
108*cf5a6c84SAndroid Build Coastguard Worker
109*cf5a6c84SAndroid Build Coastguard Worker xputsn(" --");
110*cf5a6c84SAndroid Build Coastguard Worker for (; optind<argc; optind++) out(argv[optind]);
111*cf5a6c84SAndroid Build Coastguard Worker putchar('\n');
112*cf5a6c84SAndroid Build Coastguard Worker }
113