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 
dummy_get_one_option(const struct my_option * opt,const char * argument,const char * filename)63 my_bool dummy_get_one_option(const struct my_option *opt __attribute__((unused)),
64                              const char *argument __attribute__((unused)),
65                              const char *filename __attribute__((unused)))
66 {
67   return FALSE;
68 }
69 
run(const char * arg,...)70 void run(const char *arg, ...)
71 {
72   va_list ap;
73   va_start(ap, arg);
74   arg_v= arg_s;
75   *arg_v++= (char*)"<skipped>";
76   while (arg)
77   {
78     *arg_v++= (char*)arg;
79     arg= va_arg(ap, char*);
80   }
81   va_end(ap);
82   arg_c= (int)(arg_v - arg_s);
83   arg_v= arg_s;
84   res= handle_options(&arg_c, &arg_v, mopts_options, &dummy_get_one_option);
85 }
86 
87 int mopts1_argc= 4;
88 const char *mopts1_argv[]= {"mopts1", "--num=123", "--str=str", "--bool"};
test_mopts1()89 void test_mopts1()
90 {
91   int rc;
92   char **av= (char **)mopts1_argv;
93 
94   rc= handle_options(&mopts1_argc, &av, mopts_options, &dummy_get_one_option);
95   ok( (rc == 0), "%s", "test_mopts1 call");
96   ok( (mopts_num == 122), "%s", "test_mopts1 num");
97   ok( (strncmp(mopts_str, "str", 4) == 0), "%s", "test_mopts1 str");
98   ok( (mopts_bool == 1), "%s", "test_mopts1 bool");
99 }
100 
101 int mopts2_argc= 4;
102 const char *mopts2_argv[]= {"mopts2", "--num=123", "--num=124", "--bool=0"};
test_mopts2()103 void test_mopts2()
104 {
105   int rc;
106   char **av= (char **)mopts2_argv;
107 
108   rc= handle_options(&mopts2_argc, &av, mopts_options, &dummy_get_one_option);
109   ok( (rc == 0), "%s", "test_mopts2 call");
110   ok( (mopts_num == 124), "%s", "test_mopts2 num");
111   ok( (strncmp(mopts_str, "ddd", 4) == 0), "%s", "test_mopts2 str");
112   ok( (mopts_bool == 0), "%s", "test_mopts2 bool");
113 }
114 
115 int mopts3_argc= 4;
116 const char *mopts3_argv[]= {"mopts3", "--loose-foo", "--loose-loose-foo", "--enable-bool"};
test_mopts3()117 void test_mopts3()
118 {
119   int rc;
120   char **av= (char **)mopts3_argv;
121 
122   rc= handle_options(&mopts3_argc, &av, mopts_options, &dummy_get_one_option);
123   ok( (rc == 0), "%s", "test_mopts3 call");
124   ok( (mopts_num == 1000000L), "%s", "test_mopts3 num");
125   ok( (strncmp(mopts_str, "ddd", 4) == 0), "%s", "test_mopts3 str");
126   ok( (mopts_bool == 1), "%s", "test_mopts3 bool");
127 }
128 
129 int mopts4_argc= 3;
130 const char *mopts4_argv[]= {"mopts4", "--loose-str=aa", "--skip-bool"};
test_mopts4()131 void test_mopts4()
132 {
133   int rc;
134   char **av= (char **)mopts4_argv;
135 
136   rc= handle_options(&mopts4_argc, &av, mopts_options, &dummy_get_one_option);
137   ok( (rc == 0), "%s", "test_mopts4 call");
138   ok( (mopts_num == 1000000L), "%s", "test_mopts4 num");
139   ok( (strncmp(mopts_str, "aa", 3) == 0), "%s", "test_mopts4 str");
140   ok( (mopts_bool == 0), "%s", "test_mopts4 bool");
141 }
142 
143 int mopts5_argc= 2;
144 const char *mopts5_argv[]= {"mopts5", "--loose-skip-bool"};
test_mopts5()145 void test_mopts5()
146 {
147   int rc;
148   char **av= (char **)mopts5_argv;
149 
150   rc= handle_options(&mopts5_argc, &av, mopts_options, &dummy_get_one_option);
151   ok( (rc == 0), "%s", "test_mopts5 call");
152   ok( (mopts_num == 1000000L), "%s", "test_mopts5 num");
153   ok( (strncmp(mopts_str, "ddd", 4) == 0), "%s", "test_mopts5 str");
154   ok( (mopts_bool == 0), "%s", "test_mopts5 bool");
155 }
156 
157 int mopts6_argc= 2;
158 const char *mopts6_argv[]= {"mopts6", "--loose-skip-skip-bool"};
test_mopts6()159 void test_mopts6()
160 {
161   int rc;
162   char **av= (char **)mopts6_argv;
163 
164   rc= handle_options(&mopts6_argc, &av, mopts_options, &dummy_get_one_option);
165   ok( (rc == 0), "%s", "test_mopts6 call");
166   ok( (mopts_num == 1000000L), "%s", "test_mopts6 num");
167   ok( (strncmp(mopts_str, "ddd", 4) == 0), "%s", "test_mopts6 str");
168   ok( (mopts_bool == 0), "%s", "test_mopts6 bool");
169 }
170 
171 int mopts7_argc= 2;
172 const char *mopts7_argv[]= {"mopts7", "--loose-disable-skip-bool"};
test_mopts7()173 void test_mopts7()
174 {
175   int rc;
176   char **av= (char **)mopts7_argv;
177 
178   rc= handle_options(&mopts7_argc, &av, mopts_options, &dummy_get_one_option);
179   ok( (rc == 0), "%s", "test_mopts7 call");
180   ok( (mopts_num == 1000000L), "%s", "test_mopts7 num");
181   ok( (strncmp(mopts_str, "ddd", 4) == 0), "%s", "test_mopts7 str");
182   ok( (mopts_bool == 0), "%s", "test_mopts7 bool");
183 }
184 
185 int mopts8_argc= 2;
186 const char *mopts8_argv[]= {"mopts8", "--loose-disable-enable-bool"};
test_mopts8()187 void test_mopts8()
188 {
189   int rc;
190   char **av= (char **)mopts8_argv;
191 
192   rc= handle_options(&mopts8_argc, &av, mopts_options, &dummy_get_one_option);
193   ok( (rc == 0), "%s", "test_mopts8 call");
194   ok( (mopts_num == 1000000L), "%s", "test_mopts7 num");
195   ok( (strncmp(mopts_str, "ddd", 4) == 0), "%s", "test_mopts7 str");
196   ok( (mopts_bool == 1), "%s", "test_mopts7 bool");
197 }
198 
199 int mopts9_argc= 2;
200 const char *mopts9_argv[]= {"mopts9", "--foo"};
test_mopts9()201 void test_mopts9()
202 {
203   int rc;
204   char **av= (char **)mopts9_argv;
205 
206   rc= handle_options(&mopts9_argc, &av, mopts_options, &dummy_get_one_option);
207   ok( (rc != 0), "%s", "test_mopts9 call");
208 }
209 
210 int mopts10_argc= 2;
211 const char *mopts10_argv[]= {"mopts10", "--skip-foo"};
test_mopts10()212 void test_mopts10()
213 {
214   int rc;
215   char **av= (char **)mopts10_argv;
216 
217   rc= handle_options(&mopts10_argc, &av, mopts_options, &dummy_get_one_option);
218   ok( (rc != 0), "%s", "test_mopts10 call");
219 }
220 
221 ulong auto_num;
222 static struct my_option auto_options[]=
223 {
224   {"anum", 0,
225    "Something numeric.",
226    &auto_num, &auto_num, 0, GET_ULONG | GET_AUTO,
227    REQUIRED_ARG, 1000000L, 1, ULONG_MAX, 0, 1, 0},
228   {"num", 0,
229    "Something numeric.",
230    &mopts_num, &mopts_num, 0, GET_ULONG,
231    REQUIRED_ARG, 1000000L, 1, ULONG_MAX, 0, 1, 0},
232   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
233 };
234 
235 
236 
auto_get_one_option(const struct my_option * opt,const char * argument,const char * filename)237 my_bool auto_get_one_option(const struct my_option *opt,
238                             const char *argument,
239                             const char *filename __attribute__((unused)))
240 {
241   if (argument == autoset_my_option)
242   {
243     *((ulong*)opt->value)= 111;
244   }
245   return FALSE;
246 }
247 
248 int auto2_argc= 3;
249 const char *auto2_argv[]= {"auto2", "--num=123", "--autoset-num"};
test_auto2()250 void test_auto2()
251 {
252   int rc;
253   char **av= (char **)auto2_argv;
254 
255   rc= handle_options(&auto2_argc, &av, auto_options, &auto_get_one_option);
256   ok( (rc == EXIT_ARGUMENT_INVALID), "%s", "test_auto2 call");
257 }
258 
259 int auto3_argc= 3;
260 const char *auto3_argv[]= {"auto3", "--anum=123", "--autoset-anum"};
test_auto3()261 void test_auto3()
262 {
263   int rc;
264   char **av= (char **)auto3_argv;
265 
266   rc= handle_options(&auto3_argc, &av, auto_options, &auto_get_one_option);
267   ok( (rc == 0), "%s", "test_auto3 call");
268   ok( (mopts_num == 1000000L), "%s", "test_auto3 num");
269   ok( (auto_num == 111), "%s", "test_auto3 anum");
270 }
271 
272 int auto4_argc= 3;
273 const char *auto4_argv[]= {"auto4", "--loose-autoset-num", "--loose-autoset-anum"};
test_auto4()274 void test_auto4()
275 {
276   int rc;
277   char **av= (char **)auto4_argv;
278 
279   rc= handle_options(&auto4_argc, &av, auto_options, &auto_get_one_option);
280   ok( (rc == 0), "%s", "test_auto4 call");
281   ok( (mopts_num == 1000000L), "%s", "test_auto4 num");
282   ok( (auto_num == 111), "%s", "test_auto4 anum");
283 }
284 
285 int auto5_argc= 3;
286 const char *auto5_argv[]= {"auto5", "--autoset-loose-num", "--autoset-loose-anum"};
test_auto5()287 void test_auto5()
288 {
289   int rc;
290   char **av= (char **)auto5_argv;
291 
292   rc= handle_options(&auto5_argc, &av, auto_options, &auto_get_one_option);
293   ok( (rc == 0), "%s", "test_auto5 call");
294   ok( (mopts_num == 1000000L), "%s", "test_auto5 num");
295   ok( (auto_num == 111), "%s", "test_auto5 anum");
296 }
297 
298 int auto6_argc= 3;
299 const char *auto6_argv[]= {"auto6", "--autoset-anum", "--anum=123"};
test_auto6()300 void test_auto6()
301 {
302   int rc;
303   char **av= (char **)auto6_argv;
304 
305   rc= handle_options(&auto6_argc, &av, auto_options, &auto_get_one_option);
306   ok( (rc == 0), "%s", "test_auto6 call");
307   ok( (mopts_num == 1000000L), "%s", "test_auto6 num");
308   ok( (auto_num == 123), "%s", "test_auto6 anum");
309 }
310 
311 
312 ulong max_num= ULONG_MAX;
313 static struct my_option max_options[]=
314 {
315   {"num", 0,
316    "Something numeric.",
317    &mopts_num, &max_num, 0, GET_ULONG,
318    REQUIRED_ARG, 1000000L, 1, 1000001L, 0, 1, 0},
319   { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
320 };
321 
322 int max1_argc= 3;
323 const char *max1_argv[]= {"max1", "--num=100", "--num=200"};
test_max1()324 void test_max1()
325 {
326   int rc;
327   char **av= (char **)max1_argv;
328 
329   rc= handle_options(&max1_argc, &av, max_options, &dummy_get_one_option);
330   ok( (rc == 0), "%s", "test_max1 call");
331   ok( (mopts_num == 200), "%s", "test_max1 num");
332   ok( (max_num == 1000001L), "%s", "test_max1 max_num");
333 }
334 int max2_argc= 3;
335 const char *max2_argv[]= {"max2", "--maximum-num=100", "--num=200"};
test_max2()336 void test_max2()
337 {
338   int rc;
339   char **av= (char **)max2_argv;
340 
341   rc= handle_options(&max2_argc, &av, max_options, &dummy_get_one_option);
342   ok( (rc == 0), "%s", "test_max2 call");
343   ok( (mopts_num == 200), "%s", "test_max2 num");
344   ok( (max_num == 100), "%s", "test_max2 max_num");
345 }
346 
main(int argc,char ** argv)347 int main(int argc __attribute__((unused)), char **argv)
348 {
349   MY_INIT(argv[0]);
350   plan(4*8 + 1*4 + 3*4 + 3*2 + 2);
351 
352   /* gcc 4.1.2 doesn't want it in the initializer, we have to do it run-time */
353   mopts_options[0].def_value= (intptr)"ddd";
354 
355   test_mopts1();
356   test_mopts2();
357   test_mopts3();
358   test_mopts4();
359   test_mopts5();
360   test_mopts6();
361   test_mopts7();
362   test_mopts8();
363 
364   test_mopts9();
365   test_mopts10();
366   test_auto2();
367 
368   test_auto3();
369   test_auto4();
370   test_auto5();
371   test_auto6();
372 
373   test_max1();
374   test_max2();
375 
376   run("--ull=100", NULL);
377   ok(res==0 && arg_c==0 && opt_ull==100,
378      "res:%d, argc:%d, opt_ull:%llu", res, arg_c, opt_ull);
379 
380   /*
381     negative numbers are wrapped. this is kinda questionable,
382     we might want to fix it eventually. but it'd be a change in behavior,
383     users might've got used to "-1" meaning "max possible value"
384   */
385   run("--ull=-100", NULL);
386   ok(res==0 && arg_c==0 && opt_ull==18446744073709551516ULL,
387      "res:%d, argc:%d, opt_ull:%llu", res, arg_c, opt_ull);
388   run("--ul=-100", NULL);
389   ok(res==0 && arg_c==0 && opt_ul==4294967295UL,
390      "res:%d, argc:%d, opt_ul:%lu", res, arg_c, opt_ul);
391 
392   my_end(0);
393   return exit_status();
394 }
395