diff options
author | "Vladimir N. Oleynik" <dzo@simtreas.ru> | 2005-09-05 14:46:07 +0000 |
---|---|---|
committer | "Vladimir N. Oleynik" <dzo@simtreas.ru> | 2005-09-05 14:46:07 +0000 |
commit | 27421a1878847389391c1a43420baaccf57057a7 (patch) | |
tree | 73e57d430a5828d242b78deb0a591a99f0df44a9 /libbb | |
parent | bef14d7a878049a01f1fb9b412611a2d64c2b154 (diff) | |
download | busybox-w32-27421a1878847389391c1a43420baaccf57057a7.tar.gz busybox-w32-27421a1878847389391c1a43420baaccf57057a7.tar.bz2 busybox-w32-27421a1878847389391c1a43420baaccf57057a7.zip |
1) bb_opt_complementaly -> bb_opt_complementally
2) better support long options
3) new flag '!' for bb_opt_complementally: produce bb_show_usage() if BB_GETOPT_ERROR internally
Diffstat (limited to 'libbb')
-rw-r--r-- | libbb/getopt_ulflags.c | 273 |
1 files changed, 149 insertions, 124 deletions
diff --git a/libbb/getopt_ulflags.c b/libbb/getopt_ulflags.c index 6197e8d9f..44c8e1a76 100644 --- a/libbb/getopt_ulflags.c +++ b/libbb/getopt_ulflags.c | |||
@@ -2,7 +2,7 @@ | |||
2 | /* | 2 | /* |
3 | * universal getopt_ulflags implementation for busybox | 3 | * universal getopt_ulflags implementation for busybox |
4 | * | 4 | * |
5 | * Copyright (C) 2003 Vladimir Oleynik <dzo@simtreas.ru> | 5 | * Copyright (C) 2003-2005 Vladimir Oleynik <dzo@simtreas.ru> |
6 | * | 6 | * |
7 | * This program is free software; you can redistribute it and/or modify | 7 | * This program is free software; you can redistribute it and/or modify |
8 | * it under the terms of the GNU General Public License as published by | 8 | * it under the terms of the GNU General Public License as published by |
@@ -31,158 +31,152 @@ | |||
31 | unsigned long | 31 | unsigned long |
32 | bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | 32 | bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) |
33 | 33 | ||
34 | The command line options must be declared in const char | 34 | The command line options must be declared in const char |
35 | *applet_opts as a string of chars, for example: | 35 | *applet_opts as a string of chars, for example: |
36 | 36 | ||
37 | flags = bb_getopt_ulflags(argc, argv, "rnug"); | 37 | flags = bb_getopt_ulflags(argc, argv, "rnug"); |
38 | 38 | ||
39 | If one of the given options is found, a flag value is added to | 39 | If one of the given options is found, a flag value is added to |
40 | the return value (an unsigned long). | 40 | the return value (an unsigned long). |
41 | 41 | ||
42 | The flag value is determined by the position of the char in | 42 | The flag value is determined by the position of the char in |
43 | applet_opts string. For example, in the above case: | 43 | applet_opts string. For example, in the above case: |
44 | 44 | ||
45 | flags = bb_getopt_ulflags(argc, argv, "rnug"); | 45 | flags = bb_getopt_ulflags(argc, argv, "rnug"); |
46 | 46 | ||
47 | "r" will add 1 (bit 1 : 0x01) | 47 | "r" will add 1 (bit 1 : 0x01) |
48 | "n" will add 2 (bit 2 : 0x02) | 48 | "n" will add 2 (bit 2 : 0x02) |
49 | "u will add 4 (bit 3 : 0x03) | 49 | "u will add 4 (bit 3 : 0x03) |
50 | "g" will add 8 (bit 4 : 0x04) | 50 | "g" will add 8 (bit 4 : 0x04) |
51 | 51 | ||
52 | and so on. You can also look at the return value as a bit | 52 | and so on. You can also look at the return value as a bit |
53 | field and each option sets one of bits. | 53 | field and each option sets one of bits. |
54 | 54 | ||
55 | ":" If one of the options requires an argument, then add a ":" | 55 | ":" If one of the options requires an argument, then add a ":" |
56 | after the char in applet_opts and provide a pointer to store | 56 | after the char in applet_opts and provide a pointer to store |
57 | the argument. For example: | 57 | the argument. For example: |
58 | 58 | ||
59 | char *pointer_to_arg_for_a; | 59 | char *pointer_to_arg_for_a; |
60 | char *pointer_to_arg_for_b; | 60 | char *pointer_to_arg_for_b; |
61 | char *pointer_to_arg_for_c; | 61 | char *pointer_to_arg_for_c; |
62 | char *pointer_to_arg_for_d; | 62 | char *pointer_to_arg_for_d; |
63 | 63 | ||
64 | flags = bb_getopt_ulflags(argc, argv, "a:b:c:d:", | 64 | flags = bb_getopt_ulflags(argc, argv, "a:b:c:d:", |
65 | &pointer_to_arg_for_a, &pointer_to_arg_for_b, | 65 | &pointer_to_arg_for_a, &pointer_to_arg_for_b, |
66 | &pointer_to_arg_for_c, &pointer_to_arg_for_d); | 66 | &pointer_to_arg_for_c, &pointer_to_arg_for_d); |
67 | 67 | ||
68 | The type of the pointer (char* or llist_t *) may be controlled | 68 | The type of the pointer (char* or llist_t *) may be controlled |
69 | by the "*" special character that is set in the external string | 69 | by the "*" special character that is set in the external string |
70 | bb_opt_complementaly (see below for more info). | 70 | bb_opt_complementally (see below for more info). |
71 | 71 | ||
72 | static const struct option bb_default_long_options[] | 72 | static const struct option bb_default_long_options[] |
73 | 73 | ||
74 | This struct allows you to define long options. The syntax for | 74 | This struct allows you to define long options. The syntax for |
75 | declaring the array is just like that of getopt's longopts. | 75 | declaring the array is just like that of getopt's longopts. |
76 | (see getopt(3)) | ||
76 | 77 | ||
77 | static const struct option applet_long_options[] = { | 78 | static const struct option applet_long_options[] = { |
78 | { "verbose", 0, 0, "v" }, | 79 | { "verbose", 0, 0, v }, |
79 | { 0, 0, 0, 0 } | 80 | { 0, 0, 0, 0 } |
80 | }; | 81 | }; |
81 | bb_applet_long_options = applet_long_options; | 82 | bb_applet_long_options = applet_long_options; |
82 | 83 | ||
83 | The first parameter is the long option name that you would pass | 84 | The last argument (val) can undefined from applet_opts. |
84 | to the applet (without the dashes). | 85 | If you use this, then: |
86 | - return bit have next position after short options | ||
87 | - if has_arg is not "no_argument", use ptr for arg also | ||
88 | - bb_opt_complementally have effects for this too | ||
85 | 89 | ||
86 | The second field determines whether the option has an argument. | 90 | Note: a good applet will make long options configurable via the |
87 | You can set this to 0, 1, or 2, or you can use the long named | 91 | config process and not a required feature. The current standard |
88 | defines of no_argument, required_argument, and optional_argument. | 92 | is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS. |
89 | 93 | ||
90 | The third argument is used only when the long option does not | 94 | const char *bb_opt_complementally |
91 | have a corresponding short option. In that case, it should be | ||
92 | an integer pointer. Otherwise (and normally), it should just | ||
93 | bet set to NULL. | ||
94 | 95 | ||
95 | The last argument is the corresponding short option (if there | 96 | ":" The colon (":") is used to separate groups of two or more chars |
96 | is one of course). | 97 | and/or groups of chars and special characters (stating some |
98 | conditions to be checked). | ||
97 | 99 | ||
98 | Note: a good applet will make long options configurable via the | 100 | "abc" If groups of two or more chars are specified, the first char |
99 | config process and not a required feature. The current standard | 101 | is the main option and the other chars are secondary options. |
100 | is to name the config option CONFIG_FEATURE_<applet>_LONG_OPTIONS. | 102 | Their flags will be turned on if the main option is found even |
103 | if they are not specifed on the command line. For example: | ||
101 | 104 | ||
102 | const char *bb_opt_complementaly | 105 | bb_opt_complementally = "abc"; |
103 | 106 | ||
104 | ":" The colon (":") is used to separate groups of two or more chars | 107 | flags = bb_getopt_ulflags(argc, argv, "abcd") |
105 | and/or groups of chars and special characters (stating some | ||
106 | conditions to be checked). | ||
107 | 108 | ||
108 | "abc" If groups of two or more chars are specified, the first char | 109 | If getopt() finds "-a" on the command line, then |
109 | is the main option and the other chars are secondary options. | 110 | bb_getopt_ulflags's return value will be as if "-a -b -c" were |
110 | Their flags will be turned on if the main option is found even | 111 | found. |
111 | if they are not specifed on the command line. For example: | ||
112 | |||
113 | bb_opt_complementaly = "abc"; | ||
114 | |||
115 | flags = bb_getopt_ulflags(argc, argv, "abcd") | ||
116 | |||
117 | If getopt() finds "-a" on the command line, then | ||
118 | bb_getopt_ulflags's return value will be as if "-a -b -c" were | ||
119 | found. | ||
120 | 112 | ||
121 | Special characters: | 113 | Special characters: |
122 | 114 | ||
123 | "-" A dash between two options causes the second of the two | 115 | "-" A dash between two options causes the second of the two |
124 | to be unset (and ignored) if it is given on the command line. | 116 | to be unset (and ignored) if it is given on the command line. |
125 | 117 | ||
126 | For example: | 118 | For example: |
127 | The du applet has the options "-s" and "-d depth". If | 119 | The du applet has the options "-s" and "-d depth". If |
128 | bb_getopt_ulflags finds -s, then -d is unset or if it finds -d | 120 | bb_getopt_ulflags finds -s, then -d is unset or if it finds -d |
129 | then -s is unset. (Note: busybox implements the GNU | 121 | then -s is unset. (Note: busybox implements the GNU |
130 | "--max-depth" option as "-d".) To obtain this behavior, you | 122 | "--max-depth" option as "-d".) To obtain this behavior, you |
131 | set bb_opt_complementaly = "s-d:d-s". Only one flag value is | 123 | set bb_opt_complementally = "s-d:d-s". Only one flag value is |
132 | added to bb_getopt_ulflags's return value depending on the | 124 | added to bb_getopt_ulflags's return value depending on the |
133 | position of the options on the command line. If one of the | 125 | position of the options on the command line. If one of the |
134 | two options requires an argument pointer (":" in applet_opts | 126 | two options requires an argument pointer (":" in applet_opts |
135 | as in "d:") optarg is set accordingly. | 127 | as in "d:") optarg is set accordingly. |
136 | 128 | ||
137 | char *smax_print_depth; | 129 | char *smax_print_depth; |
138 | 130 | ||
139 | bb_opt_complementaly = "s-d:d-s"; | 131 | bb_opt_complementally = "s-d:d-s"; |
140 | opt = bb_getopt_ulflags(argc, argv, "sd:", &smax_print_depth); | 132 | opt = bb_getopt_ulflags(argc, argv, "sd:", &smax_print_depth); |
141 | 133 | ||
142 | if (opt & 2) { | 134 | if (opt & 2) { |
143 | max_print_depth = bb_xgetularg10_bnd(smax_print_depth, | 135 | max_print_depth = bb_xgetularg10_bnd(smax_print_depth, |
144 | 0, INT_MAX); | 136 | 0, INT_MAX); |
145 | } | 137 | } |
146 | 138 | ||
147 | "~" A tilde between two options, or between an option and a group | 139 | "~" A tilde between two options, or between an option and a group |
148 | of options, means that they are mutually exclusive. Unlike | 140 | of options, means that they are mutually exclusive. Unlike |
149 | the "-" case above, an error will be forced if the options | 141 | the "-" case above, an error will be forced if the options |
150 | are used together. | 142 | are used together. |
151 | 143 | ||
152 | For example: | 144 | For example: |
153 | The cut applet must have only one type of list specified, so | 145 | The cut applet must have only one type of list specified, so |
154 | -b, -c and -f are mutally exclusive and should raise an error | 146 | -b, -c and -f are mutally exclusive and should raise an error |
155 | if specified together. In this case you must set | 147 | if specified together. In this case you must set |
156 | bb_opt_complementaly = "b~cf:c~bf:f~bc". If two of the | 148 | bb_opt_complementally = "b~cf:c~bf:f~bc". If two of the |
157 | mutually exclusive options are found, bb_getopt_ulflags's | 149 | mutually exclusive options are found, bb_getopt_ulflags's |
158 | return value will have the error flag set (BB_GETOPT_ERROR) so | 150 | return value will have the error flag set (BB_GETOPT_ERROR) so |
159 | that we can check for it: | 151 | that we can check for it: |
160 | 152 | ||
161 | if (flags & BB_GETOPT_ERROR) | 153 | if (flags & BB_GETOPT_ERROR) |
162 | bb_show_usage(); | 154 | bb_show_usage(); |
163 | 155 | ||
164 | "*" A star after a char in bb_opt_complementaly means that the | 156 | "!" If previous point set BB_GETOPT_ERROR, don`t return and call |
165 | option can occur multiple times: | 157 | previous example internally |
166 | 158 | ||
167 | For example: | 159 | "*" A star after a char in bb_opt_complementally means that the |
168 | The grep applet can have one or more "-e pattern" arguments. | 160 | option can occur multiple times: |
169 | In this case you should use bb_getopt_ulflags() as follows: | ||
170 | 161 | ||
171 | llist_t *patterns = NULL; | 162 | For example: |
163 | The grep applet can have one or more "-e pattern" arguments. | ||
164 | In this case you should use bb_getopt_ulflags() as follows: | ||
172 | 165 | ||
173 | (this pointer must be initializated to NULL if the list is empty | 166 | llist_t *patterns = NULL; |
174 | as required by *llist_add_to(llist_t *old_head, char *new_item).) | ||
175 | 167 | ||
176 | bb_opt_complementaly = "e*"; | 168 | (this pointer must be initializated to NULL if the list is empty |
169 | as required by *llist_add_to(llist_t *old_head, char *new_item).) | ||
177 | 170 | ||
178 | bb_getopt_ulflags(argc, argv, "e:", &patterns); | 171 | bb_opt_complementally = "e*"; |
179 | $ grep -e user -e root /etc/passwd | ||
180 | root:x:0:0:root:/root:/bin/bash | ||
181 | user:x:500:500::/home/user:/bin/bash | ||
182 | 172 | ||
173 | bb_getopt_ulflags(argc, argv, "e:", &patterns); | ||
174 | $ grep -e user -e root /etc/passwd | ||
175 | root:x:0:0:root:/root:/bin/bash | ||
176 | user:x:500:500::/home/user:/bin/bash | ||
183 | */ | 177 | */ |
184 | 178 | ||
185 | const char *bb_opt_complementaly; | 179 | const char *bb_opt_complementally; |
186 | 180 | ||
187 | typedef struct { | 181 | typedef struct { |
188 | unsigned char opt; | 182 | unsigned char opt; |
@@ -191,12 +185,12 @@ typedef struct { | |||
191 | unsigned long switch_off; | 185 | unsigned long switch_off; |
192 | unsigned long incongruously; | 186 | unsigned long incongruously; |
193 | void **optarg; /* char **optarg or llist_t **optarg */ | 187 | void **optarg; /* char **optarg or llist_t **optarg */ |
194 | } t_complementaly; | 188 | } t_complementally; |
195 | 189 | ||
196 | /* You can set bb_applet_long_options for parse called long options */ | 190 | /* You can set bb_applet_long_options for parse called long options */ |
197 | 191 | ||
198 | static const struct option bb_default_long_options[] = { | 192 | static const struct option bb_default_long_options[] = { |
199 | /* { "help", 0, NULL, '?' }, */ | 193 | /* { "help", 0, NULL, '?' }, */ |
200 | { 0, 0, 0, 0 } | 194 | { 0, 0, 0, 0 } |
201 | }; | 195 | }; |
202 | 196 | ||
@@ -206,11 +200,13 @@ unsigned long | |||
206 | bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | 200 | bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) |
207 | { | 201 | { |
208 | unsigned long flags = 0; | 202 | unsigned long flags = 0; |
209 | t_complementaly complementaly[sizeof(flags) * 8 + 1]; | 203 | t_complementally complementally[sizeof(flags) * 8 + 1]; |
210 | int c; | 204 | int c; |
211 | const unsigned char *s; | 205 | const unsigned char *s; |
212 | t_complementaly *on_off; | 206 | t_complementally *on_off; |
213 | va_list p; | 207 | va_list p; |
208 | const struct option *l_o; | ||
209 | char flg_show_usage_if_error = 0; | ||
214 | 210 | ||
215 | va_start (p, applet_opts); | 211 | va_start (p, applet_opts); |
216 | 212 | ||
@@ -220,7 +216,7 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | |||
220 | s++; | 216 | s++; |
221 | 217 | ||
222 | c = 0; | 218 | c = 0; |
223 | on_off = complementaly; | 219 | on_off = complementally; |
224 | for (; *s; s++) { | 220 | for (; *s; s++) { |
225 | if(c >= (sizeof(flags)*8)) | 221 | if(c >= (sizeof(flags)*8)) |
226 | break; | 222 | break; |
@@ -240,9 +236,31 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | |||
240 | c++; | 236 | c++; |
241 | } | 237 | } |
242 | on_off->opt = 0; | 238 | on_off->opt = 0; |
239 | |||
240 | for(l_o = bb_applet_long_options; l_o->name; l_o++) { | ||
241 | for(on_off = complementally; on_off->opt != 0; on_off++) | ||
242 | if(on_off->opt == l_o->val) | ||
243 | break; | ||
244 | if(on_off->opt == 0) { | ||
245 | if(c >= (sizeof(flags)*8)) | ||
246 | break; | ||
247 | on_off->opt = l_o->val; | ||
248 | on_off->switch_on = (1 << c); | ||
249 | on_off->list_flg = 0; | ||
250 | on_off->switch_off = 0; | ||
251 | on_off->incongruously = 0; | ||
252 | if(l_o->has_arg != no_argument) | ||
253 | on_off->optarg = va_arg (p, void **); | ||
254 | else | ||
255 | on_off->optarg = NULL; | ||
256 | on_off++; | ||
257 | on_off->opt = 0; | ||
258 | c++; | ||
259 | } | ||
260 | } | ||
243 | c = 0; | 261 | c = 0; |
244 | for (s = bb_opt_complementaly; s && *s; s++) { | 262 | for (s = bb_opt_complementally; s && *s; s++) { |
245 | t_complementaly *pair; | 263 | t_complementally *pair; |
246 | 264 | ||
247 | if (*s == ':') { | 265 | if (*s == ':') { |
248 | c = 0; | 266 | c = 0; |
@@ -250,7 +268,11 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | |||
250 | } | 268 | } |
251 | if (c) | 269 | if (c) |
252 | continue; | 270 | continue; |
253 | for (on_off = complementaly; on_off->opt; on_off++) | 271 | if(*s == '!') { |
272 | flg_show_usage_if_error = '!'; | ||
273 | continue; | ||
274 | } | ||
275 | for (on_off = complementally; on_off->opt; on_off++) | ||
254 | if (on_off->opt == *s) | 276 | if (on_off->opt == *s) |
255 | break; | 277 | break; |
256 | pair = on_off; | 278 | pair = on_off; |
@@ -263,7 +285,7 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | |||
263 | unsigned long *pair_switch = &(pair->switch_on); | 285 | unsigned long *pair_switch = &(pair->switch_on); |
264 | if(c) | 286 | if(c) |
265 | pair_switch = c == '-' ? &(pair->switch_off) : &(pair->incongruously); | 287 | pair_switch = c == '-' ? &(pair->switch_off) : &(pair->incongruously); |
266 | for (on_off = complementaly; on_off->opt; on_off++) | 288 | for (on_off = complementally; on_off->opt; on_off++) |
267 | if (on_off->opt == *s) { | 289 | if (on_off->opt == *s) { |
268 | *pair_switch |= on_off->switch_on; | 290 | *pair_switch |= on_off->switch_on; |
269 | break; | 291 | break; |
@@ -274,13 +296,16 @@ bb_getopt_ulflags (int argc, char **argv, const char *applet_opts, ...) | |||
274 | } | 296 | } |
275 | 297 | ||
276 | while ((c = getopt_long (argc, argv, applet_opts, | 298 | while ((c = getopt_long (argc, argv, applet_opts, |
277 | bb_applet_long_options, NULL)) > 0) { | 299 | bb_applet_long_options, NULL)) > 0) { |
278 | for (on_off = complementaly; on_off->opt != c; on_off++) { | 300 | for (on_off = complementally; on_off->opt != c; on_off++) { |
279 | if(!on_off->opt) | 301 | if(!on_off->opt) |
280 | bb_show_usage (); | 302 | bb_show_usage (); |
281 | } | 303 | } |
282 | if(flags & on_off->incongruously) | 304 | if(flags & on_off->incongruously) { |
305 | if(flg_show_usage_if_error) | ||
306 | bb_show_usage (); | ||
283 | flags |= BB_GETOPT_ERROR; | 307 | flags |= BB_GETOPT_ERROR; |
308 | } | ||
284 | flags &= ~on_off->switch_off; | 309 | flags &= ~on_off->switch_off; |
285 | flags |= on_off->switch_on; | 310 | flags |= on_off->switch_on; |
286 | if(on_off->list_flg) { | 311 | if(on_off->list_flg) { |