1 | /* Copyright (c) 2015, MariaDB Corporation |
2 | |
3 | Redistribution and use in source and binary forms, with or without |
4 | modification, are permitted provided that the following conditions are |
5 | met: |
6 | |
7 | 1. Redistributions of source code must retain the above copyright |
8 | notice, this list of conditions and the following disclaimer. |
9 | |
10 | 2. Redistributions in binary form must the following disclaimer in |
11 | the documentation and/or other materials provided with the |
12 | distribution. |
13 | |
14 | THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND ANY |
15 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
16 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
17 | PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> OR |
18 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
19 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
20 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
21 | USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
22 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
24 | OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
25 | SUCH DAMAGE. |
26 | */ |
27 | |
28 | #include <my_global.h> |
29 | #include <my_getopt.h> |
30 | #include <mysys_err.h> |
31 | #include <stdarg.h> |
32 | #include <tap.h> |
33 | |
34 | ulonglong opt_ull; |
35 | ulong opt_ul; |
36 | int arg_c, res; |
37 | char **arg_v, *arg_s[100]; |
38 | |
39 | ulong mopts_num; |
40 | char *mopts_str; |
41 | my_bool mopts_bool; |
42 | static struct my_option mopts_options[]= |
43 | { |
44 | {"str" , 0, |
45 | "Something numeric." , |
46 | &mopts_str, &mopts_str, 0, GET_STR, |
47 | REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, |
48 | {"bool" , 0, |
49 | "Something true or false" , |
50 | &mopts_bool, &mopts_bool, 0, GET_BOOL, |
51 | OPT_ARG, FALSE, 0, 0, 0, 0, 0}, |
52 | {"num" , 0, |
53 | "Something numeric." , |
54 | &mopts_num, &mopts_num, 0, GET_ULONG, |
55 | REQUIRED_ARG, 1000000L, 1, ULONG_MAX, 0, 2, 0}, |
56 | {"ull" , 0, "ull" , &opt_ull, &opt_ull, |
57 | 0, GET_ULL, REQUIRED_ARG, 1, 0, ~0ULL, 0, 0, 0}, |
58 | {"ul" , 0, "ul" , &opt_ul, &opt_ul, |
59 | 0, GET_ULONG, REQUIRED_ARG, 1, 0, 0xFFFFFFFF, 0, 0, 0}, |
60 | { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} |
61 | }; |
62 | |
63 | void run(const char *arg, ...) |
64 | { |
65 | va_list ap; |
66 | va_start(ap, arg); |
67 | arg_v= arg_s; |
68 | *arg_v++= (char*)"<skipped>" ; |
69 | while (arg) |
70 | { |
71 | *arg_v++= (char*)arg; |
72 | arg= va_arg(ap, char*); |
73 | } |
74 | va_end(ap); |
75 | arg_c= (int)(arg_v - arg_s); |
76 | arg_v= arg_s; |
77 | res= handle_options(&arg_c, &arg_v, mopts_options, 0); |
78 | } |
79 | |
80 | int mopts1_argc= 4; |
81 | const char *mopts1_argv[]= {"mopts1" , "--num=123" , "--str=str" , "--bool" }; |
82 | void test_mopts1() |
83 | { |
84 | int rc; |
85 | char **av= (char **)mopts1_argv; |
86 | |
87 | rc= handle_options(&mopts1_argc, &av, mopts_options, NULL); |
88 | ok( (rc == 0), "%s" , "test_mopts1 call" ); |
89 | ok( (mopts_num == 122), "%s" , "test_mopts1 num" ); |
90 | ok( (strncmp(mopts_str, "str" , 4) == 0), "%s" , "test_mopts1 str" ); |
91 | ok( (mopts_bool == 1), "%s" , "test_mopts1 bool" ); |
92 | } |
93 | |
94 | int mopts2_argc= 4; |
95 | const char *mopts2_argv[]= {"mopts2" , "--num=123" , "--num=124" , "--bool=0" }; |
96 | void test_mopts2() |
97 | { |
98 | int rc; |
99 | char **av= (char **)mopts2_argv; |
100 | |
101 | rc= handle_options(&mopts2_argc, &av, mopts_options, NULL); |
102 | ok( (rc == 0), "%s" , "test_mopts2 call" ); |
103 | ok( (mopts_num == 124), "%s" , "test_mopts2 num" ); |
104 | ok( (strncmp(mopts_str, "ddd" , 4) == 0), "%s" , "test_mopts2 str" ); |
105 | ok( (mopts_bool == 0), "%s" , "test_mopts2 bool" ); |
106 | } |
107 | |
108 | int mopts3_argc= 4; |
109 | const char *mopts3_argv[]= {"mopts3" , "--loose-foo" , "--loose-loose-foo" , "--enable-bool" }; |
110 | void test_mopts3() |
111 | { |
112 | int rc; |
113 | char **av= (char **)mopts3_argv; |
114 | |
115 | rc= handle_options(&mopts3_argc, &av, mopts_options, NULL); |
116 | ok( (rc == 0), "%s" , "test_mopts3 call" ); |
117 | ok( (mopts_num == 1000000L), "%s" , "test_mopts3 num" ); |
118 | ok( (strncmp(mopts_str, "ddd" , 4) == 0), "%s" , "test_mopts3 str" ); |
119 | ok( (mopts_bool == 1), "%s" , "test_mopts3 bool" ); |
120 | } |
121 | |
122 | int mopts4_argc= 3; |
123 | const char *mopts4_argv[]= {"mopts4" , "--loose-str=aa" , "--skip-bool" }; |
124 | void test_mopts4() |
125 | { |
126 | int rc; |
127 | char **av= (char **)mopts4_argv; |
128 | |
129 | rc= handle_options(&mopts4_argc, &av, mopts_options, NULL); |
130 | ok( (rc == 0), "%s" , "test_mopts4 call" ); |
131 | ok( (mopts_num == 1000000L), "%s" , "test_mopts4 num" ); |
132 | ok( (strncmp(mopts_str, "aa" , 3) == 0), "%s" , "test_mopts4 str" ); |
133 | ok( (mopts_bool == 0), "%s" , "test_mopts4 bool" ); |
134 | } |
135 | |
136 | int mopts5_argc= 2; |
137 | const char *mopts5_argv[]= {"mopts5" , "--loose-skip-bool" }; |
138 | void test_mopts5() |
139 | { |
140 | int rc; |
141 | char **av= (char **)mopts5_argv; |
142 | |
143 | rc= handle_options(&mopts5_argc, &av, mopts_options, NULL); |
144 | ok( (rc == 0), "%s" , "test_mopts5 call" ); |
145 | ok( (mopts_num == 1000000L), "%s" , "test_mopts5 num" ); |
146 | ok( (strncmp(mopts_str, "ddd" , 4) == 0), "%s" , "test_mopts5 str" ); |
147 | ok( (mopts_bool == 0), "%s" , "test_mopts5 bool" ); |
148 | } |
149 | |
150 | int mopts6_argc= 2; |
151 | const char *mopts6_argv[]= {"mopts6" , "--loose-skip-skip-bool" }; |
152 | void test_mopts6() |
153 | { |
154 | int rc; |
155 | char **av= (char **)mopts6_argv; |
156 | |
157 | rc= handle_options(&mopts6_argc, &av, mopts_options, NULL); |
158 | ok( (rc == 0), "%s" , "test_mopts6 call" ); |
159 | ok( (mopts_num == 1000000L), "%s" , "test_mopts6 num" ); |
160 | ok( (strncmp(mopts_str, "ddd" , 4) == 0), "%s" , "test_mopts6 str" ); |
161 | ok( (mopts_bool == 0), "%s" , "test_mopts6 bool" ); |
162 | } |
163 | |
164 | int mopts7_argc= 2; |
165 | const char *mopts7_argv[]= {"mopts7" , "--loose-disable-skip-bool" }; |
166 | void test_mopts7() |
167 | { |
168 | int rc; |
169 | char **av= (char **)mopts7_argv; |
170 | |
171 | rc= handle_options(&mopts7_argc, &av, mopts_options, NULL); |
172 | ok( (rc == 0), "%s" , "test_mopts7 call" ); |
173 | ok( (mopts_num == 1000000L), "%s" , "test_mopts7 num" ); |
174 | ok( (strncmp(mopts_str, "ddd" , 4) == 0), "%s" , "test_mopts7 str" ); |
175 | ok( (mopts_bool == 0), "%s" , "test_mopts7 bool" ); |
176 | } |
177 | |
178 | int mopts8_argc= 2; |
179 | const char *mopts8_argv[]= {"mopts8" , "--loose-disable-enable-bool" }; |
180 | void test_mopts8() |
181 | { |
182 | int rc; |
183 | char **av= (char **)mopts8_argv; |
184 | |
185 | rc= handle_options(&mopts8_argc, &av, mopts_options, NULL); |
186 | ok( (rc == 0), "%s" , "test_mopts8 call" ); |
187 | ok( (mopts_num == 1000000L), "%s" , "test_mopts7 num" ); |
188 | ok( (strncmp(mopts_str, "ddd" , 4) == 0), "%s" , "test_mopts7 str" ); |
189 | ok( (mopts_bool == 1), "%s" , "test_mopts7 bool" ); |
190 | } |
191 | |
192 | int mopts9_argc= 2; |
193 | const char *mopts9_argv[]= {"mopts9" , "--foo" }; |
194 | void test_mopts9() |
195 | { |
196 | int rc; |
197 | char **av= (char **)mopts9_argv; |
198 | |
199 | rc= handle_options(&mopts9_argc, &av, mopts_options, NULL); |
200 | ok( (rc != 0), "%s" , "test_mopts9 call" ); |
201 | } |
202 | |
203 | int mopts10_argc= 2; |
204 | const char *mopts10_argv[]= {"mopts10" , "--skip-foo" }; |
205 | void test_mopts10() |
206 | { |
207 | int rc; |
208 | char **av= (char **)mopts10_argv; |
209 | |
210 | rc= handle_options(&mopts10_argc, &av, mopts_options, NULL); |
211 | ok( (rc != 0), "%s" , "test_mopts10 call" ); |
212 | } |
213 | |
214 | ulong auto_num; |
215 | static struct my_option auto_options[]= |
216 | { |
217 | {"anum" , 0, |
218 | "Something numeric." , |
219 | &auto_num, &auto_num, 0, GET_ULONG | GET_AUTO, |
220 | REQUIRED_ARG, 1000000L, 1, ULONG_MAX, 0, 1, 0}, |
221 | {"num" , 0, |
222 | "Something numeric." , |
223 | &mopts_num, &mopts_num, 0, GET_ULONG, |
224 | REQUIRED_ARG, 1000000L, 1, ULONG_MAX, 0, 1, 0}, |
225 | { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} |
226 | }; |
227 | |
228 | |
229 | |
230 | my_bool auto_get_one_option(int optid __attribute__((unused)), |
231 | const struct my_option *opt, |
232 | char *argument) |
233 | { |
234 | if (argument == autoset_my_option) |
235 | { |
236 | *((ulong*)opt->value)= 111; |
237 | } |
238 | return FALSE; |
239 | } |
240 | |
241 | int auto1_argc= 3; |
242 | const char *auto1_argv[]= {"auto1" , "--anum=123" , "--autoset-anum" }; |
243 | void test_auto1() |
244 | { |
245 | int rc; |
246 | char **av= (char **)auto1_argv; |
247 | |
248 | rc= handle_options(&auto1_argc, &av, auto_options, NULL); |
249 | ok( (rc == EXIT_ARGUMENT_INVALID), "%s" , "test_auto1 call" ); |
250 | } |
251 | |
252 | int auto2_argc= 3; |
253 | const char *auto2_argv[]= {"auto2" , "--num=123" , "--autoset-num" }; |
254 | void test_auto2() |
255 | { |
256 | int rc; |
257 | char **av= (char **)auto2_argv; |
258 | |
259 | rc= handle_options(&auto2_argc, &av, auto_options, &auto_get_one_option); |
260 | ok( (rc == EXIT_ARGUMENT_INVALID), "%s" , "test_auto2 call" ); |
261 | } |
262 | |
263 | int auto3_argc= 3; |
264 | const char *auto3_argv[]= {"auto3" , "--anum=123" , "--autoset-anum" }; |
265 | void test_auto3() |
266 | { |
267 | int rc; |
268 | char **av= (char **)auto3_argv; |
269 | |
270 | rc= handle_options(&auto3_argc, &av, auto_options, &auto_get_one_option); |
271 | ok( (rc == 0), "%s" , "test_auto3 call" ); |
272 | ok( (mopts_num == 1000000L), "%s" , "test_auto3 num" ); |
273 | ok( (auto_num == 111), "%s" , "test_auto3 anum" ); |
274 | } |
275 | |
276 | int auto4_argc= 3; |
277 | const char *auto4_argv[]= {"auto4" , "--loose-autoset-num" , "--loose-autoset-anum" }; |
278 | void test_auto4() |
279 | { |
280 | int rc; |
281 | char **av= (char **)auto4_argv; |
282 | |
283 | rc= handle_options(&auto4_argc, &av, auto_options, &auto_get_one_option); |
284 | ok( (rc == 0), "%s" , "test_auto4 call" ); |
285 | ok( (mopts_num == 1000000L), "%s" , "test_auto4 num" ); |
286 | ok( (auto_num == 111), "%s" , "test_auto4 anum" ); |
287 | } |
288 | |
289 | int auto5_argc= 3; |
290 | const char *auto5_argv[]= {"auto5" , "--autoset-loose-num" , "--autoset-loose-anum" }; |
291 | void test_auto5() |
292 | { |
293 | int rc; |
294 | char **av= (char **)auto5_argv; |
295 | |
296 | rc= handle_options(&auto5_argc, &av, auto_options, &auto_get_one_option); |
297 | ok( (rc == 0), "%s" , "test_auto5 call" ); |
298 | ok( (mopts_num == 1000000L), "%s" , "test_auto5 num" ); |
299 | ok( (auto_num == 111), "%s" , "test_auto5 anum" ); |
300 | } |
301 | |
302 | int auto6_argc= 3; |
303 | const char *auto6_argv[]= {"auto6" , "--autoset-anum" , "--anum=123" }; |
304 | void test_auto6() |
305 | { |
306 | int rc; |
307 | char **av= (char **)auto6_argv; |
308 | |
309 | rc= handle_options(&auto6_argc, &av, auto_options, &auto_get_one_option); |
310 | ok( (rc == 0), "%s" , "test_auto6 call" ); |
311 | ok( (mopts_num == 1000000L), "%s" , "test_auto6 num" ); |
312 | ok( (auto_num == 123), "%s" , "test_auto6 anum" ); |
313 | } |
314 | |
315 | |
316 | ulong max_num= ULONG_MAX; |
317 | static struct my_option max_options[]= |
318 | { |
319 | {"num" , 0, |
320 | "Something numeric." , |
321 | &mopts_num, &max_num, 0, GET_ULONG, |
322 | REQUIRED_ARG, 1000000L, 1, 1000001L, 0, 1, 0}, |
323 | { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} |
324 | }; |
325 | |
326 | int max1_argc= 3; |
327 | const char *max1_argv[]= {"max1" , "--num=100" , "--num=200" }; |
328 | void test_max1() |
329 | { |
330 | int rc; |
331 | char **av= (char **)max1_argv; |
332 | |
333 | rc= handle_options(&max1_argc, &av, max_options, NULL); |
334 | ok( (rc == 0), "%s" , "test_max1 call" ); |
335 | ok( (mopts_num == 200), "%s" , "test_max1 num" ); |
336 | ok( (max_num == 1000001L), "%s" , "test_max1 max_num" ); |
337 | } |
338 | int max2_argc= 3; |
339 | const char *max2_argv[]= {"max2" , "--maximum-num=100" , "--num=200" }; |
340 | void test_max2() |
341 | { |
342 | int rc; |
343 | char **av= (char **)max2_argv; |
344 | |
345 | rc= handle_options(&max2_argc, &av, max_options, NULL); |
346 | ok( (rc == 0), "%s" , "test_max2 call" ); |
347 | ok( (mopts_num == 200), "%s" , "test_max2 num" ); |
348 | ok( (max_num == 100), "%s" , "test_max2 max_num" ); |
349 | } |
350 | |
351 | int main(int argc __attribute__((unused)), char **argv) |
352 | { |
353 | MY_INIT(argv[0]); |
354 | plan(4*8 + 1*4 + 3*4 + 3*2 + 3); |
355 | |
356 | /* gcc 4.1.2 doesn't want it in the initializer, we have to do it run-time */ |
357 | mopts_options[0].def_value= (intptr)"ddd" ; |
358 | |
359 | test_mopts1(); |
360 | test_mopts2(); |
361 | test_mopts3(); |
362 | test_mopts4(); |
363 | test_mopts5(); |
364 | test_mopts6(); |
365 | test_mopts7(); |
366 | test_mopts8(); |
367 | |
368 | test_mopts9(); |
369 | test_mopts10(); |
370 | test_auto1(); |
371 | test_auto2(); |
372 | |
373 | test_auto3(); |
374 | test_auto4(); |
375 | test_auto5(); |
376 | test_auto6(); |
377 | |
378 | test_max1(); |
379 | test_max2(); |
380 | |
381 | run("--ull=100" , NULL); |
382 | ok(res==0 && arg_c==0 && opt_ull==100, |
383 | "res:%d, argc:%d, opt_ull:%llu" , res, arg_c, opt_ull); |
384 | |
385 | /* |
386 | negative numbers are wrapped. this is kinda questionable, |
387 | we might want to fix it eventually. but it'd be a change in behavior, |
388 | users might've got used to "-1" meaning "max possible value" |
389 | */ |
390 | run("--ull=-100" , NULL); |
391 | ok(res==0 && arg_c==0 && opt_ull==18446744073709551516ULL, |
392 | "res:%d, argc:%d, opt_ull:%llu" , res, arg_c, opt_ull); |
393 | run("--ul=-100" , NULL); |
394 | ok(res==0 && arg_c==0 && opt_ul==4294967295UL, |
395 | "res:%d, argc:%d, opt_ul:%lu" , res, arg_c, opt_ul); |
396 | |
397 | my_end(0); |
398 | return exit_status(); |
399 | } |
400 | |