blob: a57951305b28b1ef5fe257ca9f6f33d78b259efa [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
10#include <getopt.h>
11#include <string.h>
Eric Andersen8876fb22003-06-20 09:01:58 +000012#include <assert.h>
13#include <stdlib.h>
Manuel Novoa III cad53642003-03-19 09:13:01 +000014#include "libbb.h"
15
Rob Landleyf76cd962006-05-03 21:23:15 +000016/* Documentation
Mike Frysinger2bf88a82005-04-18 22:42:58 +000017
Mike Frysingere5d0bde2005-05-10 23:48:35 +000018unsigned long
Mike Frysinger2bf88a82005-04-18 22:42:58 +000019bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...)
20
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000021 The command line options must be declared in const char
22 *applet_opts as a string of chars, for example:
Mike Frysinger2bf88a82005-04-18 22:42:58 +000023
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000024 flags = bb_getopt_ulflags(argc, argv, "rnug");
Mike Frysinger2bf88a82005-04-18 22:42:58 +000025
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000026 If one of the given options is found, a flag value is added to
27 the return value (an unsigned long).
Mike Frysinger2bf88a82005-04-18 22:42:58 +000028
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000029 The flag value is determined by the position of the char in
30 applet_opts string. For example, in the above case:
Mike Frysinger2bf88a82005-04-18 22:42:58 +000031
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000032 flags = bb_getopt_ulflags(argc, argv, "rnug");
Mike Frysinger2bf88a82005-04-18 22:42:58 +000033
Rob Landleyf76cd962006-05-03 21:23:15 +000034 "r" will add 1 (bit 0)
35 "n" will add 2 (bit 1)
36 "u will add 4 (bit 2)
37 "g" will add 8 (bit 3)
Mike Frysinger2bf88a82005-04-18 22:42:58 +000038
Rob Landleyf76cd962006-05-03 21:23:15 +000039 and so on. You can also look at the return value as a bit
40 field and each option sets one bit.
Mike Frysinger2bf88a82005-04-18 22:42:58 +000041
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000042 ":" If one of the options requires an argument, then add a ":"
43 after the char in applet_opts and provide a pointer to store
44 the argument. For example:
Mike Frysinger2bf88a82005-04-18 22:42:58 +000045
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000046 char *pointer_to_arg_for_a;
47 char *pointer_to_arg_for_b;
48 char *pointer_to_arg_for_c;
49 char *pointer_to_arg_for_d;
Mike Frysinger2bf88a82005-04-18 22:42:58 +000050
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000051 flags = bb_getopt_ulflags(argc, argv, "a:b:c:d:",
Rob Landleyf76cd962006-05-03 21:23:15 +000052 &pointer_to_arg_for_a, &pointer_to_arg_for_b,
53 &pointer_to_arg_for_c, &pointer_to_arg_for_d);
Mike Frysinger2bf88a82005-04-18 22:42:58 +000054
Rob Landleyf76cd962006-05-03 21:23:15 +000055 The type of the pointer (char* or llist_t*) may be controlled
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +000056 by the "::" special separator that is set in the external string
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000057 bb_opt_complementally (see below for more info).
Mike Frysingere5d0bde2005-05-10 23:48:35 +000058
Mike Frysinger992a58c2006-02-22 22:56:30 +000059 "+" If the first character in the applet_opts string is a plus,
60 then option processing will stop as soon as a non-option is
61 encountered in the argv array. Useful for applets like env
62 which should not process arguments to subprograms:
63 env -i ls -d /
64 Here we want env to process just the '-i', not the '-d'.
65
Rob Landleyf76cd962006-05-03 21:23:15 +000066const struct option *bb_applet_long_options
Mike Frysingere5d0bde2005-05-10 23:48:35 +000067
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000068 This struct allows you to define long options. The syntax for
69 declaring the array is just like that of getopt's longopts.
70 (see getopt(3))
Mike Frysingere5d0bde2005-05-10 23:48:35 +000071
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000072 static const struct option applet_long_options[] = {
Rob Landleyf76cd962006-05-03 21:23:15 +000073 { "verbose", 0, 0, 'v' },
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000074 { 0, 0, 0, 0 }
75 };
76 bb_applet_long_options = applet_long_options;
Mike Frysingere5d0bde2005-05-10 23:48:35 +000077
Rob Landleyf76cd962006-05-03 21:23:15 +000078 The last member of struct option (val) typically is set to
79 matching short option from applet_opts. If there is no matching
80 char in applet_opts, then:
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000081 - return bit have next position after short options
82 - if has_arg is not "no_argument", use ptr for arg also
Rob Landleyf76cd962006-05-03 21:23:15 +000083 - bb_opt_complementally affects it too
Mike Frysingerfb6d22c2005-05-11 00:02:39 +000084
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000085 Note: a good applet will make long options configurable via the
86 config process and not a required feature. The current standard
87 is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS.
Mike Frysingerfb6d22c2005-05-11 00:02:39 +000088
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000089const char *bb_opt_complementally
Mike Frysinger57f4cb22006-02-21 00:50:37 +000090 this should be bb_opt_complementary, but we'll just keep it as
91 bb_opt_complementally due to the Russian origins
Mike Frysingerfb6d22c2005-05-11 00:02:39 +000092
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000093 ":" The colon (":") is used to separate groups of two or more chars
94 and/or groups of chars and special characters (stating some
95 conditions to be checked).
Mike Frysingere5d0bde2005-05-10 23:48:35 +000096
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +000097 "abc" If groups of two or more chars are specified, the first char
98 is the main option and the other chars are secondary options.
99 Their flags will be turned on if the main option is found even
100 if they are not specifed on the command line. For example:
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000101
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000102 bb_opt_complementally = "abc";
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000103
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000104 flags = bb_getopt_ulflags(argc, argv, "abcd")
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000105
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000106 If getopt() finds "-a" on the command line, then
107 bb_getopt_ulflags's return value will be as if "-a -b -c" were
108 found.
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000109
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000110 "ww" Adjacent double options have a counter associated which indicates
Rob Landleyf76cd962006-05-03 21:23:15 +0000111 the number of occurences of the option.
"Vladimir N. Oleynik"d1b60782005-10-05 12:44:52 +0000112 For example the ps applet needs:
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000113 if w is given once, GNU ps sets the width to 132,
114 if w is given more than once, it is "unlimited"
115
116 int w_counter = 0;
117 bb_opt_complementally = "ww";
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000118 bb_getopt_ulflags(argc, argv, "w", &w_counter);
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000119
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000120 if(w_counter)
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000121 width = (w_counter == 1) ? 132 : INT_MAX;
122 else
123 get_terminal_width(...&width...);
124
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000125 w_counter is a pointer to an integer. It has to be passed to
126 bb_getopt_ulflags() after all other option argument sinks.
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000127 For example: accept multiple -v to indicate the level of verbosity
128 and for each -b optarg, add optarg to my_b. Finally, if b is given,
129 turn off c and vice versa:
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000130
131 llist_t *my_b = NULL;
132 int verbose_level = 0;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000133 bb_opt_complementally = "vv:b::b-c:c-b";
"Vladimir N. Oleynik"4a5ce082005-10-05 13:58:40 +0000134 f = bb_getopt_ulflags(argc, argv, "vb:c", &my_b, &verbose_level);
Rob Landleyf76cd962006-05-03 21:23:15 +0000135 if((f & 2)) // -c after -b unsets -b flag
136 while(my_b) { dosomething_with(my_b->data) ; my_b = my_b->link; }
137 if(my_b) // but llist is stored if -b is specified
"Vladimir N. Oleynik"4a5ce082005-10-05 13:58:40 +0000138 free_llist(my_b);
Rob Landleyf76cd962006-05-03 21:23:15 +0000139 if(verbose_level) bb_printf("verbose level is %d\n", verbose_level);
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000140
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000141Special characters:
142
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000143 "-" A dash between two options causes the second of the two
Rob Landleyf76cd962006-05-03 21:23:15 +0000144 to be unset (and ignored) if it is given on the command line.
145
146 [FIXME: what if they are the same? like "x-x"? Is it ever useful?]
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000147
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000148 For example:
149 The du applet has the options "-s" and "-d depth". If
150 bb_getopt_ulflags finds -s, then -d is unset or if it finds -d
151 then -s is unset. (Note: busybox implements the GNU
152 "--max-depth" option as "-d".) To obtain this behavior, you
153 set bb_opt_complementally = "s-d:d-s". Only one flag value is
154 added to bb_getopt_ulflags's return value depending on the
155 position of the options on the command line. If one of the
156 two options requires an argument pointer (":" in applet_opts
157 as in "d:") optarg is set accordingly.
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000158
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000159 char *smax_print_depth;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000160
"Vladimir N. Oleynik"45a8ed82005-09-06 16:08:33 +0000161 bb_opt_complementally = "s-d:d-s:x-x";
162 opt = bb_getopt_ulflags(argc, argv, "sd:x", &smax_print_depth);
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000163
Rob Landleyf76cd962006-05-03 21:23:15 +0000164 if (opt & 2)
165 max_print_depth = atoi(smax_print_depth);
166 if (opt & 4)
167 printf("Detected odd -x usage\n");
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000168
Rob Landleyf76cd962006-05-03 21:23:15 +0000169 "-" A dash as the first char in a bb_opt_complementally group forces
170 all arguments to be treated as options, even if they have
171 no leading dashes. Next char in this case can't be a digit (0-9),
172 use ':' or end of line. For example:
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000173
"Vladimir N. Oleynik"d1b60782005-10-05 12:44:52 +0000174 bb_opt_complementally = "-:w-x:x-w";
175 bb_getopt_ulflags(argc, argv, "wx");
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000176
"Vladimir N. Oleynik"4a5ce082005-10-05 13:58:40 +0000177 Allows any arguments to be given without a dash (./program w x)
Rob Landleyf76cd962006-05-03 21:23:15 +0000178 as well as with a dash (./program -x).
Bernhard Reutner-Fischer43fb3fc2005-10-05 12:23:13 +0000179
Rob Landleyf76cd962006-05-03 21:23:15 +0000180 "-N" A dash as the first char in a bb_opt_complementally group followed
181 by a single digit (0-9) means that at least N non-option
182 arguments must be present on the command line
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000183
Rob Landleyf76cd962006-05-03 21:23:15 +0000184 "V-" An option with dash before colon or end-of-line results in
185 bb_show_usage being called if this option is encountered.
186 This is typically used to implement "print verbose usage message
187 and exit" option.
"Vladimir N. Oleynik"4fc92202006-02-02 14:48:54 +0000188
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000189 "--" A double dash between two options, or between an option and a group
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000190 of options, means that they are mutually exclusive. Unlike
191 the "-" case above, an error will be forced if the options
192 are used together.
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000193
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000194 For example:
195 The cut applet must have only one type of list specified, so
196 -b, -c and -f are mutally exclusive and should raise an error
197 if specified together. In this case you must set
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000198 bb_opt_complementally = "b--cf:c--bf:f--bc". If two of the
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000199 mutually exclusive options are found, bb_getopt_ulflags's
200 return value will have the error flag set (BB_GETOPT_ERROR) so
201 that we can check for it:
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000202
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000203 if (flags & BB_GETOPT_ERROR)
204 bb_show_usage();
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000205
Rob Landleyf76cd962006-05-03 21:23:15 +0000206 "?" A "?" as the first char in a bb_opt_complementally group means:
207 if BB_GETOPT_ERROR is detected, don't return, call bb_show_usage
208 and exit instead. Next char after '?' can't be a digit.
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000209
Rob Landleyf76cd962006-05-03 21:23:15 +0000210 "?N" A "?" as the first char in a bb_opt_complementally group followed
211 by a single digit (0-9) means that at most N arguments must be present
212 on the command line.
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000213
214 "::" A double colon after a char in bb_opt_complementally means that the
Rob Landleyf76cd962006-05-03 21:23:15 +0000215 option can occur multiple times. Each occurrence will be saved as
216 a llist_t element instead of char*.
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000217
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000218 For example:
219 The grep applet can have one or more "-e pattern" arguments.
220 In this case you should use bb_getopt_ulflags() as follows:
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000221
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000222 llist_t *patterns = NULL;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000223
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000224 (this pointer must be initializated to NULL if the list is empty
225 as required by *llist_add_to(llist_t *old_head, char *new_item).)
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000226
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000227 bb_opt_complementally = "e::";
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000228
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000229 bb_getopt_ulflags(argc, argv, "e:", &patterns);
230 $ grep -e user -e root /etc/passwd
231 root:x:0:0:root:/root:/bin/bash
232 user:x:500:500::/home/user:/bin/bash
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000233
Mike Frysingere17c80e2006-02-21 00:37:42 +0000234 "--" A double dash at the beginning of bb_opt_complementally means the
235 argv[1] string should always be treated as options, even if it isn't
236 prefixed with a "-". This is to support the special syntax in applets
237 such as "ar" and "tar":
238 tar xvf foo.tar
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000239
Rob Landleyf76cd962006-05-03 21:23:15 +0000240 "?" An "?" between an option and a group of options means that
241 at least one of them is required to occur if the first option
242 occurs in preceding command line arguments.
243
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000244 For example from "id" applet:
245
246 // Don't allow -n -r -rn -ug -rug -nug -rnug
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000247 bb_opt_complementally = "r?ug:n?ug:?u--g:g--u";
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000248 flags = bb_getopt_ulflags(argc, argv, "rnug");
249
250 This example allowed only:
251 $ id; id -u; id -g; id -ru; id -nu; id -rg; id -ng; id -rnu; id -rng
252
Rob Landleyf76cd962006-05-03 21:23:15 +0000253 "X" A bb_opt_complementally group with just a single letter means
254 that this this option is required. If more than one such group exists,
255 at least one option is required to occur (not all of them).
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000256 For example from "start-stop-daemon" applet:
257
Rob Landleyf76cd962006-05-03 21:23:15 +0000258 // Don't allow -KS -SK, but -S or -K is required
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000259 bb_opt_complementally = "K:S:?K--S:S--K";
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000260 flags = bb_getopt_ulflags(argc, argv, "KS...);
261
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000262
263 "x--x" give error if double or more used -x option
264
Rob Landleyf76cd962006-05-03 21:23:15 +0000265 Don't forget to use ':'. For example "?322-22-23X-x-a" is interpreted as
266 "?3:22:-2:2-2:2-3Xa:2--x": max 3 args; count uses of '-2'; min 2 args;
267 if there is a '-2' option then unset '-3', '-X' and '-a'; if there is
268 a '-2' and after it a '-x' then error out.
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000269
Eric Andersen8876fb22003-06-20 09:01:58 +0000270*/
271
Mike Frysingere17c80e2006-02-21 00:37:42 +0000272/* this should be bb_opt_complementary, but we'll just keep it as
273 bb_opt_complementally due to the Russian origins */
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000274const char *bb_opt_complementally;
Eric Andersen8876fb22003-06-20 09:01:58 +0000275
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000276typedef struct {
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000277 int opt;
278 int list_flg;
Eric Andersen8876fb22003-06-20 09:01:58 +0000279 unsigned long switch_on;
280 unsigned long switch_off;
281 unsigned long incongruously;
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000282 unsigned long requires;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000283 void **optarg; /* char **optarg or llist_t **optarg */
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000284 int *counter;
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000285} t_complementally;
Eric Andersen8876fb22003-06-20 09:01:58 +0000286
287/* You can set bb_applet_long_options for parse called long options */
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000288#if ENABLE_GETOPT_LONG
Eric Andersen8876fb22003-06-20 09:01:58 +0000289static const struct option bb_default_long_options[] = {
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000290/* { "help", 0, NULL, '?' }, */
Eric Andersen8876fb22003-06-20 09:01:58 +0000291 { 0, 0, 0, 0 }
292};
293
294const struct option *bb_applet_long_options = bb_default_long_options;
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000295#endif
Eric Andersen8876fb22003-06-20 09:01:58 +0000296
Eric Andersen8876fb22003-06-20 09:01:58 +0000297unsigned long
298bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...)
Manuel Novoa III cad53642003-03-19 09:13:01 +0000299{
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000300 unsigned long flags = 0;
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000301 unsigned long requires = 0;
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000302 t_complementally complementally[sizeof(flags) * 8 + 1];
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000303 int c;
304 const unsigned char *s;
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000305 t_complementally *on_off;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000306 va_list p;
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000307#if ENABLE_GETOPT_LONG
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000308 const struct option *l_o;
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000309#endif
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000310 unsigned long trigger;
"Vladimir N. Oleynik"f01e1782006-01-09 13:28:31 +0000311#ifdef CONFIG_PS
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000312 char **pargv = NULL;
"Vladimir N. Oleynik"f01e1782006-01-09 13:28:31 +0000313#endif
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000314 int min_arg = 0;
315 int max_arg = -1;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000316
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000317#define SHOW_USAGE_IF_ERROR 1
318#define ALL_ARGV_IS_OPTS 2
319#define FIRST_ARGV_IS_OPT 4
320#define FREE_FIRST_ARGV_IS_OPT 8
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000321 int spec_flgs = 0;
322
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000323 va_start (p, applet_opts);
Eric Andersen8876fb22003-06-20 09:01:58 +0000324
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000325 c = 0;
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000326 on_off = complementally;
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000327 memset(on_off, 0, sizeof(complementally));
328
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000329 /* skip GNU extension */
"Vladimir N. Oleynik"bf968f72005-12-02 10:10:28 +0000330 s = (const unsigned char *)applet_opts;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000331 if(*s == '+' || *s == '-')
332 s++;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000333 for (; *s; s++) {
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000334 if(c >= (int)(sizeof(flags)*8))
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000335 break;
336 on_off->opt = *s;
337 on_off->switch_on = (1 << c);
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000338 if (s[1] == ':') {
339 on_off->optarg = va_arg (p, void **);
340 do
341 s++;
342 while (s[1] == ':');
343 }
344 on_off++;
345 c++;
Eric Andersen8876fb22003-06-20 09:01:58 +0000346 }
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000347
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000348#if ENABLE_GETOPT_LONG
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000349 for(l_o = bb_applet_long_options; l_o->name; l_o++) {
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000350 if(l_o->flag)
351 continue;
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000352 for(on_off = complementally; on_off->opt != 0; on_off++)
353 if(on_off->opt == l_o->val)
354 break;
355 if(on_off->opt == 0) {
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000356 if(c >= (int)(sizeof(flags)*8))
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000357 break;
358 on_off->opt = l_o->val;
359 on_off->switch_on = (1 << c);
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000360 if(l_o->has_arg != no_argument)
361 on_off->optarg = va_arg (p, void **);
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000362 c++;
363 }
364 }
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000365#endif /* ENABLE_GETOPT_LONG */
"Vladimir N. Oleynik"bf968f72005-12-02 10:10:28 +0000366 for (s = (const unsigned char *)bb_opt_complementally; s && *s; s++) {
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000367 t_complementally *pair;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000368 unsigned long *pair_switch;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000369
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000370 if (*s == ':')
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000371 continue;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000372 c = s[1];
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000373 if(*s == '?') {
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000374 if(c < '0' || c > '9') {
375 spec_flgs |= SHOW_USAGE_IF_ERROR;
376 } else {
377 max_arg = c - '0';
378 s++;
379 }
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000380 continue;
381 }
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000382 if(*s == '-') {
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000383 if(c < '0' || c > '9') {
384 if(c == '-') {
385 spec_flgs |= FIRST_ARGV_IS_OPT;
386 s++;
387 } else
388 spec_flgs |= ALL_ARGV_IS_OPTS;
389 } else {
390 min_arg = c - '0';
391 s++;
392 }
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000393 continue;
394 }
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000395 for (on_off = complementally; on_off->opt; on_off++)
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000396 if (on_off->opt == *s)
397 break;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000398 if(c == ':' && s[2] == ':') {
399 on_off->list_flg++;
400 continue;
401 }
402 if(c == ':' || c == '\0') {
403 requires |= on_off->switch_on;
404 continue;
405 }
"Vladimir N. Oleynik"4fc92202006-02-02 14:48:54 +0000406 if(c == '-' && (s[2] == ':' || s[2] == '\0')) {
407 flags |= on_off->switch_on;
408 on_off->incongruously |= on_off->switch_on;
409 s++;
410 continue;
411 }
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000412 if(c == *s) {
413 on_off->counter = va_arg (p, int *);
414 s++;
415 }
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000416 pair = on_off;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000417 pair_switch = &(pair->switch_on);
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000418 for(s++; *s && *s != ':'; s++) {
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000419 if(*s == '?') {
420 pair_switch = &(pair->requires);
421 } else if (*s == '-') {
422 if(pair_switch == &(pair->switch_off))
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000423 pair_switch = &(pair->incongruously);
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000424 else
425 pair_switch = &(pair->switch_off);
426 } else {
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000427 for (on_off = complementally; on_off->opt; on_off++)
428 if (on_off->opt == *s) {
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000429 *pair_switch |= on_off->switch_on;
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000430 break;
431 }
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000432 }
433 }
434 s--;
Eric Andersen8876fb22003-06-20 09:01:58 +0000435 }
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000436 va_end (p);
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000437
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000438#if defined(CONFIG_AR) || defined(CONFIG_TAR)
439 if((spec_flgs & FIRST_ARGV_IS_OPT)) {
440 if(argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') {
441 argv[1] = bb_xasprintf("-%s", argv[1]);
442 if(ENABLE_FEATURE_CLEAN_UP)
443 spec_flgs |= FREE_FIRST_ARGV_IS_OPT;
444 }
445 }
446#endif
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000447#if ENABLE_GETOPT_LONG
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000448 while ((c = getopt_long (argc, argv, applet_opts,
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000449 bb_applet_long_options, NULL)) >= 0) {
Bernhard Reutner-Fischerf9437aa2006-05-31 14:12:51 +0000450#else
451 while ((c = getopt (argc, argv, applet_opts)) >= 0) {
452#endif /* ENABLE_GETOPT_LONG */
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000453#ifdef CONFIG_PS
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000454loop_arg_is_opt:
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000455#endif
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000456 for (on_off = complementally; on_off->opt != c; on_off++) {
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000457 /* c==0 if long opt have non NULL flag */
458 if(on_off->opt == 0 && c != 0)
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000459 bb_show_usage ();
460 }
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000461 if(flags & on_off->incongruously) {
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000462 if((spec_flgs & SHOW_USAGE_IF_ERROR))
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000463 bb_show_usage ();
Mike Frysinger348e84c2005-05-11 00:39:03 +0000464 flags |= BB_GETOPT_ERROR;
"Vladimir N. Oleynik"27421a12005-09-05 14:46:07 +0000465 }
"Vladimir N. Oleynik"45a8ed82005-09-06 16:08:33 +0000466 trigger = on_off->switch_on & on_off->switch_off;
467 flags &= ~(on_off->switch_off ^ trigger);
468 flags |= on_off->switch_on ^ trigger;
469 flags ^= trigger;
"Vladimir N. Oleynik"be0ed3d2005-10-04 16:48:26 +0000470 if(on_off->counter)
471 (*(on_off->counter))++;
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000472 if(on_off->list_flg) {
Rob Landley8bb50782006-05-26 23:44:51 +0000473 llist_add_to((llist_t **)(on_off->optarg), optarg);
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000474 } else if (on_off->optarg) {
475 *(char **)(on_off->optarg) = optarg;
476 }
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000477#ifdef CONFIG_PS
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000478 if(pargv != NULL)
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000479 break;
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000480#endif
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000481 }
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000482
483#ifdef CONFIG_PS
484 if((spec_flgs & ALL_ARGV_IS_OPTS)) {
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000485 /* process argv is option, for example "ps" applet */
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000486 if(pargv == NULL)
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000487 pargv = argv + optind;
"Vladimir N. Oleynik"35939d92005-10-05 10:52:47 +0000488 while(*pargv) {
489 c = **pargv;
490 if(c == '\0') {
491 pargv++;
492 } else {
493 (*pargv)++;
494 goto loop_arg_is_opt;
495 }
496 }
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000497 }
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000498#endif
499
500#if (defined(CONFIG_AR) || defined(CONFIG_TAR)) && \
501 defined(CONFIG_FEATURE_CLEAN_UP)
502 if((spec_flgs & FREE_FIRST_ARGV_IS_OPT))
503 free(argv[1]);
504#endif
"Vladimir N. Oleynik"064f04e2005-10-11 14:38:01 +0000505 /* check depending requires for given options */
506 for (on_off = complementally; on_off->opt; on_off++) {
507 if(on_off->requires && (flags & on_off->switch_on) &&
508 (flags & on_off->requires) == 0)
509 bb_show_usage ();
510 }
511 if(requires && (flags & requires) == 0)
512 bb_show_usage ();
"Vladimir N. Oleynik"f704b272005-10-14 09:56:52 +0000513 argc -= optind;
514 if(argc < min_arg || (max_arg >= 0 && argc > max_arg))
515 bb_show_usage ();
Mike Frysinger2bf88a82005-04-18 22:42:58 +0000516 return flags;
Manuel Novoa III cad53642003-03-19 09:13:01 +0000517}