blob: 19c96914ddc80c64b05acf07339051ecafb25b1b [file] [log] [blame]
Manuel Novoa III cad53642003-03-19 09:13:01 +00001/* vi: set sw=4 ts=4: */
2/*
Eric Andersen8876fb22003-06-20 09:01:58 +00003 * universal getopt_ulflags implementation for busybox
Manuel Novoa III cad53642003-03-19 09:13:01 +00004 *
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +00005 * Copyright (C) 2003-2005 Vladimir Oleynik <dzo@simtreas.ru>
Manuel Novoa III cad53642003-03-19 09:13:01 +00006 *
"Robert P. J. Day"5d8843e2006-07-10 11:41:19 +00007 * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
Manuel Novoa III cad53642003-03-19 09:13:01 +00008 */
9
Manuel Novoa III cad53642003-03-19 09:13:01 +000010#include "libbb.h"
Rob Landleyd921b2e2006-08-03 15:41:12 +000011#include <getopt.h>
Manuel Novoa III cad53642003-03-19 09:13:01 +000012
Rob Landleyf76cd962006-05-03 21:23:15 +000013/* Documentation
Mike Frysinger2bf88a82005-04-18 22:42:58 +000014
Mike Frysingere5d0bde2005-05-10 23:48:35 +000015unsigned long
Mike Frysinger2bf88a82005-04-18 22:42:58 +000016bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...)
17
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000018 The command line options must be declared in const char
19 *applet_opts as a string of chars, for example:
Mike Frysinger2bf88a82005-04-18 22:42:58 +000020
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000021 flags = bb_getopt_ulflags(argc, argv, "rnug");
Mike Frysinger2bf88a82005-04-18 22:42:58 +000022
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000023 If one of the given options is found, a flag value is added to
24 the return value (an unsigned long).
Mike Frysinger2bf88a82005-04-18 22:42:58 +000025
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000026 The flag value is determined by the position of the char in
27 applet_opts string. For example, in the above case:
Mike Frysinger2bf88a82005-04-18 22:42:58 +000028
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000029 flags = bb_getopt_ulflags(argc, argv, "rnug");
Mike Frysinger2bf88a82005-04-18 22:42:58 +000030
Rob Landleyf76cd962006-05-03 21:23:15 +000031 "r" will add 1 (bit 0)
32 "n" will add 2 (bit 1)
33 "u will add 4 (bit 2)
34 "g" will add 8 (bit 3)
Mike Frysinger2bf88a82005-04-18 22:42:58 +000035
Rob Landleyf76cd962006-05-03 21:23:15 +000036 and so on. You can also look at the return value as a bit
37 field and each option sets one bit.
Mike Frysinger2bf88a82005-04-18 22:42:58 +000038
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000039 ":" If one of the options requires an argument, then add a ":"
40 after the char in applet_opts and provide a pointer to store
41 the argument. For example:
Mike Frysinger2bf88a82005-04-18 22:42:58 +000042
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000043 char *pointer_to_arg_for_a;
44 char *pointer_to_arg_for_b;
45 char *pointer_to_arg_for_c;
46 char *pointer_to_arg_for_d;
Mike Frysinger2bf88a82005-04-18 22:42:58 +000047
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000048 flags = bb_getopt_ulflags(argc, argv, "a:b:c:d:",
Rob Landleyf76cd962006-05-03 21:23:15 +000049 &pointer_to_arg_for_a, &pointer_to_arg_for_b,
50 &pointer_to_arg_for_c, &pointer_to_arg_for_d);
Mike Frysinger2bf88a82005-04-18 22:42:58 +000051
Rob Landleyf76cd962006-05-03 21:23:15 +000052 The type of the pointer (char* or llist_t*) may be controlled
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +000053 by the "::" special separator that is set in the external string
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000054 bb_opt_complementally (see below for more info).
Mike Frysingere5d0bde2005-05-10 23:48:35 +000055
Mike Frysinger992a58c2006-02-22 22:56:30 +000056 "+" If the first character in the applet_opts string is a plus,
57 then option processing will stop as soon as a non-option is
58 encountered in the argv array. Useful for applets like env
59 which should not process arguments to subprograms:
60 env -i ls -d /
61 Here we want env to process just the '-i', not the '-d'.
62
Rob Landleyf76cd962006-05-03 21:23:15 +000063const struct option *bb_applet_long_options
Mike Frysingere5d0bde2005-05-10 23:48:35 +000064
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000065 This struct allows you to define long options. The syntax for
66 declaring the array is just like that of getopt's longopts.
67 (see getopt(3))
Mike Frysingere5d0bde2005-05-10 23:48:35 +000068
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000069 static const struct option applet_long_options[] = {
Rob Landleyf76cd962006-05-03 21:23:15 +000070 { "verbose", 0, 0, 'v' },
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000071 { 0, 0, 0, 0 }
72 };
73 bb_applet_long_options = applet_long_options;
Mike Frysingere5d0bde2005-05-10 23:48:35 +000074
Rob Landleyf76cd962006-05-03 21:23:15 +000075 The last member of struct option (val) typically is set to
76 matching short option from applet_opts. If there is no matching
77 char in applet_opts, then:
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000078 - return bit have next position after short options
79 - if has_arg is not "no_argument", use ptr for arg also
Rob Landleyf76cd962006-05-03 21:23:15 +000080 - bb_opt_complementally affects it too
Mike Frysingerfb6d22c2005-05-11 00:02:39 +000081
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000082 Note: a good applet will make long options configurable via the
83 config process and not a required feature. The current standard
84 is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS.
Mike Frysingerfb6d22c2005-05-11 00:02:39 +000085
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000086const char *bb_opt_complementally
Mike Frysinger57f4cb22006-02-21 00:50:37 +000087 this should be bb_opt_complementary, but we'll just keep it as
88 bb_opt_complementally due to the Russian origins
Mike Frysingerfb6d22c2005-05-11 00:02:39 +000089
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000090 ":" The colon (":") is used to separate groups of two or more chars
91 and/or groups of chars and special characters (stating some
92 conditions to be checked).
Mike Frysingere5d0bde2005-05-10 23:48:35 +000093
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000094 "abc" If groups of two or more chars are specified, the first char
95 is the main option and the other chars are secondary options.
96 Their flags will be turned on if the main option is found even
97 if they are not specifed on the command line. For example:
Mike Frysinger2bf88a82005-04-18 22:42:58 +000098
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000099 bb_opt_complementally = "abc";
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000100
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000101 flags = bb_getopt_ulflags(argc, argv, "abcd")
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000102
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000103 If getopt() finds "-a" on the command line, then
104 bb_getopt_ulflags's return value will be as if "-a -b -c" were
105 found.
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000106
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000107 "ww" Adjacent double options have a counter associated which indicates
Rob Landleyf76cd962006-05-03 21:23:15 +0000108 the number of occurences of the option.
"Vladimir N. Oleynik"d1b60782005-10-05 12:44:52 +0000109 For example the ps applet needs:
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000110 if w is given once, GNU ps sets the width to 132,
111 if w is given more than once, it is "unlimited"
112
113 int w_counter = 0;
114 bb_opt_complementally = "ww";
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000115 bb_getopt_ulflags(argc, argv, "w", &w_counter);
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000116
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000117 if(w_counter)
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000118 width = (w_counter == 1) ? 132 : INT_MAX;
119 else
120 get_terminal_width(...&width...);
121
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000122 w_counter is a pointer to an integer. It has to be passed to
123 bb_getopt_ulflags() after all other option argument sinks.
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000124 For example: accept multiple -v to indicate the level of verbosity
125 and for each -b optarg, add optarg to my_b. Finally, if b is given,
126 turn off c and vice versa:
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000127
128 llist_t *my_b = NULL;
129 int verbose_level = 0;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000130 bb_opt_complementally = "vv:b::b-c:c-b";
"Vladimir N. Oleynik"4a5ce082005-10-05 13:58:40 +0000131 f = bb_getopt_ulflags(argc, argv, "vb:c", &my_b, &verbose_level);
Rob Landleyf76cd962006-05-03 21:23:15 +0000132 if((f & 2)) // -c after -b unsets -b flag
133 while(my_b) { dosomething_with(my_b->data) ; my_b = my_b->link; }
134 if(my_b) // but llist is stored if -b is specified
"Vladimir N. Oleynik"4a5ce082005-10-05 13:58:40 +0000135 free_llist(my_b);
Rob Landleyf76cd962006-05-03 21:23:15 +0000136 if(verbose_level) bb_printf("verbose level is %d\n", verbose_level);
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000137
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000138Special characters:
139
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000140 "-" A dash between two options causes the second of the two
Rob Landleyf76cd962006-05-03 21:23:15 +0000141 to be unset (and ignored) if it is given on the command line.
142
143 [FIXME: what if they are the same? like "x-x"? Is it ever useful?]
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000144
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000145 For example:
146 The du applet has the options "-s" and "-d depth". If
147 bb_getopt_ulflags finds -s, then -d is unset or if it finds -d
148 then -s is unset. (Note: busybox implements the GNU
149 "--max-depth" option as "-d".) To obtain this behavior, you
150 set bb_opt_complementally = "s-d:d-s". Only one flag value is
151 added to bb_getopt_ulflags's return value depending on the
152 position of the options on the command line. If one of the
153 two options requires an argument pointer (":" in applet_opts
154 as in "d:") optarg is set accordingly.
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000155
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000156 char *smax_print_depth;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000157
"Vladimir N. Oleynik"45a8ed82005-09-06 16:08:33 +0000158 bb_opt_complementally = "s-d:d-s:x-x";
159 opt = bb_getopt_ulflags(argc, argv, "sd:x", &smax_print_depth);
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000160
Rob Landleyf76cd962006-05-03 21:23:15 +0000161 if (opt & 2)
162 max_print_depth = atoi(smax_print_depth);
163 if (opt & 4)
164 printf("Detected odd -x usage\n");
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000165
Rob Landleyf76cd962006-05-03 21:23:15 +0000166 "-" A dash as the first char in a bb_opt_complementally group forces
167 all arguments to be treated as options, even if they have
168 no leading dashes. Next char in this case can't be a digit (0-9),
169 use ':' or end of line. For example:
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000170
"Vladimir N. Oleynik"d1b60782005-10-05 12:44:52 +0000171 bb_opt_complementally = "-:w-x:x-w";
172 bb_getopt_ulflags(argc, argv, "wx");
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000173
"Vladimir N. Oleynik"4a5ce082005-10-05 13:58:40 +0000174 Allows any arguments to be given without a dash (./program w x)
Rob Landleyf76cd962006-05-03 21:23:15 +0000175 as well as with a dash (./program -x).
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000176
Rob Landleyf76cd962006-05-03 21:23:15 +0000177 "-N" A dash as the first char in a bb_opt_complementally group followed
178 by a single digit (0-9) means that at least N non-option
179 arguments must be present on the command line
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000180
Rob Landleyf76cd962006-05-03 21:23:15 +0000181 "V-" An option with dash before colon or end-of-line results in
182 bb_show_usage being called if this option is encountered.
183 This is typically used to implement "print verbose usage message
184 and exit" option.
"Vladimir N. Oleynik"4fc92202006-02-02 14:48:54 +0000185
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000186 "--" A double dash between two options, or between an option and a group
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000187 of options, means that they are mutually exclusive. Unlike
188 the "-" case above, an error will be forced if the options
189 are used together.
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000190
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000191 For example:
192 The cut applet must have only one type of list specified, so
193 -b, -c and -f are mutally exclusive and should raise an error
194 if specified together. In this case you must set
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000195 bb_opt_complementally = "b--cf:c--bf:f--bc". If two of the
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000196 mutually exclusive options are found, bb_getopt_ulflags's
197 return value will have the error flag set (BB_GETOPT_ERROR) so
198 that we can check for it:
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000199
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000200 if (flags & BB_GETOPT_ERROR)
201 bb_show_usage();
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000202
Rob Landleyf76cd962006-05-03 21:23:15 +0000203 "?" A "?" as the first char in a bb_opt_complementally group means:
204 if BB_GETOPT_ERROR is detected, don't return, call bb_show_usage
205 and exit instead. Next char after '?' can't be a digit.
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000206
Rob Landleyf76cd962006-05-03 21:23:15 +0000207 "?N" A "?" as the first char in a bb_opt_complementally group followed
208 by a single digit (0-9) means that at most N arguments must be present
209 on the command line.
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000210
211 "::" A double colon after a char in bb_opt_complementally means that the
Rob Landleyf76cd962006-05-03 21:23:15 +0000212 option can occur multiple times. Each occurrence will be saved as
213 a llist_t element instead of char*.
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000214
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000215 For example:
216 The grep applet can have one or more "-e pattern" arguments.
217 In this case you should use bb_getopt_ulflags() as follows:
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000218
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000219 llist_t *patterns = NULL;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000220
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000221 (this pointer must be initializated to NULL if the list is empty
222 as required by *llist_add_to(llist_t *old_head, char *new_item).)
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000223
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000224 bb_opt_complementally = "e::";
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000225
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000226 bb_getopt_ulflags(argc, argv, "e:", &patterns);
227 $ grep -e user -e root /etc/passwd
228 root:x:0:0:root:/root:/bin/bash
229 user:x:500:500::/home/user:/bin/bash
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000230
Mike Frysingere17c80e2006-02-21 00:37:42 +0000231 "--" A double dash at the beginning of bb_opt_complementally means the
232 argv[1] string should always be treated as options, even if it isn't
233 prefixed with a "-". This is to support the special syntax in applets
234 such as "ar" and "tar":
235 tar xvf foo.tar
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000236
Rob Landleyf76cd962006-05-03 21:23:15 +0000237 "?" An "?" between an option and a group of options means that
238 at least one of them is required to occur if the first option
239 occurs in preceding command line arguments.
240
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000241 For example from "id" applet:
242
243 // Don't allow -n -r -rn -ug -rug -nug -rnug
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000244 bb_opt_complementally = "r?ug:n?ug:?u--g:g--u";
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000245 flags = bb_getopt_ulflags(argc, argv, "rnug");
246
247 This example allowed only:
248 $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng
249
Rob Landleyf76cd962006-05-03 21:23:15 +0000250 "X" A bb_opt_complementally group with just a single letter means
251 that this this option is required. If more than one such group exists,
252 at least one option is required to occur (not all of them).
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000253 For example from "start-stop-daemon" applet:
254
Rob Landleyf76cd962006-05-03 21:23:15 +0000255 // Don't allow -KS -SK, but -S or -K is required
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000256 bb_opt_complementally = "K:S:?K--S:S--K";
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000257 flags = bb_getopt_ulflags(argc, argv, "KS...);
258
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000259
260 "x--x" give error if double or more used -x option
261
Rob Landleyf76cd962006-05-03 21:23:15 +0000262 Don't forget to use ':'. For example "?322-22-23X-x-a" is interpreted as
263 "?3:22:-2:2-2:2-3Xa:2--x": max 3 args; count uses of '-2'; min 2 args;
264 if there is a '-2' option then unset '-3', '-X' and '-a'; if there is
265 a '-2' and after it a '-x' then error out.
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000266
Eric Andersen8876fb22003-06-20 09:01:58 +0000267*/
268
Mike Frysingere17c80e2006-02-21 00:37:42 +0000269/* this should be bb_opt_complementary, but we'll just keep it as
270 bb_opt_complementally due to the Russian origins */
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000271const char *bb_opt_complementally;
Eric Andersen8876fb22003-06-20 09:01:58 +0000272
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000273typedef struct {
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000274 int opt;
275 int list_flg;
Eric Andersen8876fb22003-06-20 09:01:58 +0000276 unsigned long switch_on;
277 unsigned long switch_off;
278 unsigned long incongruously;
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000279 unsigned long requires;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000280 void **optarg; /* char **optarg or llist_t **optarg */
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000281 int *counter;
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000282} t_complementally;
Eric Andersen8876fb22003-06-20 09:01:58 +0000283
284/* You can set bb_applet_long_options for parse called long options */
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000285#if ENABLE_GETOPT_LONG
Eric Andersen8876fb22003-06-20 09:01:58 +0000286static const struct option bb_default_long_options[] = {
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000287/* { "help", 0, NULL, '?' }, */
Eric Andersen8876fb22003-06-20 09:01:58 +0000288 { 0, 0, 0, 0 }
289};
290
291const struct option *bb_applet_long_options = bb_default_long_options;
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000292#endif
Eric Andersen8876fb22003-06-20 09:01:58 +0000293
Eric Andersen8876fb22003-06-20 09:01:58 +0000294unsigned long
295bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000296{
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000297 unsigned long flags = 0;
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000298 unsigned long requires = 0;
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000299 t_complementally complementally[sizeof(flags) * 8 + 1];
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000300 int c;
301 const unsigned char *s;
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000302 t_complementally *on_off;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000303 va_list p;
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000304#if ENABLE_GETOPT_LONG
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000305 const struct option *l_o;
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000306#endif
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000307 unsigned long trigger;
"Vladimir N. Oleynik"f01e1782006-01-09 13:28:31 +0000308#ifdef CONFIG_PS
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000309 char **pargv = NULL;
"Vladimir N. Oleynik"f01e1782006-01-09 13:28:31 +0000310#endif
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000311 int min_arg = 0;
312 int max_arg = -1;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000313
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000314#define SHOW_USAGE_IF_ERROR 1
315#define ALL_ARGV_IS_OPTS 2
316#define FIRST_ARGV_IS_OPT 4
317#define FREE_FIRST_ARGV_IS_OPT 8
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000318 int spec_flgs = 0;
319
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000320 va_start (p, applet_opts);
Eric Andersen8876fb22003-06-20 09:01:58 +0000321
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000322 c = 0;
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000323 on_off = complementally;
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000324 memset(on_off, 0, sizeof(complementally));
325
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000326 /* skip GNU extension */
"Vladimir N. Oleynik"bf968f72005-12-02 10:10:28 +0000327 s = (const unsigned char *)applet_opts;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000328 if(*s == '+' || *s == '-')
329 s++;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000330 for (; *s; s++) {
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000331 if(c >= (int)(sizeof(flags)*8))
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000332 break;
333 on_off->opt = *s;
334 on_off->switch_on = (1 << c);
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000335 if (s[1] == ':') {
336 on_off->optarg = va_arg (p, void **);
337 do
338 s++;
339 while (s[1] == ':');
340 }
341 on_off++;
342 c++;
Eric Andersen8876fb22003-06-20 09:01:58 +0000343 }
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000344
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000345#if ENABLE_GETOPT_LONG
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000346 for(l_o = bb_applet_long_options; l_o->name; l_o++) {
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000347 if(l_o->flag)
348 continue;
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000349 for(on_off = complementally; on_off->opt != 0; on_off++)
350 if(on_off->opt == l_o->val)
351 break;
352 if(on_off->opt == 0) {
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000353 if(c >= (int)(sizeof(flags)*8))
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000354 break;
355 on_off->opt = l_o->val;
356 on_off->switch_on = (1 << c);
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000357 if(l_o->has_arg != no_argument)
358 on_off->optarg = va_arg (p, void **);
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000359 c++;
360 }
361 }
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000362#endif /* ENABLE_GETOPT_LONG */
"Vladimir N. Oleynik"bf968f72005-12-02 10:10:28 +0000363 for (s = (const unsigned char *)bb_opt_complementally; s && *s; s++) {
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000364 t_complementally *pair;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000365 unsigned long *pair_switch;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000366
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000367 if (*s == ':')
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000368 continue;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000369 c = s[1];
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000370 if(*s == '?') {
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000371 if(c < '0' || c > '9') {
372 spec_flgs |= SHOW_USAGE_IF_ERROR;
373 } else {
374 max_arg = c - '0';
375 s++;
376 }
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000377 continue;
378 }
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000379 if(*s == '-') {
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000380 if(c < '0' || c > '9') {
381 if(c == '-') {
382 spec_flgs |= FIRST_ARGV_IS_OPT;
383 s++;
384 } else
385 spec_flgs |= ALL_ARGV_IS_OPTS;
386 } else {
387 min_arg = c - '0';
388 s++;
389 }
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000390 continue;
391 }
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000392 for (on_off = complementally; on_off->opt; on_off++)
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000393 if (on_off->opt == *s)
394 break;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000395 if(c == ':' && s[2] == ':') {
396 on_off->list_flg++;
397 continue;
398 }
399 if(c == ':' || c == '\0') {
400 requires |= on_off->switch_on;
401 continue;
402 }
"Vladimir N. Oleynik"4fc92202006-02-02 14:48:54 +0000403 if(c == '-' && (s[2] == ':' || s[2] == '\0')) {
404 flags |= on_off->switch_on;
405 on_off->incongruously |= on_off->switch_on;
406 s++;
407 continue;
408 }
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000409 if(c == *s) {
410 on_off->counter = va_arg (p, int *);
411 s++;
412 }
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000413 pair = on_off;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000414 pair_switch = &(pair->switch_on);
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000415 for(s++; *s && *s != ':'; s++) {
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000416 if(*s == '?') {
417 pair_switch = &(pair->requires);
418 } else if (*s == '-') {
419 if(pair_switch == &(pair->switch_off))
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000420 pair_switch = &(pair->incongruously);
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000421 else
422 pair_switch = &(pair->switch_off);
423 } else {
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000424 for (on_off = complementally; on_off->opt; on_off++)
425 if (on_off->opt == *s) {
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000426 *pair_switch |= on_off->switch_on;
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000427 break;
428 }
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000429 }
430 }
431 s--;
Eric Andersen8876fb22003-06-20 09:01:58 +0000432 }
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000433 va_end (p);
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000434
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000435#if defined(CONFIG_AR) || defined(CONFIG_TAR)
436 if((spec_flgs & FIRST_ARGV_IS_OPT)) {
437 if(argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') {
Rob Landleyd921b2e2006-08-03 15:41:12 +0000438 argv[1] = xasprintf("-%s", argv[1]);
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000439 if(ENABLE_FEATURE_CLEAN_UP)
440 spec_flgs |= FREE_FIRST_ARGV_IS_OPT;
441 }
442 }
443#endif
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000444#if ENABLE_GETOPT_LONG
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000445 while ((c = getopt_long (argc, argv, applet_opts,
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000446 bb_applet_long_options, NULL)) >= 0) {
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000447#else
448 while ((c = getopt (argc, argv, applet_opts)) >= 0) {
449#endif /* ENABLE_GETOPT_LONG */
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000450#ifdef CONFIG_PS
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000451loop_arg_is_opt:
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000452#endif
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000453 for (on_off = complementally; on_off->opt != c; on_off++) {
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000454 /* c==0 if long opt have non NULL flag */
455 if(on_off->opt == 0 && c != 0)
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000456 bb_show_usage ();
457 }
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000458 if(flags & on_off->incongruously) {
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000459 if((spec_flgs & SHOW_USAGE_IF_ERROR))
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000460 bb_show_usage ();
Mike Frysinger348e84c2005-05-11 00:39:03 +0000461 flags |= BB_GETOPT_ERROR;
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000462 }
"Vladimir N. Oleynik"45a8ed82005-09-06 16:08:33 +0000463 trigger = on_off->switch_on & on_off->switch_off;
464 flags &= ~(on_off->switch_off ^ trigger);
465 flags |= on_off->switch_on ^ trigger;
466 flags ^= trigger;
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000467 if(on_off->counter)
468 (*(on_off->counter))++;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000469 if(on_off->list_flg) {
Rob Landley8bb50782006-05-26 23:44:51 +0000470 llist_add_to((llist_t **)(on_off->optarg), optarg);
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000471 } else if (on_off->optarg) {
472 *(char **)(on_off->optarg) = optarg;
473 }
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000474#ifdef CONFIG_PS
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000475 if(pargv != NULL)
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000476 break;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000477#endif
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000478 }
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000479
480#ifdef CONFIG_PS
481 if((spec_flgs & ALL_ARGV_IS_OPTS)) {
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000482 /* process argv is option, for example "ps" applet */
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000483 if(pargv == NULL)
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000484 pargv = argv + optind;
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000485 while(*pargv) {
486 c = **pargv;
487 if(c == '\0') {
488 pargv++;
489 } else {
490 (*pargv)++;
491 goto loop_arg_is_opt;
492 }
493 }
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000494 }
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000495#endif
496
497#if (defined(CONFIG_AR) || defined(CONFIG_TAR)) && \
498 defined(CONFIG_FEATURE_CLEAN_UP)
499 if((spec_flgs & FREE_FIRST_ARGV_IS_OPT))
500 free(argv[1]);
501#endif
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000502 /* check depending requires for given options */
503 for (on_off = complementally; on_off->opt; on_off++) {
504 if(on_off->requires && (flags & on_off->switch_on) &&
505 (flags & on_off->requires) == 0)
506 bb_show_usage ();
507 }
508 if(requires && (flags & requires) == 0)
509 bb_show_usage ();
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000510 argc -= optind;
511 if(argc < min_arg || (max_arg >= 0 && argc > max_arg))
512 bb_show_usage ();
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000513 return flags;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000514}