xref: /aosp_15_r20/external/toybox/toys/other/getopt.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
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