diff options
Diffstat (limited to 'externals/mysql/mysys/my_getopt.c')
-rw-r--r-- | externals/mysql/mysys/my_getopt.c | 1301 |
1 files changed, 1301 insertions, 0 deletions
diff --git a/externals/mysql/mysys/my_getopt.c b/externals/mysql/mysys/my_getopt.c new file mode 100644 index 00000000000..a16cc0897a8 --- /dev/null +++ b/externals/mysql/mysys/my_getopt.c @@ -0,0 +1,1301 @@ +/* Copyright (C) 2002-2006 MySQL AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; version 2 of the License. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include <my_global.h> +#include <m_string.h> +#include <stdlib.h> +#include <my_sys.h> +#include <mysys_err.h> +#include <my_getopt.h> +#include <errno.h> + +typedef void (*init_func_p)(const struct my_option *option, uchar* *variable, + longlong value); + +static void default_reporter(enum loglevel level, const char *format, ...); +my_error_reporter my_getopt_error_reporter= &default_reporter; + +static int findopt(char *, uint, const struct my_option **, char **); +my_bool getopt_compare_strings(const char *, const char *, uint); +static longlong getopt_ll(char *, const struct my_option *, int *); +static ulonglong getopt_ull(char *, const struct my_option *, int *); +static double getopt_double(char *, const struct my_option *, int *); +static void init_variables(const struct my_option *, init_func_p); +static void init_one_value(const struct my_option *opt, uchar **, longlong); +static void fini_one_value(const struct my_option *, uchar **, longlong); +static int setval(const struct my_option *, uchar **, char *, my_bool); +static char *check_struct_option(char *cur_arg, char *key_name); + +/* + The following three variables belong to same group and the number and + order of their arguments must correspond to each other. +*/ +static const char *special_opt_prefix[]= +{"skip", "disable", "enable", "maximum", "loose", 0}; +static const uint special_opt_prefix_lengths[]= +{ 4, 7, 6, 7, 5, 0}; +enum enum_special_opt +{ OPT_SKIP, OPT_DISABLE, OPT_ENABLE, OPT_MAXIMUM, OPT_LOOSE}; + +char *disabled_my_option= (char*) "0"; + +/* + This is a flag that can be set in client programs. 0 means that + my_getopt will not print error messages, but the client should do + it by itself +*/ + +my_bool my_getopt_print_errors= 1; + +/* + This is a flag that can be set in client programs. 1 means that + my_getopt will skip over options it does not know how to handle. +*/ + +my_bool my_getopt_skip_unknown= 0; + +static void default_reporter(enum loglevel level, + const char *format, ...) +{ + va_list args; + va_start(args, format); + if (level == WARNING_LEVEL) + fprintf(stderr, "%s", "Warning: "); + else if (level == INFORMATION_LEVEL) + fprintf(stderr, "%s", "Info: "); + vfprintf(stderr, format, args); + va_end(args); + fputc('\n', stderr); + fflush(stderr); +} + +/* + function: handle_options + + Sort options; put options first, until special end of options (--), or + until end of argv. Parse options; check that the given option matches with + one of the options in struct 'my_option', return error in case of ambiguous + or unknown option. Check that option was given an argument if it requires + one. Call function 'get_one_option()' once for each option. +*/ + +static uchar** (*getopt_get_addr)(const char *, uint, const struct my_option *, int *); + +void my_getopt_register_get_addr(uchar** (*func_addr)(const char *, uint, + const struct my_option *, int *)) +{ + getopt_get_addr= func_addr; +} + +int handle_options(int *argc, char ***argv, + const struct my_option *longopts, + my_get_one_option get_one_option) +{ + uint opt_found, argvpos= 0, length; + my_bool end_of_options= 0, must_be_var, set_maximum_value, + option_is_loose; + char **pos, **pos_end, *optend, *prev_found, + *opt_str, key_name[FN_REFLEN]; + const struct my_option *optp; + uchar* *value; + int error, i; + my_bool is_cmdline_arg= 1; + + LINT_INIT(opt_found); + /* handle_options() assumes arg0 (program name) always exists */ + DBUG_ASSERT(argc && *argc >= 1); + DBUG_ASSERT(argv && *argv); + (*argc)--; /* Skip the program name */ + (*argv)++; /* --- || ---- */ + init_variables(longopts, init_one_value); + + /* + Search for args_separator, if found, then the first part of the + arguments are loaded from configs + */ + for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++) + { + if (*pos == args_separator) + { + is_cmdline_arg= 0; + break; + } + } + + for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++) + { + char **first= pos; + char *cur_arg= *pos; + if (!is_cmdline_arg && (cur_arg == args_separator)) + { + is_cmdline_arg= 1; + + /* save the separator too if skip unkown options */ + if (my_getopt_skip_unknown) + (*argv)[argvpos++]= cur_arg; + else + (*argc)--; + continue; + } + if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */ + { + char *argument= 0; + must_be_var= 0; + set_maximum_value= 0; + option_is_loose= 0; + + cur_arg++; /* skip '-' */ + if (*cur_arg == '-' || *cur_arg == 'O') /* check for long option, */ + { /* --set-variable, or -O */ + if (*cur_arg == 'O') + { + must_be_var= 1; + + if (!(*++cur_arg)) /* If not -Ovar=# */ + { + /* the argument must be in next argv */ + if (!*++pos) + { + if (my_getopt_print_errors) + my_getopt_error_reporter(ERROR_LEVEL, + "%s: Option '-O' requires an argument", + my_progname); + return EXIT_ARGUMENT_REQUIRED; + } + cur_arg= *pos; + (*argc)--; + } + } + else if (!getopt_compare_strings(cur_arg, "-set-variable", 13)) + { + must_be_var= 1; + if (cur_arg[13] == '=') + { + cur_arg+= 14; + if (!*cur_arg) + { + if (my_getopt_print_errors) + my_getopt_error_reporter(ERROR_LEVEL, + "%s: Option '--set-variable' requires an argument", + my_progname); + return EXIT_ARGUMENT_REQUIRED; + } + } + else if (cur_arg[14]) /* garbage, or another option. break out */ + must_be_var= 0; + else + { + /* the argument must be in next argv */ + if (!*++pos) + { + if (my_getopt_print_errors) + my_getopt_error_reporter(ERROR_LEVEL, + "%s: Option '--set-variable' requires an argument", + my_progname); + return EXIT_ARGUMENT_REQUIRED; + } + cur_arg= *pos; + (*argc)--; + } + } + else if (!must_be_var) + { + if (!*++cur_arg) /* skip the double dash */ + { + /* '--' means end of options, look no further */ + end_of_options= 1; + (*argc)--; + continue; + } + } + opt_str= check_struct_option(cur_arg, key_name); + optend= strcend(opt_str, '='); + length= (uint) (optend - opt_str); + if (*optend == '=') + optend++; + else + optend= 0; + + /* + Find first the right option. Return error in case of an ambiguous, + or unknown option + */ + LINT_INIT(prev_found); + optp= longopts; + if (!(opt_found= findopt(opt_str, length, &optp, &prev_found))) + { + /* + Didn't find any matching option. Let's see if someone called + option with a special option prefix + */ + if (!must_be_var) + { + if (optend) + must_be_var= 1; /* option is followed by an argument */ + for (i= 0; special_opt_prefix[i]; i++) + { + if (!getopt_compare_strings(special_opt_prefix[i], opt_str, + special_opt_prefix_lengths[i]) && + (opt_str[special_opt_prefix_lengths[i]] == '-' || + opt_str[special_opt_prefix_lengths[i]] == '_')) + { + /* + We were called with a special prefix, we can reuse opt_found + */ + opt_str+= special_opt_prefix_lengths[i] + 1; + length-= special_opt_prefix_lengths[i] + 1; + if (i == OPT_LOOSE) + option_is_loose= 1; + if ((opt_found= findopt(opt_str, length, &optp, &prev_found))) + { + if (opt_found > 1) + { + if (my_getopt_print_errors) + my_getopt_error_reporter(ERROR_LEVEL, + "%s: ambiguous option '--%s-%s' (--%s-%s)", + my_progname, special_opt_prefix[i], + cur_arg, special_opt_prefix[i], + prev_found); + return EXIT_AMBIGUOUS_OPTION; + } + switch (i) { + case OPT_SKIP: + case OPT_DISABLE: /* fall through */ + /* + double negation is actually enable again, + for example: --skip-option=0 -> option = TRUE + */ + optend= (optend && *optend == '0' && !(*(optend + 1))) ? + (char*) "1" : disabled_my_option; + break; + case OPT_ENABLE: + optend= (optend && *optend == '0' && !(*(optend + 1))) ? + disabled_my_option : (char*) "1"; + break; + case OPT_MAXIMUM: + set_maximum_value= 1; + must_be_var= 1; + break; + } + break; /* break from the inner loop, main loop continues */ + } + i= -1; /* restart the loop */ + } + } + } + if (!opt_found) + { + if (my_getopt_skip_unknown) + { + /* + preserve all the components of this unknown option, this may + occurr when the user provides options like: "-O foo" or + "--set-variable foo" (note that theres a space in there) + Generally, these kind of options are to be avoided + */ + do { + (*argv)[argvpos++]= *first++; + } while (first <= pos); + continue; + } + if (must_be_var) + { + if (my_getopt_print_errors) + my_getopt_error_reporter(option_is_loose ? + WARNING_LEVEL : ERROR_LEVEL, + "%s: unknown variable '%s'", + my_progname, cur_arg); + if (!option_is_loose) + return EXIT_UNKNOWN_VARIABLE; + } + else + { + if (my_getopt_print_errors) + my_getopt_error_reporter(option_is_loose ? + WARNING_LEVEL : ERROR_LEVEL, + "%s: unknown option '--%s'", + my_progname, cur_arg); + if (!option_is_loose) + return EXIT_UNKNOWN_OPTION; + } + if (option_is_loose) + { + (*argc)--; + continue; + } + } + } + if (opt_found > 1) + { + if (must_be_var) + { + if (my_getopt_print_errors) + my_getopt_error_reporter(ERROR_LEVEL, + "%s: variable prefix '%s' is not unique", + my_progname, opt_str); + return EXIT_VAR_PREFIX_NOT_UNIQUE; + } + else + { + if (my_getopt_print_errors) + my_getopt_error_reporter(ERROR_LEVEL, + "%s: ambiguous option '--%s' (%s, %s)", + my_progname, opt_str, prev_found, + optp->name); + return EXIT_AMBIGUOUS_OPTION; + } + } + if ((optp->var_type & GET_TYPE_MASK) == GET_DISABLED) + { + if (my_getopt_print_errors) + fprintf(stderr, + "%s: %s: Option '%s' used, but is disabled\n", my_progname, + option_is_loose ? "WARNING" : "ERROR", opt_str); + if (option_is_loose) + { + (*argc)--; + continue; + } + return EXIT_OPTION_DISABLED; + } + if (must_be_var && (optp->var_type & GET_TYPE_MASK) == GET_NO_ARG) + { + if (my_getopt_print_errors) + my_getopt_error_reporter(ERROR_LEVEL, + "%s: option '%s' cannot take an argument", + my_progname, optp->name); + return EXIT_NO_ARGUMENT_ALLOWED; + } + error= 0; + value= optp->var_type & GET_ASK_ADDR ? + (*getopt_get_addr)(key_name, (uint) strlen(key_name), optp, &error) : + optp->value; + if (error) + return error; + + if (optp->arg_type == NO_ARG) + { + if (optend && (optp->var_type & GET_TYPE_MASK) != GET_BOOL) + { + if (my_getopt_print_errors) + my_getopt_error_reporter(ERROR_LEVEL, + "%s: option '--%s' cannot take an argument", + my_progname, optp->name); + return EXIT_NO_ARGUMENT_ALLOWED; + } + if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL) + { + /* + Set bool to 1 if no argument or if the user has used + --enable-'option-name'. + *optend was set to '0' if one used --disable-option + */ + (*argc)--; + if (!optend || *optend == '1' || + !my_strcasecmp(&my_charset_latin1, optend, "true")) + *((my_bool*) value)= (my_bool) 1; + else if (*optend == '0' || + !my_strcasecmp(&my_charset_latin1, optend, "false")) + *((my_bool*) value)= (my_bool) 0; + else + { + my_getopt_error_reporter(WARNING_LEVEL, + "%s: ignoring option '--%s' due to \ +invalid value '%s'", + my_progname, optp->name, optend); + continue; + } + if (get_one_option(optp->id, optp, + *((my_bool*) value) ? + (char*) "1" : disabled_my_option)) + return EXIT_ARGUMENT_INVALID; + continue; + } + argument= optend; + } + else if (optp->arg_type == OPT_ARG && + (optp->var_type & GET_TYPE_MASK) == GET_BOOL) + { + if (optend == disabled_my_option) + *((my_bool*) value)= (my_bool) 0; + else + { + if (!optend) /* No argument -> enable option */ + *((my_bool*) value)= (my_bool) 1; + else + argument= optend; + } + } + else if (optp->arg_type == REQUIRED_ARG && !optend) + { + /* Check if there are more arguments after this one, + + Note: options loaded from config file that requires value + should always be in the form '--option=value'. + */ + if (!is_cmdline_arg || !*++pos) + { + if (my_getopt_print_errors) + my_getopt_error_reporter(ERROR_LEVEL, + "%s: option '--%s' requires an argument", + my_progname, optp->name); + return EXIT_ARGUMENT_REQUIRED; + } + argument= *pos; + (*argc)--; + } + else + argument= optend; + } + else /* must be short option */ + { + for (optend= cur_arg; *optend; optend++) + { + opt_found= 0; + for (optp= longopts; optp->id; optp++) + { + if (optp->id == (int) (uchar) *optend) + { + /* Option recognized. Find next what to do with it */ + opt_found= 1; + if ((optp->var_type & GET_TYPE_MASK) == GET_DISABLED) + { + if (my_getopt_print_errors) + fprintf(stderr, + "%s: ERROR: Option '-%c' used, but is disabled\n", + my_progname, optp->id); + return EXIT_OPTION_DISABLED; + } + if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL && + optp->arg_type == NO_ARG) + { + *((my_bool*) optp->value)= (my_bool) 1; + if (get_one_option(optp->id, optp, argument)) + return EXIT_UNSPECIFIED_ERROR; + continue; + } + else if (optp->arg_type == REQUIRED_ARG || + optp->arg_type == OPT_ARG) + { + if (*(optend + 1)) + { + /* The rest of the option is option argument */ + argument= optend + 1; + /* This is in effect a jump out of the outer loop */ + optend= (char*) " "; + } + else + { + if (optp->arg_type == OPT_ARG) + { + if (optp->var_type == GET_BOOL) + *((my_bool*) optp->value)= (my_bool) 1; + if (get_one_option(optp->id, optp, argument)) + return EXIT_UNSPECIFIED_ERROR; + continue; + } + /* Check if there are more arguments after this one */ + if (!pos[1]) + { + if (my_getopt_print_errors) + my_getopt_error_reporter(ERROR_LEVEL, + "%s: option '-%c' requires an argument", + my_progname, optp->id); + return EXIT_ARGUMENT_REQUIRED; + } + argument= *++pos; + (*argc)--; + /* the other loop will break, because *optend + 1 == 0 */ + } + } + if ((error= setval(optp, optp->value, argument, + set_maximum_value))) + { + my_getopt_error_reporter(ERROR_LEVEL, + "%s: Error while setting value '%s' to '%s'", + my_progname, argument, optp->name); + return error; + } + if (get_one_option(optp->id, optp, argument)) + return EXIT_UNSPECIFIED_ERROR; + break; + } + } + if (!opt_found) + { + if (my_getopt_print_errors) + my_getopt_error_reporter(ERROR_LEVEL, + "%s: unknown option '-%c'", + my_progname, *optend); + return EXIT_UNKNOWN_OPTION; + } + } + (*argc)--; /* option handled (short), decrease argument count */ + continue; + } + if ((error= setval(optp, value, argument, set_maximum_value))) + { + my_getopt_error_reporter(ERROR_LEVEL, + "%s: Error while setting value '%s' to '%s'", + my_progname, argument, optp->name); + return error; + } + if (get_one_option(optp->id, optp, argument)) + return EXIT_UNSPECIFIED_ERROR; + + (*argc)--; /* option handled (short or long), decrease argument count */ + } + else /* non-option found */ + (*argv)[argvpos++]= cur_arg; + } + /* + Destroy the first, already handled option, so that programs that look + for arguments in 'argv', without checking 'argc', know when to stop. + Items in argv, before the destroyed one, are all non-option -arguments + to the program, yet to be (possibly) handled. + */ + (*argv)[argvpos]= 0; + return 0; +} + + +/* + function: check_struct_option + + Arguments: Current argument under processing from argv and a variable + where to store the possible key name. + + Return value: In case option is a struct option, returns a pointer to + the current argument at the position where the struct option (key_name) + ends, the next character after the dot. In case argument is not a struct + option, returns a pointer to the argument. + + key_name will hold the name of the key, or 0 if not found. +*/ + +static char *check_struct_option(char *cur_arg, char *key_name) +{ + char *ptr, *end; + + ptr= strcend(cur_arg + 1, '.'); /* Skip the first character */ + end= strcend(cur_arg, '='); + + /* + If the first dot is after an equal sign, then it is part + of a variable value and the option is not a struct option. + Also, if the last character in the string before the ending + NULL, or the character right before equal sign is the first + dot found, the option is not a struct option. + */ + if (end - ptr > 1) + { + uint len= (uint) (ptr - cur_arg); + set_if_smaller(len, FN_REFLEN-1); + strmake(key_name, cur_arg, len); + return ++ptr; + } + else + { + key_name[0]= 0; + return cur_arg; + } +} + +/* + function: setval + + Arguments: opts, argument + Will set the option value to given value +*/ + +static int setval(const struct my_option *opts, uchar* *value, char *argument, + my_bool set_maximum_value) +{ + int err= 0; + + if (value && argument) + { + uchar* *result_pos= ((set_maximum_value) ? + opts->u_max_value : value); + + if (!result_pos) + return EXIT_NO_PTR_TO_VARIABLE; + + switch ((opts->var_type & GET_TYPE_MASK)) { + case GET_BOOL: /* If argument differs from 0, enable option, else disable */ + *((my_bool*) result_pos)= (my_bool) atoi(argument) != 0; + break; + case GET_INT: + *((int*) result_pos)= (int) getopt_ll(argument, opts, &err); + break; + case GET_UINT: + *((uint*) result_pos)= (uint) getopt_ull(argument, opts, &err); + break; + case GET_LONG: + *((long*) result_pos)= (long) getopt_ll(argument, opts, &err); + break; + case GET_ULONG: + *((long*) result_pos)= (long) getopt_ull(argument, opts, &err); + break; + case GET_LL: + *((longlong*) result_pos)= getopt_ll(argument, opts, &err); + break; + case GET_ULL: + *((ulonglong*) result_pos)= getopt_ull(argument, opts, &err); + break; + case GET_DOUBLE: + *((double*) result_pos)= getopt_double(argument, opts, &err); + break; + case GET_STR: + *((char**) result_pos)= argument; + break; + case GET_STR_ALLOC: + if ((*((char**) result_pos))) + my_free((*(char**) result_pos), MYF(MY_WME | MY_FAE)); + if (!(*((char**) result_pos)= my_strdup(argument, MYF(MY_WME)))) + return EXIT_OUT_OF_MEMORY; + break; + case GET_ENUM: + if (((*(int*)result_pos)= find_type(argument, opts->typelib, 2) - 1) < 0) + return EXIT_ARGUMENT_INVALID; + break; + case GET_SET: + *((ulonglong*)result_pos)= find_typeset(argument, opts->typelib, &err); + if (err) + return EXIT_ARGUMENT_INVALID; + break; + default: /* dummy default to avoid compiler warnings */ + break; + } + if (err) + return EXIT_UNKNOWN_SUFFIX; + } + return 0; +} + + +/* + Find option + + SYNOPSIS + findopt() + optpat Prefix of option to find (with - or _) + length Length of optpat + opt_res Options + ffname Place for pointer to first found name + + IMPLEMENTATION + Go through all options in the my_option struct. Return number + of options found that match the pattern and in the argument + list the option found, if any. In case of ambiguous option, store + the name in ffname argument + + RETURN + 0 No matching options + # Number of matching options + ffname points to first matching option +*/ + +static int findopt(char *optpat, uint length, + const struct my_option **opt_res, + char **ffname) +{ + uint count; + struct my_option *opt= (struct my_option *) *opt_res; + + for (count= 0; opt->name; opt++) + { + if (!getopt_compare_strings(opt->name, optpat, length)) /* match found */ + { + (*opt_res)= opt; + if (!opt->name[length]) /* Exact match */ + return 1; + if (!count) + { + count= 1; + *ffname= (char *) opt->name; /* We only need to know one prev */ + } + else if (strcmp(*ffname, opt->name)) + { + /* + The above test is to not count same option twice + (see mysql.cc, option "help") + */ + count++; + } + } + } + return count; +} + + +/* + function: compare_strings + + Works like strncmp, other than 1.) considers '-' and '_' the same. + 2.) Returns -1 if strings differ, 0 if they are equal +*/ + +my_bool getopt_compare_strings(register const char *s, register const char *t, + uint length) +{ + char const *end= s + length; + for (;s != end ; s++, t++) + { + if ((*s != '-' ? *s : '_') != (*t != '-' ? *t : '_')) + return 1; + } + return 0; +} + +/* + function: eval_num_suffix + + Transforms a number with a suffix to real number. Suffix can + be k|K for kilo, m|M for mega or g|G for giga. +*/ + +static longlong eval_num_suffix(char *argument, int *error, char *option_name) +{ + char *endchar; + longlong num; + + *error= 0; + errno= 0; + num= strtoll(argument, &endchar, 10); + if (errno == ERANGE) + { + my_getopt_error_reporter(ERROR_LEVEL, + "Incorrect integer value: '%s'", argument); + *error= 1; + return 0; + } + if (*endchar == 'k' || *endchar == 'K') + num*= 1024L; + else if (*endchar == 'm' || *endchar == 'M') + num*= 1024L * 1024L; + else if (*endchar == 'g' || *endchar == 'G') + num*= 1024L * 1024L * 1024L; + else if (*endchar) + { + fprintf(stderr, + "Unknown suffix '%c' used for variable '%s' (value '%s')\n", + *endchar, option_name, argument); + *error= 1; + return 0; + } + return num; +} + +/* + function: getopt_ll + + Evaluates and returns the value that user gave as an argument + to a variable. Recognizes (case insensitive) K as KILO, M as MEGA + and G as GIGA bytes. Some values must be in certain blocks, as + defined in the given my_option struct, this function will check + that those values are honored. + In case of an error, set error value in *err. +*/ + +static longlong getopt_ll(char *arg, const struct my_option *optp, int *err) +{ + longlong num=eval_num_suffix(arg, err, (char*) optp->name); + return getopt_ll_limit_value(num, optp, NULL); +} + +/* + function: getopt_ll_limit_value + + Applies min/max/block_size to a numeric value of an option. + Returns "fixed" value. +*/ + +longlong getopt_ll_limit_value(longlong num, const struct my_option *optp, + my_bool *fix) +{ + longlong old= num; + my_bool adjusted= FALSE; + char buf1[255], buf2[255]; + ulonglong block_size= (optp->block_size ? (ulonglong) optp->block_size : 1L); + + if (num > 0 && ((ulonglong) num > (ulonglong) optp->max_value) && + optp->max_value) /* if max value is not set -> no upper limit */ + { + num= (ulonglong) optp->max_value; + adjusted= TRUE; + } + + switch ((optp->var_type & GET_TYPE_MASK)) { + case GET_INT: + if (num > (longlong) INT_MAX) + { + num= ((longlong) INT_MAX); + adjusted= TRUE; + } + break; + case GET_LONG: +#if SIZEOF_LONG < SIZEOF_LONG_LONG + if (num > (longlong) LONG_MAX) + { + num= ((longlong) LONG_MAX); + adjusted= TRUE; + } +#endif + break; + default: + DBUG_ASSERT((optp->var_type & GET_TYPE_MASK) == GET_LL); + break; + } + + num= ((num - optp->sub_size) / block_size); + num= (longlong) (num * block_size); + + if (num < optp->min_value) + { + num= optp->min_value; + if (old < optp->min_value) + adjusted= TRUE; + } + + if (fix) + *fix= adjusted; + else if (adjusted) + my_getopt_error_reporter(WARNING_LEVEL, + "option '%s': signed value %s adjusted to %s", + optp->name, llstr(old, buf1), llstr(num, buf2)); + return num; +} + +/* + function: getopt_ull + + This is the same as getopt_ll, but is meant for unsigned long long + values. +*/ + +static ulonglong getopt_ull(char *arg, const struct my_option *optp, int *err) +{ + ulonglong num= eval_num_suffix(arg, err, (char*) optp->name); + return getopt_ull_limit_value(num, optp, NULL); +} + + +ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp, + my_bool *fix) +{ + my_bool adjusted= FALSE; + ulonglong old= num; + char buf1[255], buf2[255]; + + if ((ulonglong) num > (ulonglong) optp->max_value && + optp->max_value) /* if max value is not set -> no upper limit */ + { + num= (ulonglong) optp->max_value; + adjusted= TRUE; + } + + switch ((optp->var_type & GET_TYPE_MASK)) { + case GET_UINT: + if (num > (ulonglong) UINT_MAX) + { + num= ((ulonglong) UINT_MAX); + adjusted= TRUE; + } + break; + case GET_ULONG: +#if SIZEOF_LONG < SIZEOF_LONG_LONG + if (num > (ulonglong) ULONG_MAX) + { + num= ((ulonglong) ULONG_MAX); + adjusted= TRUE; + } +#endif + break; + default: + DBUG_ASSERT((optp->var_type & GET_TYPE_MASK) == GET_ULL); + break; + } + + if (optp->block_size > 1) + { + num/= (ulonglong) optp->block_size; + num*= (ulonglong) optp->block_size; + } + + if (num < (ulonglong) optp->min_value) + { + num= (ulonglong) optp->min_value; + if (old < (ulonglong) optp->min_value) + adjusted= TRUE; + } + + if (fix) + *fix= adjusted; + else if (adjusted) + my_getopt_error_reporter(WARNING_LEVEL, + "option '%s': unsigned value %s adjusted to %s", + optp->name, ullstr(old, buf1), ullstr(num, buf2)); + return num; +} + + +/* + Get double value withing ranges + + Evaluates and returns the value that user gave as an argument to a variable. + + RETURN + decimal value of arg + + In case of an error, prints an error message and sets *err to + EXIT_ARGUMENT_INVALID. Otherwise err is not touched +*/ + +static double getopt_double(char *arg, const struct my_option *optp, int *err) +{ + double num; + int error; + char *end= arg + 1000; /* Big enough as *arg is \0 terminated */ + num= my_strtod(arg, &end, &error); + if (end[0] != 0 || error) + { + fprintf(stderr, + "%s: ERROR: Invalid decimal value for option '%s'\n", + my_progname, optp->name); + *err= EXIT_ARGUMENT_INVALID; + return 0.0; + } + if (optp->max_value && num > (double) optp->max_value) + num= (double) optp->max_value; + return max(num, (double) optp->min_value); +} + +/* + Init one value to it's default values + + SYNOPSIS + init_one_value() + option Option to initialize + value Pointer to variable +*/ + +static void init_one_value(const struct my_option *option, uchar* *variable, + longlong value) +{ + DBUG_ENTER("init_one_value"); + switch ((option->var_type & GET_TYPE_MASK)) { + case GET_BOOL: + *((my_bool*) variable)= (my_bool) value; + break; + case GET_INT: + *((int*) variable)= (int) getopt_ll_limit_value((int) value, option, NULL); + break; + case GET_ENUM: + *((uint*) variable)= (uint) value; + break; + case GET_UINT: + *((uint*) variable)= (uint) getopt_ull_limit_value((uint) value, option, NULL); + break; + case GET_LONG: + *((long*) variable)= (long) getopt_ll_limit_value((long) value, option, NULL); + break; + case GET_ULONG: + *((ulong*) variable)= (ulong) getopt_ull_limit_value((ulong) value, option, NULL); + break; + case GET_LL: + *((longlong*) variable)= (longlong) getopt_ll_limit_value((longlong) value, option, NULL); + break; + case GET_ULL: /* Fall through */ + case GET_SET: + *((ulonglong*) variable)= (ulonglong) getopt_ull_limit_value((ulonglong) value, option, NULL); + break; + case GET_DOUBLE: + *((double*) variable)= (double) value; + break; + case GET_STR: + /* + Do not clear variable value if it has no default value. + The default value may already be set. + NOTE: To avoid compiler warnings, we first cast longlong to intptr, + so that the value has the same size as a pointer. + */ + if ((char*) (intptr) value) + *((char**) variable)= (char*) (intptr) value; + break; + case GET_STR_ALLOC: + /* + Do not clear variable value if it has no default value. + The default value may already be set. + NOTE: To avoid compiler warnings, we first cast longlong to intptr, + so that the value has the same size as a pointer. + */ + if ((char*) (intptr) value) + { + my_free((*(char**) variable), MYF(MY_ALLOW_ZERO_PTR)); + *((char**) variable)= my_strdup((char*) (intptr) value, MYF(MY_WME)); + } + break; + default: /* dummy default to avoid compiler warnings */ + break; + } + DBUG_VOID_RETURN; +} + + +/* + Init one value to it's default values + + SYNOPSIS + init_one_value() + option Option to initialize + value Pointer to variable +*/ + +static void fini_one_value(const struct my_option *option, uchar* *variable, + longlong value __attribute__ ((unused))) +{ + DBUG_ENTER("fini_one_value"); + switch ((option->var_type & GET_TYPE_MASK)) { + case GET_STR_ALLOC: + my_free((*(char**) variable), MYF(MY_ALLOW_ZERO_PTR)); + *((char**) variable)= NULL; + break; + default: /* dummy default to avoid compiler warnings */ + break; + } + DBUG_VOID_RETURN; +} + + +void my_cleanup_options(const struct my_option *options) +{ + init_variables(options, fini_one_value); +} + + +/* + initialize all variables to their default values + + SYNOPSIS + init_variables() + options Array of options + + NOTES + We will initialize the value that is pointed to by options->value. + If the value is of type GET_ASK_ADDR, we will also ask for the address + for a value and initialize. +*/ + +static void init_variables(const struct my_option *options, + init_func_p init_one_value) +{ + DBUG_ENTER("init_variables"); + for (; options->name; options++) + { + uchar* *variable; + DBUG_PRINT("options", ("name: '%s'", options->name)); + /* + We must set u_max_value first as for some variables + options->u_max_value == options->value and in this case we want to + set the value to default value. + */ + if (options->u_max_value) + init_one_value(options, options->u_max_value, options->max_value); + if (options->value) + init_one_value(options, options->value, options->def_value); + if (options->var_type & GET_ASK_ADDR && + (variable= (*getopt_get_addr)("", 0, options, 0))) + init_one_value(options, variable, options->def_value); + } + DBUG_VOID_RETURN; +} + + +/* + function: my_print_options + + Print help for all options and variables. +*/ + +void my_print_help(const struct my_option *options) +{ + uint col, name_space= 22, comment_space= 57; + const char *line_end; + const struct my_option *optp; + + for (optp= options; optp->id; optp++) + { + if (optp->id < 256) + { + printf(" -%c%s", optp->id, strlen(optp->name) ? ", " : " "); + col= 6; + } + else + { + printf(" "); + col= 2; + } + if (strlen(optp->name)) + { + printf("--%s", optp->name); + col+= 2 + (uint) strlen(optp->name); + if ((optp->var_type & GET_TYPE_MASK) == GET_STR || + (optp->var_type & GET_TYPE_MASK) == GET_STR_ALLOC) + { + printf("%s=name%s ", optp->arg_type == OPT_ARG ? "[" : "", + optp->arg_type == OPT_ARG ? "]" : ""); + col+= (optp->arg_type == OPT_ARG) ? 8 : 6; + } + else if ((optp->var_type & GET_TYPE_MASK) == GET_NO_ARG || + (optp->var_type & GET_TYPE_MASK) == GET_BOOL) + { + putchar(' '); + col++; + } + else + { + printf("%s=#%s ", optp->arg_type == OPT_ARG ? "[" : "", + optp->arg_type == OPT_ARG ? "]" : ""); + col+= (optp->arg_type == OPT_ARG) ? 5 : 3; + } + if (col > name_space && optp->comment && *optp->comment) + { + putchar('\n'); + col= 0; + } + } + for (; col < name_space; col++) + putchar(' '); + if (optp->comment && *optp->comment) + { + const char *comment= optp->comment, *end= strend(comment); + + while ((uint) (end - comment) > comment_space) + { + for (line_end= comment + comment_space; + *line_end != ' ' && line_end > comment; + line_end--); + if (line_end == comment) + { + /* There was no space, try to find one going forward */ + for (line_end= comment + comment_space; + *line_end != ' ' && line_end < end; + line_end++); + } + for (; comment != line_end; comment++) + putchar(*comment); + if (comment < end) + { + comment++; /* skip the space, as a newline will take it's place now */ + putchar('\n'); + for (col= 0; col < name_space; col++) + putchar(' '); + } + } + printf("%s", comment); + } + putchar('\n'); + if ((optp->var_type & GET_TYPE_MASK) == GET_NO_ARG || + (optp->var_type & GET_TYPE_MASK) == GET_BOOL) + { + if (optp->def_value != 0) + { + printf("%*s(Defaults to on; use --skip-%s to disable.)\n", name_space, "", optp->name); + } + } + } +} + + +/* + function: my_print_options + + Print variables. +*/ + +void my_print_variables(const struct my_option *options) +{ + uint name_space= 34, length, nr; + ulonglong bit, llvalue; + char buff[255]; + const struct my_option *optp; + + printf("\nVariables (--variable-name=value)\n"); + printf("and boolean options {FALSE|TRUE} Value (after reading options)\n"); + printf("--------------------------------- -----------------------------\n"); + for (optp= options; optp->id; optp++) + { + uchar* *value= (optp->var_type & GET_ASK_ADDR ? + (*getopt_get_addr)("", 0, optp, 0) : optp->value); + if (value) + { + printf("%s ", optp->name); + length= (uint) strlen(optp->name)+1; + for (; length < name_space; length++) + putchar(' '); + switch ((optp->var_type & GET_TYPE_MASK)) { + case GET_SET: + if (!(llvalue= *(ulonglong*) value)) + printf("%s\n", "(No default value)"); + else + for (nr= 0, bit= 1; llvalue && nr < optp->typelib->count; nr++, bit<<=1) + { + if (!(bit & llvalue)) + continue; + llvalue&= ~bit; + printf( llvalue ? "%s," : "%s\n", get_type(optp->typelib, nr)); + } + break; + case GET_ENUM: + printf("%s\n", get_type(optp->typelib, *(uint*) value)); + break; + case GET_STR: + case GET_STR_ALLOC: /* fall through */ + printf("%s\n", *((char**) value) ? *((char**) value) : + "(No default value)"); + break; + case GET_BOOL: + printf("%s\n", *((my_bool*) value) ? "TRUE" : "FALSE"); + break; + case GET_INT: + printf("%d\n", *((int*) value)); + break; + case GET_UINT: + printf("%d\n", *((uint*) value)); + break; + case GET_LONG: + printf("%ld\n", *((long*) value)); + break; + case GET_ULONG: + printf("%lu\n", *((ulong*) value)); + break; + case GET_LL: + printf("%s\n", llstr(*((longlong*) value), buff)); + break; + case GET_ULL: + longlong2str(*((ulonglong*) value), buff, 10); + printf("%s\n", buff); + break; + case GET_DOUBLE: + printf("%g\n", *(double*) value); + break; + default: + printf("(Disabled)\n"); + break; + } + } + } +} |