1/*
2 Copyright (c) 2002, 2013, Oracle and/or its affiliates
3 Copyright (c) 2009, 2015, MariaDB
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */
17
18#include <my_global.h>
19#include <my_default.h>
20#include <m_string.h>
21#include <stdlib.h>
22#include <my_sys.h>
23#include <mysys_err.h>
24#include <my_getopt.h>
25#include <errno.h>
26
27typedef void (*init_func_p)(const struct my_option *option, void *variable,
28 longlong value);
29
30static void default_reporter(enum loglevel level, const char *format, ...);
31my_error_reporter my_getopt_error_reporter= &default_reporter;
32
33static int findopt(char *, uint, const struct my_option **, const char **);
34my_bool getopt_compare_strings(const char *, const char *, uint);
35static longlong getopt_ll(char *arg, const struct my_option *optp, int *err);
36static ulonglong getopt_ull(char *, const struct my_option *, int *);
37static double getopt_double(char *arg, const struct my_option *optp, int *err);
38static void init_variables(const struct my_option *, init_func_p);
39static void init_one_value(const struct my_option *, void *, longlong);
40static void fini_one_value(const struct my_option *, void *, longlong);
41static int setval(const struct my_option *, void *, char *, my_bool);
42static char *check_struct_option(char *cur_arg, char *key_name);
43
44/*
45 The following three variables belong to same group and the number and
46 order of their arguments must correspond to each other.
47*/
48static const char *special_opt_prefix[]=
49{"skip", "disable", "enable", "maximum", "loose", "autoset", 0};
50static const uint special_opt_prefix_lengths[]=
51{ 4, 7, 6, 7, 5, 7, 0};
52enum enum_special_opt
53{ OPT_SKIP, OPT_DISABLE, OPT_ENABLE, OPT_MAXIMUM, OPT_LOOSE, OPT_AUTOSET};
54
55char *disabled_my_option= (char*) "0";
56char *enabled_my_option= (char*) "1";
57char *autoset_my_option= (char*) "auto";
58
59/*
60 This is a flag that can be set in client programs. 0 means that
61 my_getopt will not print error messages, but the client should do
62 it by itself
63*/
64
65my_bool my_getopt_print_errors= 1;
66
67/*
68 This is a flag that can be set in client programs. 1 means that
69 my_getopt will skip over options it does not know how to handle.
70*/
71
72my_bool my_getopt_skip_unknown= 0;
73
74
75/*
76 This is a flag that can be set in client programs. 1 means that
77 my_getopt will reconize command line options by their unambiguous
78 prefixes. 0 means an option must be always specified in full.
79*/
80my_bool my_getopt_prefix_matching= 1;
81
82static void default_reporter(enum loglevel level,
83 const char *format, ...)
84{
85 va_list args;
86 DBUG_ENTER("default_reporter");
87
88 va_start(args, format);
89 if (level == WARNING_LEVEL)
90 fprintf(stderr, "%s", "Warning: ");
91 else if (level == INFORMATION_LEVEL)
92 fprintf(stderr, "%s", "Info: ");
93 vfprintf(stderr, format, args);
94 va_end(args);
95 fputc('\n', stderr);
96 fflush(stderr);
97 DBUG_VOID_RETURN;
98}
99
100static my_getopt_value getopt_get_addr;
101
102void my_getopt_register_get_addr(my_getopt_value func_addr)
103{
104 getopt_get_addr= func_addr;
105}
106
107union ull_dbl
108{
109 ulonglong ull;
110 double dbl;
111};
112
113/**
114 Returns an ulonglong value containing a raw
115 representation of the given double value.
116*/
117ulonglong getopt_double2ulonglong(double v)
118{
119 union ull_dbl u;
120 u.dbl= v;
121 compile_time_assert(sizeof(ulonglong) >= sizeof(double));
122 return u.ull;
123}
124
125/**
126 Returns the double value which corresponds to
127 the given raw representation.
128*/
129double getopt_ulonglong2double(ulonglong v)
130{
131 union ull_dbl u;
132 u.ull= v;
133 return u.dbl;
134}
135
136/**
137 Handle command line options.
138 Sort options.
139 Put options first, until special end of options (--),
140 or until the end of argv. Parse options, check that the given option
141 matches with one of the options in struct 'my_option'.
142 Check that option was given an argument if it requires one
143 Call the optional 'get_one_option()' function once for each option.
144
145 Note that handle_options() can be invoked multiple times to
146 parse a command line in several steps.
147 In this case, use the global flag @c my_getopt_skip_unknown to indicate
148 that options unknown in the current step should be preserved in the
149 command line for later parsing in subsequent steps.
150
151 For 'long' options (--a_long_option), @c my_getopt_skip_unknown is
152 fully supported. Command line parameters such as:
153 - "--a_long_option"
154 - "--a_long_option=value"
155 - "--a_long_option value"
156 will be preserved as is when the option is not known.
157
158 For 'short' options (-S), support for @c my_getopt_skip_unknown
159 comes with some limitation, because several short options
160 can also be specified together in the same command line argument,
161 as in "-XYZ".
162
163 The first use case supported is: all short options are declared.
164 handle_options() will be able to interpret "-XYZ" as one of:
165 - an unknown X option
166 - "-X -Y -Z", three short options with no arguments
167 - "-X -YZ", where Y is a short option with argument Z
168 - "-XYZ", where X is a short option with argument YZ
169 based on the full short options specifications.
170
171 The second use case supported is: no short option is declared.
172 handle_options() will reject "-XYZ" as unknown, to be parsed later.
173
174 The use case that is explicitly not supported is to provide
175 only a partial list of short options to handle_options().
176 This function can not be expected to extract some option Y
177 in the middle of the string "-XYZ" in these conditions,
178 without knowing if X will be declared an option later.
179
180 Note that this limitation only impacts parsing of several
181 short options from the same command line argument,
182 as in "mysqld -anW5".
183 When each short option is properly separated out in the command line
184 argument, for example in "mysqld -a -n -w5", the code would actually
185 work even with partial options specs given at each stage.
186
187 @param [in, out] argc command line options (count)
188 @param [in, out] argv command line options (values)
189 @param [in] longopts descriptor of all valid options
190 @param [in] get_one_option optional callback function to process each option,
191 can be NULL.
192 @return error in case of ambiguous or unknown options,
193 0 on success.
194*/
195int handle_options(int *argc, char ***argv,
196 const struct my_option *longopts,
197 my_get_one_option get_one_option)
198{
199 uint UNINIT_VAR(opt_found), argvpos= 0, length;
200 my_bool end_of_options= 0, must_be_var, set_maximum_value,
201 option_is_loose, option_is_autoset;
202 char **pos, **pos_end, *optend, *opt_str, key_name[FN_REFLEN];
203 const char *UNINIT_VAR(prev_found);
204 const struct my_option *optp;
205 void *value;
206 int error, i;
207 my_bool is_cmdline_arg= 1;
208 DBUG_ENTER("handle_options");
209
210 /* handle_options() assumes arg0 (program name) always exists */
211 DBUG_ASSERT(argc && *argc >= 1);
212 DBUG_ASSERT(argv && *argv);
213 (*argc)--; /* Skip the program name */
214 (*argv)++; /* --- || ---- */
215 init_variables(longopts, init_one_value);
216
217 /*
218 Search for args_separator, if found, then the first part of the
219 arguments are loaded from configs
220 */
221 for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++)
222 {
223 if (my_getopt_is_args_separator(*pos))
224 {
225 is_cmdline_arg= 0;
226 break;
227 }
228 }
229
230 for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++)
231 {
232 char **first= pos;
233 char *cur_arg= *pos;
234 opt_found= 0;
235 if (!is_cmdline_arg && (my_getopt_is_args_separator(cur_arg)))
236 {
237 is_cmdline_arg= 1;
238
239 /* save the separator too if skip unknown options */
240 if (my_getopt_skip_unknown)
241 (*argv)[argvpos++]= cur_arg;
242 else
243 (*argc)--;
244 continue;
245 }
246 if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */
247 {
248 char *argument= 0;
249 must_be_var= 0;
250 set_maximum_value= 0;
251 option_is_loose= 0;
252 option_is_autoset= 0;
253
254 cur_arg++; /* skip '-' */
255 if (*cur_arg == '-') /* check for long option, */
256 {
257 if (!*++cur_arg) /* skip the double dash */
258 {
259 /* '--' means end of options, look no further */
260 end_of_options= 1;
261 (*argc)--;
262 continue;
263 }
264 opt_str= check_struct_option(cur_arg, key_name);
265 optend= strcend(opt_str, '=');
266 length= (uint) (optend - opt_str);
267 if (*optend == '=')
268 optend++;
269 else
270 optend= 0;
271
272 /*
273 Find first the right option. Return error in case of an ambiguous,
274 or unknown option
275 */
276 optp= longopts;
277 if (!(opt_found= findopt(opt_str, length, &optp, &prev_found)))
278 {
279 /*
280 Didn't find any matching option. Let's see if someone called
281 option with a special option prefix
282 */
283 if (!must_be_var)
284 {
285 if (optend)
286 must_be_var= 1; /* option is followed by an argument */
287 for (i= 0; special_opt_prefix[i]; i++)
288 {
289 if (!getopt_compare_strings(special_opt_prefix[i], opt_str,
290 special_opt_prefix_lengths[i]) &&
291 (opt_str[special_opt_prefix_lengths[i]] == '-' ||
292 opt_str[special_opt_prefix_lengths[i]] == '_'))
293 {
294 /*
295 We were called with a special prefix, we can reuse opt_found
296 */
297 opt_str+= special_opt_prefix_lengths[i] + 1;
298 length-= special_opt_prefix_lengths[i] + 1;
299 if (i == OPT_LOOSE)
300 option_is_loose= 1;
301 else if (i == OPT_AUTOSET)
302 option_is_autoset= 1;
303 if ((opt_found= findopt(opt_str, length, &optp, &prev_found)))
304 {
305 if (opt_found > 1)
306 {
307 if (my_getopt_print_errors)
308 my_getopt_error_reporter(ERROR_LEVEL,
309 "%s: ambiguous option '--%s-%s' (--%s-%s)",
310 my_progname, special_opt_prefix[i],
311 opt_str, special_opt_prefix[i],
312 prev_found);
313 DBUG_RETURN(EXIT_AMBIGUOUS_OPTION);
314 }
315 switch (i) {
316 case OPT_SKIP:
317 case OPT_DISABLE: /* fall through */
318 /*
319 double negation is actually enable again,
320 for example: --skip-option=0 -> option = TRUE
321 */
322 optend= (optend && *optend == '0' && !(*(optend + 1))) ?
323 enabled_my_option : disabled_my_option;
324 break;
325 case OPT_ENABLE:
326 optend= (optend && *optend == '0' && !(*(optend + 1))) ?
327 disabled_my_option : enabled_my_option;
328 break;
329 case OPT_MAXIMUM:
330 set_maximum_value= 1;
331 must_be_var= 1;
332 break;
333 }
334 break; /* break from the inner loop, main loop continues */
335 }
336 i= -1; /* restart the loop */
337 }
338 }
339 }
340 if (!opt_found)
341 {
342 if (my_getopt_skip_unknown)
343 {
344 /* Preserve all the components of this unknown option. */
345 do {
346 (*argv)[argvpos++]= *first++;
347 } while (first <= pos);
348 continue;
349 }
350 if (must_be_var)
351 {
352 if (my_getopt_print_errors)
353 my_getopt_error_reporter(option_is_loose ?
354 WARNING_LEVEL : ERROR_LEVEL,
355 "%s: unknown variable '%s'",
356 my_progname, cur_arg);
357 if (!option_is_loose)
358 DBUG_RETURN(EXIT_UNKNOWN_VARIABLE);
359 }
360 else
361 {
362 if (my_getopt_print_errors)
363 my_getopt_error_reporter(option_is_loose ?
364 WARNING_LEVEL : ERROR_LEVEL,
365 "%s: unknown option '--%s'",
366 my_progname, cur_arg);
367 if (!option_is_loose)
368 DBUG_RETURN(EXIT_UNKNOWN_OPTION);
369 }
370 if (option_is_loose)
371 {
372 (*argc)--;
373 continue;
374 }
375 }
376 }
377 if (opt_found > 1)
378 {
379 if (must_be_var)
380 {
381 if (my_getopt_print_errors)
382 my_getopt_error_reporter(ERROR_LEVEL,
383 "%s: variable prefix '%s' is not unique",
384 my_progname, opt_str);
385 DBUG_RETURN(EXIT_VAR_PREFIX_NOT_UNIQUE);
386 }
387 else
388 {
389 if (my_getopt_print_errors)
390 my_getopt_error_reporter(ERROR_LEVEL,
391 "%s: ambiguous option '--%s' (%s, %s)",
392 my_progname, opt_str, prev_found,
393 optp->name);
394 DBUG_RETURN(EXIT_AMBIGUOUS_OPTION);
395 }
396 }
397 if ((optp->var_type & GET_TYPE_MASK) == GET_DISABLED)
398 {
399 if (my_getopt_print_errors)
400 fprintf(stderr,
401 "%s: %s: Option '%s' used, but is disabled\n", my_progname,
402 option_is_loose ? "WARNING" : "ERROR", opt_str);
403 if (option_is_loose)
404 {
405 (*argc)--;
406 continue;
407 }
408 DBUG_RETURN(EXIT_OPTION_DISABLED);
409 }
410 error= 0;
411 value= optp->var_type & GET_ASK_ADDR ?
412 (*getopt_get_addr)(key_name, (uint) strlen(key_name), optp, &error) :
413 optp->value;
414 if (error)
415 DBUG_RETURN(error);
416
417 if (optp->arg_type == NO_ARG)
418 {
419 /*
420 Due to historical reasons GET_BOOL var_types still accepts arguments
421 despite the NO_ARG arg_type attribute. This can seems a bit unintuitive
422 and care should be taken when refactoring this code.
423 */
424 if (optend && (optp->var_type & GET_TYPE_MASK) != GET_BOOL)
425 {
426 if (my_getopt_print_errors)
427 my_getopt_error_reporter(ERROR_LEVEL,
428 "%s: option '--%s' cannot take an argument",
429 my_progname, optp->name);
430 DBUG_RETURN(EXIT_NO_ARGUMENT_ALLOWED);
431 }
432 if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL)
433 {
434 /*
435 Set bool to 1 if no argument or if the user has used
436 --enable-'option-name'.
437 *optend was set to '0' if one used --disable-option
438 */
439 (*argc)--;
440 if (!optend || *optend == '1' ||
441 !my_strcasecmp(&my_charset_latin1, optend, "true") ||
442 !my_strcasecmp(&my_charset_latin1, optend, "on"))
443 *((my_bool*) value)= (my_bool) 1;
444 else if (*optend == '0' ||
445 !my_strcasecmp(&my_charset_latin1, optend, "false") ||
446 !my_strcasecmp(&my_charset_latin1, optend, "off"))
447 *((my_bool*) value)= (my_bool) 0;
448 else
449 {
450 my_getopt_error_reporter(WARNING_LEVEL,
451 "%s: ignoring option '--%s' "
452 "due to invalid value '%s'",
453 my_progname, optp->name, optend);
454 continue;
455 }
456 if (get_one_option && get_one_option(optp->id, optp,
457 *((my_bool*) value) ?
458 enabled_my_option : disabled_my_option))
459 DBUG_RETURN(EXIT_ARGUMENT_INVALID);
460 continue;
461 }
462 argument= optend;
463 }
464 else if (option_is_autoset)
465 {
466 if (optend)
467 {
468 my_getopt_error_reporter(ERROR_LEVEL,
469 "%s: automatically set "
470 "option '--%s' cannot take an argument",
471 my_progname, optp->name);
472
473 DBUG_RETURN(EXIT_NO_ARGUMENT_ALLOWED);
474 }
475 /*
476 We support automatic setup only via get_one_option and only for
477 marked options.
478 */
479 if (!get_one_option ||
480 !(optp->var_type & GET_AUTO))
481 {
482 my_getopt_error_reporter(option_is_loose ?
483 WARNING_LEVEL : ERROR_LEVEL,
484 "%s: automatic setup request is "
485 "unsupported by option '--%s'",
486 my_progname, optp->name);
487 if (!option_is_loose)
488 DBUG_RETURN(EXIT_ARGUMENT_INVALID);
489 continue;
490 }
491 else
492 argument= autoset_my_option;
493 }
494 else if (optp->arg_type == REQUIRED_ARG && !optend)
495 {
496 /* Check if there are more arguments after this one,
497 Note: options loaded from config file that requires value
498 should always be in the form '--option=value'.
499 */
500 if (!is_cmdline_arg || !*++pos)
501 {
502 if (my_getopt_print_errors)
503 my_getopt_error_reporter(ERROR_LEVEL,
504 "%s: option '--%s' requires an argument",
505 my_progname, optp->name);
506 DBUG_RETURN(EXIT_ARGUMENT_REQUIRED);
507 }
508 argument= *pos;
509 (*argc)--;
510 }
511 else
512 argument= optend;
513 }
514 else /* must be short option */
515 {
516 for (optend= cur_arg; *optend; optend++)
517 {
518 opt_found= 0;
519 for (optp= longopts; optp->name; optp++)
520 {
521 if (optp->id && optp->id == (int) (uchar) *optend)
522 {
523 /* Option recognized. Find next what to do with it */
524 opt_found= 1;
525 if ((optp->var_type & GET_TYPE_MASK) == GET_DISABLED)
526 {
527 if (my_getopt_print_errors)
528 fprintf(stderr,
529 "%s: ERROR: Option '-%c' used, but is disabled\n",
530 my_progname, optp->id);
531 DBUG_RETURN(EXIT_OPTION_DISABLED);
532 }
533 if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL &&
534 optp->arg_type == NO_ARG)
535 {
536 *((my_bool*) optp->value)= (my_bool) 1;
537 if (get_one_option && get_one_option(optp->id, optp, argument))
538 DBUG_RETURN(EXIT_UNSPECIFIED_ERROR);
539 continue;
540 }
541 else if (optp->arg_type == REQUIRED_ARG ||
542 optp->arg_type == OPT_ARG)
543 {
544 if (*(optend + 1))
545 {
546 /* The rest of the option is option argument */
547 argument= optend + 1;
548 /* This is in effect a jump out of the outer loop */
549 optend= (char*) " ";
550 }
551 else
552 {
553 if (optp->arg_type == OPT_ARG)
554 {
555 if (optp->var_type == GET_BOOL)
556 *((my_bool*) optp->value)= (my_bool) 1;
557 if (get_one_option && get_one_option(optp->id, optp, argument))
558 DBUG_RETURN(EXIT_UNSPECIFIED_ERROR);
559 continue;
560 }
561 /* Check if there are more arguments after this one */
562 if (!pos[1])
563 {
564 if (my_getopt_print_errors)
565 my_getopt_error_reporter(ERROR_LEVEL,
566 "%s: option '-%c' requires an argument",
567 my_progname, optp->id);
568 DBUG_RETURN(EXIT_ARGUMENT_REQUIRED);
569 }
570 argument= *++pos;
571 (*argc)--;
572 /* the other loop will break, because *optend + 1 == 0 */
573 }
574 }
575 if ((error= setval(optp, optp->value, argument,
576 set_maximum_value)))
577 DBUG_RETURN(error);
578 if (get_one_option && get_one_option(optp->id, optp, argument))
579 DBUG_RETURN(EXIT_UNSPECIFIED_ERROR);
580 break;
581 }
582 }
583 if (!opt_found)
584 {
585 if (my_getopt_skip_unknown)
586 {
587 /*
588 We are currently parsing a single argv[] argument
589 of the form "-XYZ".
590 One or the argument found (say Y) is not an option.
591 Hack the string "-XYZ" to make a "-YZ" substring in it,
592 and push that to the output as an unrecognized parameter.
593 */
594 DBUG_ASSERT(optend > *pos);
595 DBUG_ASSERT(optend >= cur_arg);
596 DBUG_ASSERT(optend <= *pos + strlen(*pos));
597 DBUG_ASSERT(*optend);
598 optend--;
599 optend[0]= '-'; /* replace 'X' or '-' by '-' */
600 (*argv)[argvpos++]= optend;
601 /*
602 Do not continue to parse at the current "-XYZ" argument,
603 skip to the next argv[] argument instead.
604 */
605 optend= (char*) " ";
606 }
607 else
608 {
609 if (my_getopt_print_errors)
610 my_getopt_error_reporter(ERROR_LEVEL,
611 "%s: unknown option '-%c'",
612 my_progname, *optend);
613 DBUG_RETURN(EXIT_UNKNOWN_OPTION);
614 }
615 }
616 }
617 if (opt_found)
618 (*argc)--; /* option handled (short), decrease argument count */
619 continue;
620 }
621 if ((!option_is_autoset) &&
622 ((error= setval(optp, value, argument, set_maximum_value))) &&
623 !option_is_loose)
624 DBUG_RETURN(error);
625 if (get_one_option && get_one_option(optp->id, optp, argument))
626 DBUG_RETURN(EXIT_UNSPECIFIED_ERROR);
627
628 (*argc)--; /* option handled (long), decrease argument count */
629 }
630 else /* non-option found */
631 (*argv)[argvpos++]= cur_arg;
632 }
633 /*
634 Destroy the first, already handled option, so that programs that look
635 for arguments in 'argv', without checking 'argc', know when to stop.
636 Items in argv, before the destroyed one, are all non-option -arguments
637 to the program, yet to be (possibly) handled.
638 */
639 (*argv)[argvpos]= 0;
640 DBUG_RETURN(0);
641}
642
643
644/*
645 function: check_struct_option
646
647 Arguments: Current argument under processing from argv and a variable
648 where to store the possible key name.
649
650 Return value: In case option is a struct option, returns a pointer to
651 the current argument at the position where the struct option (key_name)
652 ends, the next character after the dot. In case argument is not a struct
653 option, returns a pointer to the argument.
654
655 key_name will hold the name of the key, or 0 if not found.
656*/
657
658static char *check_struct_option(char *cur_arg, char *key_name)
659{
660 char *ptr, *end;
661 DBUG_ENTER("check_struct_option");
662
663 ptr= strcend(cur_arg + 1, '.'); /* Skip the first character */
664 end= strcend(cur_arg, '=');
665
666 /*
667 If the first dot is after an equal sign, then it is part
668 of a variable value and the option is not a struct option.
669 Also, if the last character in the string before the ending
670 NULL, or the character right before equal sign is the first
671 dot found, the option is not a struct option.
672 */
673 if (end - ptr > 1)
674 {
675 uint len= (uint) (ptr - cur_arg);
676 set_if_smaller(len, FN_REFLEN-1);
677 strmake(key_name, cur_arg, len);
678 DBUG_RETURN(++ptr);
679 }
680 else
681 {
682 key_name[0]= 0;
683 DBUG_RETURN(cur_arg);
684 }
685}
686
687/**
688 Parse a boolean command line argument
689
690 "ON", "TRUE" and "1" will return true,
691 other values will return false.
692
693 @param[in] argument The value argument
694 @return boolean value
695*/
696static my_bool get_bool_argument(const struct my_option *opts,
697 const char *argument)
698{
699 DBUG_ENTER("get_bool_argument");
700
701 if (!my_strcasecmp(&my_charset_latin1, argument, "true") ||
702 !my_strcasecmp(&my_charset_latin1, argument, "on") ||
703 !my_strcasecmp(&my_charset_latin1, argument, "1"))
704 DBUG_RETURN(1);
705 else if (!my_strcasecmp(&my_charset_latin1, argument, "false") ||
706 !my_strcasecmp(&my_charset_latin1, argument, "off") ||
707 !my_strcasecmp(&my_charset_latin1, argument, "0"))
708 DBUG_RETURN(0);
709 my_getopt_error_reporter(WARNING_LEVEL,
710 "option '%s': boolean value '%s' wasn't recognized. Set to OFF.",
711 opts->name, argument);
712 DBUG_RETURN(0);
713}
714
715/*
716 function: setval
717
718 Arguments: opts, argument
719 Will set the option value to given value
720*/
721
722static int setval(const struct my_option *opts, void *value, char *argument,
723 my_bool set_maximum_value)
724{
725 int err= 0, res= 0;
726 DBUG_ENTER("setval");
727
728 if (!argument)
729 argument= enabled_my_option;
730
731 if (value)
732 {
733 if (set_maximum_value && !(value= opts->u_max_value))
734 {
735 my_getopt_error_reporter(ERROR_LEVEL,
736 "%s: Maximum value of '%s' cannot be set",
737 my_progname, opts->name);
738 DBUG_RETURN(EXIT_NO_PTR_TO_VARIABLE);
739 }
740
741 switch ((opts->var_type & GET_TYPE_MASK)) {
742 case GET_BOOL: /* If argument differs from 0, enable option, else disable */
743 *((my_bool*) value)= get_bool_argument(opts, argument);
744 break;
745 case GET_INT:
746 *((int*) value)= (int) getopt_ll(argument, opts, &err);
747 break;
748 case GET_UINT:
749 *((uint*) value)= (uint) getopt_ull(argument, opts, &err);
750 break;
751 case GET_LONG:
752 *((long*) value)= (long) getopt_ll(argument, opts, &err);
753 break;
754 case GET_ULONG:
755 *((long*) value)= (long) getopt_ull(argument, opts, &err);
756 break;
757 case GET_LL:
758 *((longlong*) value)= getopt_ll(argument, opts, &err);
759 break;
760 case GET_ULL:
761 *((ulonglong*) value)= getopt_ull(argument, opts, &err);
762 break;
763 case GET_DOUBLE:
764 *((double*) value)= getopt_double(argument, opts, &err);
765 break;
766 case GET_STR:
767 /* If no argument or --enable-string-option, set string to "" */
768 *((char**) value)= argument == enabled_my_option ? (char*) "" : argument;
769 break;
770 case GET_STR_ALLOC:
771 my_free(*((char**) value));
772 if (!(*((char**) value)= my_strdup(argument == enabled_my_option ? "" :
773 argument, MYF(MY_WME))))
774 {
775 res= EXIT_OUT_OF_MEMORY;
776 goto ret;
777 };
778 break;
779 case GET_ENUM:
780 {
781 int type= find_type(argument, opts->typelib, FIND_TYPE_BASIC);
782 if (type == 0)
783 {
784 /*
785 Accept an integer representation of the enumerated item.
786 */
787 char *endptr;
788 ulong arg= strtoul(argument, &endptr, 10);
789 if (*endptr || arg >= opts->typelib->count)
790 {
791 res= EXIT_ARGUMENT_INVALID;
792 goto ret;
793 }
794 *(ulong*)value= arg;
795 }
796 else if (type < 0)
797 {
798 res= EXIT_AMBIGUOUS_OPTION;
799 goto ret;
800 }
801 else
802 *(ulong*)value= type - 1;
803 }
804 break;
805 case GET_SET:
806 *((ulonglong*)value)= find_typeset(argument, opts->typelib, &err);
807 if (err)
808 {
809 /* Accept an integer representation of the set */
810 char *endptr;
811 ulonglong arg= (ulonglong) strtol(argument, &endptr, 10);
812 if (*endptr || (arg >> 1) >= (1ULL << (opts->typelib->count-1)))
813 {
814 res= EXIT_ARGUMENT_INVALID;
815 goto ret;
816 };
817 *(ulonglong*)value= arg;
818 err= 0;
819 }
820 break;
821 case GET_FLAGSET:
822 {
823 char *error;
824 uint error_len;
825
826 *((ulonglong*)value)=
827 find_set_from_flags(opts->typelib, opts->typelib->count,
828 *(ulonglong *)value, opts->def_value,
829 argument, (uint)strlen(argument),
830 &error, &error_len);
831 if (error)
832 {
833 res= EXIT_ARGUMENT_INVALID;
834 goto ret;
835 };
836 }
837 break;
838 case GET_BIT:
839 {
840 uint tmp;
841 ulonglong bit= (opts->block_size >= 0 ?
842 opts->block_size :
843 -opts->block_size);
844 /*
845 This sets a bit stored in a longlong.
846 The bit to set is stored in block_size. If block_size is positive
847 then setting the bit means value is true. If block_size is negatitive,
848 then setting the bit means value is false.
849 */
850 tmp= get_bool_argument(opts, argument);
851 if (opts->block_size < 0)
852 tmp= !tmp;
853 if (tmp)
854 (*(ulonglong*)value)|= bit;
855 else
856 (*(ulonglong*)value)&= ~bit;
857 break;
858 }
859 case GET_NO_ARG: /* get_one_option has taken care of the value already */
860 default: /* dummy default to avoid compiler warnings */
861 break;
862 }
863 if (err)
864 {
865 res= EXIT_UNKNOWN_SUFFIX;
866 goto ret;
867 };
868 }
869 DBUG_RETURN(0);
870
871ret:
872 my_getopt_error_reporter(ERROR_LEVEL,
873 "%s: Error while setting value '%s' to '%s'",
874 my_progname, argument, opts->name);
875 DBUG_RETURN(res);
876}
877
878
879/*
880 Find option
881
882 SYNOPSIS
883 findopt()
884 optpat Prefix of option to find (with - or _)
885 length Length of optpat
886 opt_res Options
887 ffname Place for pointer to first found name
888
889 IMPLEMENTATION
890 Go through all options in the my_option struct. Return number
891 of options found that match the pattern and in the argument
892 list the option found, if any. In case of ambiguous option, store
893 the name in ffname argument
894
895 RETURN
896 0 No matching options
897 # Number of matching options
898 ffname points to first matching option
899*/
900
901static int findopt(char *optpat, uint length,
902 const struct my_option **opt_res,
903 const char **ffname)
904{
905 uint count;
906 const struct my_option *opt= *opt_res;
907 DBUG_ENTER("findopt");
908
909 for (count= 0; opt->name; opt++)
910 {
911 if (!getopt_compare_strings(opt->name, optpat, length)) /* match found */
912 {
913 (*opt_res)= opt;
914 if (!opt->name[length]) /* Exact match */
915 DBUG_RETURN(1);
916
917 if (!my_getopt_prefix_matching)
918 continue;
919
920 if (!count)
921 {
922 /* We only need to know one prev */
923 count= 1;
924 *ffname= opt->name;
925 }
926 else if (strcmp(*ffname, opt->name))
927 {
928 /*
929 The above test is to not count same option twice
930 (see mysql.cc, option "help")
931 */
932 count++;
933 }
934 }
935 }
936
937 if (count == 1)
938 my_getopt_error_reporter(INFORMATION_LEVEL,
939 "Using unique option prefix '%.*s' is error-prone "
940 "and can break in the future. "
941 "Please use the full name '%s' instead.",
942 length, optpat, *ffname);
943
944 DBUG_RETURN(count);
945}
946
947
948/*
949 function: compare_strings
950
951 Works like strncmp, other than 1.) considers '-' and '_' the same.
952 2.) Returns -1 if strings differ, 0 if they are equal
953*/
954
955my_bool getopt_compare_strings(register const char *s, register const char *t,
956 uint length)
957{
958 char const *end= s + length;
959 DBUG_ENTER("getopt_compare_strings");
960
961 for (;s != end ; s++, t++)
962 {
963 if ((*s != '-' ? *s : '_') != (*t != '-' ? *t : '_'))
964 DBUG_RETURN(1);
965 }
966 DBUG_RETURN(0);
967}
968
969/*
970 function: eval_num_suffix
971
972 Transforms suffix like k/m/g/t/p/e to their real value.
973*/
974
975static inline ulonglong eval_num_suffix(char *suffix, int *error)
976{
977 switch (*suffix) {
978 case '\0':
979 return 1ULL;
980 case 'k':
981 case 'K':
982 return 1ULL << 10;
983 case 'm':
984 case 'M':
985 return 1ULL << 20;
986 case 'g':
987 case 'G':
988 return 1ULL << 30;
989 case 't':
990 case 'T':
991 return 1ULL << 40;
992 case 'p':
993 case 'P':
994 return 1ULL << 50;
995 case 'e':
996 case 'E':
997 return 1ULL << 60;
998 default:
999 *error= 1;
1000 return 0ULL;
1001 }
1002}
1003
1004/*
1005 function: eval_num_suffix_ll
1006
1007 Transforms a number with a suffix to real number. Suffix can
1008 be k|K for kilo, m|M for mega, etc.
1009*/
1010
1011static longlong eval_num_suffix_ll(char *argument,
1012 int *error, char *option_name)
1013{
1014 char *endchar;
1015 longlong num;
1016 DBUG_ENTER("eval_num_suffix_ll");
1017
1018
1019 *error= 0;
1020 errno= 0;
1021 num= strtoll(argument, &endchar, 10);
1022 if (errno == ERANGE)
1023 {
1024 my_getopt_error_reporter(ERROR_LEVEL,
1025 "Incorrect integer value: '%s'", argument);
1026 *error= 1;
1027 DBUG_RETURN(0);
1028 }
1029 num*= eval_num_suffix(endchar, error);
1030 if (*error)
1031 fprintf(stderr,
1032 "Unknown suffix '%c' used for variable '%s' (value '%s')\n",
1033 *endchar, option_name, argument);
1034 DBUG_RETURN(num);
1035}
1036
1037/*
1038 function: eval_num_suffix_ull
1039
1040 Transforms a number with a suffix to positive Integer. Suffix can
1041 be k|K for kilo, m|M for mega, etc.
1042*/
1043
1044static ulonglong eval_num_suffix_ull(char *argument,
1045 int *error, char *option_name)
1046{
1047 char *endchar;
1048 ulonglong num;
1049 DBUG_ENTER("eval_num_suffix_ull");
1050
1051 *error= 0;
1052 errno= 0;
1053 num= strtoull(argument, &endchar, 10);
1054 if (errno == ERANGE)
1055 {
1056 my_getopt_error_reporter(ERROR_LEVEL,
1057 "Incorrect integer value: '%s'", argument);
1058 *error= 1;
1059 DBUG_RETURN(0);
1060 }
1061 num*= eval_num_suffix(endchar, error);
1062 if (*error)
1063 fprintf(stderr,
1064 "Unknown suffix '%c' used for variable '%s' (value '%s')\n",
1065 *endchar, option_name, argument);
1066 DBUG_RETURN(num);
1067}
1068
1069
1070/*
1071 function: getopt_ll
1072
1073 Evaluates and returns the value that user gave as an argument
1074 to a variable. Recognizes (case insensitive) K as KILO, M as MEGA
1075 and G as GIGA bytes. Some values must be in certain blocks, as
1076 defined in the given my_option struct, this function will check
1077 that those values are honored.
1078 In case of an error, set error value in *err.
1079*/
1080
1081static longlong getopt_ll(char *arg, const struct my_option *optp, int *err)
1082{
1083 longlong num=eval_num_suffix_ll(arg, err, (char*) optp->name);
1084 return getopt_ll_limit_value(num, optp, NULL);
1085}
1086
1087/*
1088 function: getopt_ll_limit_value
1089
1090 Applies min/max/block_size to a numeric value of an option.
1091 Returns "fixed" value.
1092*/
1093
1094longlong getopt_ll_limit_value(longlong num, const struct my_option *optp,
1095 my_bool *fix)
1096{
1097 longlong old= num;
1098 my_bool adjusted= FALSE;
1099 char buf1[255], buf2[255];
1100 ulonglong block_size= (optp->block_size ? (ulonglong) optp->block_size : 1L);
1101 DBUG_ENTER("getopt_ll_limit_value");
1102
1103 if (num > 0 && ((ulonglong) num > (ulonglong) optp->max_value) &&
1104 optp->max_value) /* if max value is not set -> no upper limit */
1105 {
1106 num= (ulonglong) optp->max_value;
1107 adjusted= TRUE;
1108 }
1109
1110 switch ((optp->var_type & GET_TYPE_MASK)) {
1111 case GET_INT:
1112 if (num > (longlong) INT_MAX)
1113 {
1114 num= ((longlong) INT_MAX);
1115 adjusted= TRUE;
1116 }
1117 break;
1118 case GET_LONG:
1119#if SIZEOF_LONG < SIZEOF_LONG_LONG
1120 if (num > (longlong) LONG_MAX)
1121 {
1122 num= ((longlong) LONG_MAX);
1123 adjusted= TRUE;
1124 }
1125#endif
1126 break;
1127 default:
1128 DBUG_ASSERT((optp->var_type & GET_TYPE_MASK) == GET_LL);
1129 break;
1130 }
1131
1132 num= (num / block_size);
1133 num= (longlong) (num * block_size);
1134
1135 if (num < optp->min_value)
1136 {
1137 num= optp->min_value;
1138 if (old < optp->min_value)
1139 adjusted= TRUE;
1140 }
1141
1142 if (fix)
1143 *fix= old != num;
1144 else if (adjusted)
1145 my_getopt_error_reporter(WARNING_LEVEL,
1146 "option '%s': signed value %s adjusted to %s",
1147 optp->name, llstr(old, buf1), llstr(num, buf2));
1148 DBUG_RETURN(num);
1149}
1150
1151/*
1152 function: getopt_ull
1153
1154 This is the same as getopt_ll, but is meant for unsigned long long
1155 values.
1156*/
1157
1158static ulonglong getopt_ull(char *arg, const struct my_option *optp, int *err)
1159{
1160 ulonglong num= eval_num_suffix_ull(arg, err, (char*) optp->name);
1161 return getopt_ull_limit_value(num, optp, NULL);
1162}
1163
1164
1165ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp,
1166 my_bool *fix)
1167{
1168 my_bool adjusted= FALSE;
1169 ulonglong old= num;
1170 char buf1[255], buf2[255];
1171 DBUG_ENTER("getopt_ull_limit_value");
1172
1173 if ((ulonglong) num > (ulonglong) optp->max_value &&
1174 optp->max_value) /* if max value is not set -> no upper limit */
1175 {
1176 num= (ulonglong) optp->max_value;
1177 adjusted= TRUE;
1178 }
1179
1180 switch ((optp->var_type & GET_TYPE_MASK)) {
1181 case GET_UINT:
1182 if (num > (ulonglong) UINT_MAX)
1183 {
1184 num= ((ulonglong) UINT_MAX);
1185 adjusted= TRUE;
1186 }
1187 break;
1188 case GET_ULONG:
1189#if SIZEOF_LONG < SIZEOF_LONG_LONG
1190 if (num > (ulonglong) ULONG_MAX)
1191 {
1192 num= ((ulonglong) ULONG_MAX);
1193 adjusted= TRUE;
1194 }
1195#endif
1196 break;
1197 default:
1198 DBUG_ASSERT((optp->var_type & GET_TYPE_MASK) == GET_ULL);
1199 break;
1200 }
1201
1202 if (optp->block_size > 1)
1203 {
1204 num/= (ulonglong) optp->block_size;
1205 num*= (ulonglong) optp->block_size;
1206 }
1207
1208 if (num < (ulonglong) optp->min_value)
1209 {
1210 num= (ulonglong) optp->min_value;
1211 if (old < (ulonglong) optp->min_value)
1212 adjusted= TRUE;
1213 }
1214
1215 if (fix)
1216 *fix= old != num;
1217 else if (adjusted)
1218 my_getopt_error_reporter(WARNING_LEVEL,
1219 "option '%s': unsigned value %s adjusted to %s",
1220 optp->name, ullstr(old, buf1), ullstr(num, buf2));
1221
1222 DBUG_RETURN(num);
1223}
1224
1225double getopt_double_limit_value(double num, const struct my_option *optp,
1226 my_bool *fix)
1227{
1228 my_bool adjusted= FALSE;
1229 double old= num;
1230 double min, max;
1231 DBUG_ENTER("getopt_double_limit_value");
1232
1233 max= getopt_ulonglong2double(optp->max_value);
1234 min= getopt_ulonglong2double(optp->min_value);
1235 if (max && num > max)
1236 {
1237 num= max;
1238 adjusted= TRUE;
1239 }
1240 if (num < min)
1241 {
1242 num= min;
1243 adjusted= TRUE;
1244 }
1245 if (fix)
1246 *fix= adjusted;
1247 else if (adjusted)
1248 my_getopt_error_reporter(WARNING_LEVEL,
1249 "option '%s': value %g adjusted to %g",
1250 optp->name, old, num);
1251 DBUG_RETURN(num);
1252}
1253
1254/*
1255 Get double value withing ranges
1256
1257 Evaluates and returns the value that user gave as an argument to a variable.
1258
1259 RETURN
1260 decimal value of arg
1261
1262 In case of an error, prints an error message and sets *err to
1263 EXIT_ARGUMENT_INVALID. Otherwise err is not touched
1264*/
1265
1266static double getopt_double(char *arg, const struct my_option *optp, int *err)
1267{
1268 double num;
1269 int error;
1270 char *end= arg + 1000; /* Big enough as *arg is \0 terminated */
1271 num= my_strtod(arg, &end, &error);
1272 if (end[0] != 0 || error)
1273 {
1274 my_getopt_error_reporter(ERROR_LEVEL,
1275 "Invalid decimal value for option '%s'\n", optp->name);
1276 *err= EXIT_ARGUMENT_INVALID;
1277 return 0.0;
1278 }
1279 return getopt_double_limit_value(num, optp, NULL);
1280}
1281
1282/*
1283 Init one value to it's default values
1284
1285 SYNOPSIS
1286 init_one_value()
1287 option Option to initialize
1288 value Pointer to variable
1289*/
1290
1291static void init_one_value(const struct my_option *option, void *variable,
1292 longlong value)
1293{
1294 DBUG_ENTER("init_one_value");
1295 switch ((option->var_type & GET_TYPE_MASK)) {
1296 case GET_BOOL:
1297 *((my_bool*) variable)= (my_bool) value;
1298 break;
1299 case GET_INT:
1300 *((int*) variable)= (int) getopt_ll_limit_value((int) value, option, NULL);
1301 break;
1302 case GET_ENUM:
1303 *((ulong*) variable)= (ulong) value;
1304 break;
1305 case GET_UINT:
1306 *((uint*) variable)= (uint) getopt_ull_limit_value((uint) value, option, NULL);
1307 break;
1308 case GET_LONG:
1309 *((long*) variable)= (long) getopt_ll_limit_value((long) value, option, NULL);
1310 break;
1311 case GET_ULONG:
1312 *((ulong*) variable)= (ulong) getopt_ull_limit_value((ulong) value, option, NULL);
1313 break;
1314 case GET_LL:
1315 *((longlong*) variable)= (longlong) getopt_ll_limit_value((longlong) value, option, NULL);
1316 break;
1317 case GET_ULL:
1318 *((ulonglong*) variable)= (ulonglong) getopt_ull_limit_value((ulonglong) value, option, NULL);
1319 break;
1320 case GET_SET:
1321 case GET_FLAGSET:
1322 *((ulonglong*) variable)= (ulonglong) value;
1323 break;
1324 case GET_BIT:
1325 {
1326 ulonglong bit= (option->block_size >= 0 ?
1327 option->block_size :
1328 -option->block_size);
1329 if (option->block_size < 0)
1330 value= !value;
1331 if (value)
1332 (*(ulonglong*)variable)|= bit;
1333 else
1334 (*(ulonglong*)variable)&= ~bit;
1335 break;
1336 }
1337 case GET_DOUBLE:
1338 *((double*) variable)= getopt_ulonglong2double(value);
1339 break;
1340 case GET_STR:
1341 /*
1342 Do not clear variable value if it has no default value.
1343 The default value may already be set.
1344 NOTE: To avoid compiler warnings, we first cast longlong to intptr,
1345 so that the value has the same size as a pointer.
1346 */
1347 if ((char*) (intptr) value)
1348 *((char**) variable)= (char*) (intptr) value;
1349 break;
1350 case GET_STR_ALLOC:
1351 /*
1352 Do not clear variable value if it has no default value.
1353 The default value may already be set.
1354 NOTE: To avoid compiler warnings, we first cast longlong to intptr,
1355 so that the value has the same size as a pointer.
1356 */
1357 if ((char*) (intptr) value)
1358 {
1359 char **pstr= (char **) variable;
1360 my_free(*pstr);
1361 *pstr= my_strdup((char*) (intptr) value, MYF(MY_WME));
1362 }
1363 break;
1364 default: /* dummy default to avoid compiler warnings */
1365 break;
1366 }
1367 DBUG_VOID_RETURN;
1368}
1369
1370
1371/*
1372 Init one value to it's default values
1373
1374 SYNOPSIS
1375 init_one_value()
1376 option Option to initialize
1377 value Pointer to variable
1378*/
1379
1380static void fini_one_value(const struct my_option *option, void *variable,
1381 longlong value __attribute__ ((unused)))
1382{
1383 DBUG_ENTER("fini_one_value");
1384 switch ((option->var_type & GET_TYPE_MASK)) {
1385 case GET_STR_ALLOC:
1386 my_free(*((char**) variable));
1387 *((char**) variable)= NULL;
1388 break;
1389 default: /* dummy default to avoid compiler warnings */
1390 break;
1391 }
1392 DBUG_VOID_RETURN;
1393}
1394
1395
1396void my_cleanup_options(const struct my_option *options)
1397{
1398 DBUG_ENTER("my_cleanup_options");
1399 init_variables(options, fini_one_value);
1400 DBUG_VOID_RETURN;
1401}
1402
1403
1404/*
1405 initialize all variables to their default values
1406
1407 SYNOPSIS
1408 init_variables()
1409 options Array of options
1410 func_init_one_value Call this function to init the variable
1411
1412 NOTES
1413 We will initialize the value that is pointed to by options->value.
1414 If the value is of type GET_ASK_ADDR, we will ask for the address
1415 for a value and initialize.
1416*/
1417
1418static void init_variables(const struct my_option *options,
1419 init_func_p func_init_one_value)
1420{
1421 DBUG_ENTER("init_variables");
1422 for (; options->name; options++)
1423 {
1424 void *value;
1425 DBUG_PRINT("options", ("name: '%s'", options->name));
1426 /*
1427 We must set u_max_value first as for some variables
1428 options->u_max_value == options->value and in this case we want to
1429 set the value to default value.
1430 */
1431 if (options->u_max_value)
1432 func_init_one_value(options, options->u_max_value, options->max_value);
1433 value= (options->var_type & GET_ASK_ADDR ?
1434 (*getopt_get_addr)("", 0, options, 0) : options->value);
1435 if (value)
1436 func_init_one_value(options, value, options->def_value);
1437 }
1438 DBUG_VOID_RETURN;
1439}
1440
1441/** Prints variable or option name, replacing _ with - */
1442static uint print_name(const struct my_option *optp)
1443{
1444 const char *s= optp->name;
1445
1446 for (;*s;s++)
1447 putchar(*s == '_' ? '-' : *s);
1448 return (uint)(s - optp->name);
1449}
1450
1451/** prints option comment with indentation and wrapping.
1452
1453 The comment column starts at startpos, and has width of width
1454 Current cursor position is curpos, returns new cursor position
1455
1456 @note can print one character beyond width!
1457*/
1458static uint print_comment(const char *comment,
1459 int curpos, int startpos, int width)
1460{
1461 const char *end= strend(comment);
1462 int endpos= startpos + width;
1463
1464 for (; curpos < startpos; curpos++)
1465 putchar(' ');
1466
1467 if (*comment == '.' || *comment == ',')
1468 {
1469 putchar(*comment);
1470 comment++;
1471 curpos++;
1472 }
1473
1474 while (end - comment > endpos - curpos)
1475 {
1476 const char *line_end;
1477 for (line_end= comment + endpos - curpos;
1478 line_end > comment && *line_end != ' ';
1479 line_end--);
1480 for (; comment < line_end; comment++)
1481 putchar(*comment);
1482 while (*comment == ' ')
1483 comment++; /* skip the space, as a newline will take it's place now */
1484 putchar('\n');
1485 for (curpos= 0; curpos < startpos; curpos++)
1486 putchar(' ');
1487 }
1488 printf("%s", comment);
1489 return curpos + (int)(end - comment);
1490}
1491
1492
1493/*
1494 function: my_print_options
1495
1496 Print help for all options and variables.
1497*/
1498
1499void my_print_help(const struct my_option *options)
1500{
1501 uint col, name_space= 22, comment_space= 57;
1502 const struct my_option *optp;
1503 DBUG_ENTER("my_print_help");
1504
1505 for (optp= options; optp->name; optp++)
1506 {
1507 const char *typelib_help= 0;
1508 if (!optp->comment)
1509 continue;
1510 if (optp->id && optp->id < 256)
1511 {
1512 printf(" -%c%s", optp->id, strlen(optp->name) ? ", " : " ");
1513 col= 6;
1514 }
1515 else
1516 {
1517 printf(" ");
1518 col= 2;
1519 }
1520 if (strlen(optp->name))
1521 {
1522 printf("--");
1523 col+= 2 + print_name(optp);
1524 if (optp->arg_type == NO_ARG ||
1525 (optp->var_type & GET_TYPE_MASK) == GET_BOOL ||
1526 (optp->var_type & GET_TYPE_MASK) == GET_BIT)
1527 {
1528 putchar(' ');
1529 col++;
1530 }
1531 else if ((optp->var_type & GET_TYPE_MASK) == GET_STR ||
1532 (optp->var_type & GET_TYPE_MASK) == GET_STR_ALLOC ||
1533 (optp->var_type & GET_TYPE_MASK) == GET_ENUM ||
1534 (optp->var_type & GET_TYPE_MASK) == GET_SET ||
1535 (optp->var_type & GET_TYPE_MASK) == GET_FLAGSET )
1536 {
1537 printf("%s=name%s ", optp->arg_type == OPT_ARG ? "[" : "",
1538 optp->arg_type == OPT_ARG ? "]" : "");
1539 col+= (optp->arg_type == OPT_ARG) ? 8 : 6;
1540 }
1541 else
1542 {
1543 printf("%s=#%s ", optp->arg_type == OPT_ARG ? "[" : "",
1544 optp->arg_type == OPT_ARG ? "]" : "");
1545 col+= (optp->arg_type == OPT_ARG) ? 5 : 3;
1546 }
1547 }
1548 if (optp->comment && *optp->comment)
1549 {
1550 uint count;
1551
1552 if (col > name_space)
1553 {
1554 putchar('\n');
1555 col= 0;
1556 }
1557
1558 col= print_comment(optp->comment, col, name_space, comment_space);
1559 if (optp->var_type & GET_AUTO)
1560 {
1561 col= print_comment(" (Automatically configured unless set explicitly)",
1562 col, name_space, comment_space);
1563 }
1564
1565 switch (optp->var_type & GET_TYPE_MASK) {
1566 case GET_ENUM:
1567 typelib_help= ". One of: ";
1568 count= optp->typelib->count;
1569 break;
1570 case GET_SET:
1571 typelib_help= ". Any combination of: ";
1572 count= optp->typelib->count;
1573 break;
1574 case GET_FLAGSET:
1575 typelib_help= ". Takes a comma-separated list of option=value pairs, "
1576 "where value is on, off, or default, and options are: ";
1577 count= optp->typelib->count - 1;
1578 break;
1579 }
1580 if (typelib_help &&
1581 strstr(optp->comment, optp->typelib->type_names[0]) == NULL)
1582 {
1583 uint i;
1584 col= print_comment(typelib_help, col, name_space, comment_space);
1585 col= print_comment(optp->typelib->type_names[0], col, name_space, comment_space);
1586 for (i= 1; i < count; i++)
1587 {
1588 col= print_comment(", ", col, name_space, comment_space);
1589 col= print_comment(optp->typelib->type_names[i], col, name_space, comment_space);
1590 }
1591 }
1592 }
1593 putchar('\n');
1594 if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL)
1595 {
1596 if (optp->def_value != 0)
1597 {
1598 printf("%*s(Defaults to on; use --skip-", name_space, "");
1599 print_name(optp);
1600 printf(" to disable.)\n");
1601 }
1602 }
1603 }
1604 DBUG_VOID_RETURN;
1605}
1606
1607
1608/*
1609 function: my_print_options
1610
1611 Print variables.
1612*/
1613
1614void my_print_variables(const struct my_option *options)
1615{
1616 uint name_space= 34, length, nr;
1617 ulonglong llvalue;
1618 char buff[255];
1619 const struct my_option *optp;
1620 DBUG_ENTER("my_print_variables");
1621
1622 for (optp= options; optp->name; optp++)
1623 {
1624 length= (uint)strlen(optp->name)+1;
1625 if (length > name_space)
1626 name_space= length;
1627 }
1628
1629 printf("\nVariables (--variable-name=value)\n");
1630 printf("%-*s%s", name_space, "and boolean options {FALSE|TRUE}",
1631 "Value (after reading options)\n");
1632 for (length=1; length < 75; length++)
1633 putchar(length == name_space ? ' ' : '-');
1634 putchar('\n');
1635
1636 for (optp= options; optp->name; optp++)
1637 {
1638 void *value= (optp->var_type & GET_ASK_ADDR ?
1639 (*getopt_get_addr)("", 0, optp, 0) : optp->value);
1640 if (value)
1641 {
1642 length= print_name(optp);
1643 for (; length < name_space; length++)
1644 putchar(' ');
1645 switch ((optp->var_type & GET_TYPE_MASK)) {
1646 case GET_SET:
1647 if (!(llvalue= *(ulonglong*) value))
1648 printf("%s\n", "");
1649 else
1650 for (nr= 0; llvalue && nr < optp->typelib->count; nr++, llvalue >>=1)
1651 {
1652 if (llvalue & 1)
1653 printf( llvalue > 1 ? "%s," : "%s\n", get_type(optp->typelib, nr));
1654 }
1655 break;
1656 case GET_FLAGSET:
1657 llvalue= *(ulonglong*) value;
1658 for (nr= 0; llvalue && nr < optp->typelib->count; nr++, llvalue >>=1)
1659 {
1660 printf("%s%s=", (nr ? "," : ""), get_type(optp->typelib, nr));
1661 printf(llvalue & 1 ? "on" : "off");
1662 }
1663 printf("\n");
1664 break;
1665 case GET_ENUM:
1666 printf("%s\n", get_type(optp->typelib, *(ulong*) value));
1667 break;
1668 case GET_STR:
1669 case GET_STR_ALLOC: /* fall through */
1670 printf("%s\n", *((char**) value) ? *((char**) value) :
1671 "(No default value)");
1672 break;
1673 case GET_BOOL:
1674 printf("%s\n", *((my_bool*) value) ? "TRUE" : "FALSE");
1675 break;
1676 case GET_BIT:
1677 {
1678 ulonglong bit= (optp->block_size >= 0 ?
1679 optp->block_size :
1680 -optp->block_size);
1681 my_bool reverse= optp->block_size < 0;
1682 printf("%s\n", ((*((ulonglong*) value) & bit) != 0) ^ reverse ?
1683 "TRUE" : "FALSE");
1684 break;
1685 }
1686 case GET_INT:
1687 printf("%d\n", *((int*) value));
1688 break;
1689 case GET_UINT:
1690 printf("%u\n", *((uint*) value));
1691 break;
1692 case GET_LONG:
1693 printf("%ld\n", *((long*) value));
1694 break;
1695 case GET_ULONG:
1696 printf("%lu\n", *((ulong*) value));
1697 break;
1698 case GET_LL:
1699 printf("%s\n", llstr(*((longlong*) value), buff));
1700 break;
1701 case GET_ULL:
1702 longlong10_to_str(*((ulonglong*) value), buff, 10);
1703 printf("%s\n", buff);
1704 break;
1705 case GET_DOUBLE:
1706 printf("%g\n", *(double*) value);
1707 break;
1708 case GET_NO_ARG:
1709 printf("(No default value)\n");
1710 break;
1711 default:
1712 printf("(Disabled)\n");
1713 break;
1714 }
1715 }
1716 }
1717 DBUG_VOID_RETURN;
1718}
1719