diff options
Diffstat (limited to 'mysql/mysys_ssl/my_getopt.cpp')
-rw-r--r-- | mysql/mysys_ssl/my_getopt.cpp | 1615 |
1 files changed, 0 insertions, 1615 deletions
diff --git a/mysql/mysys_ssl/my_getopt.cpp b/mysql/mysys_ssl/my_getopt.cpp deleted file mode 100644 index 40ae171..0000000 --- a/mysql/mysys_ssl/my_getopt.cpp +++ /dev/null @@ -1,1615 +0,0 @@ -/* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved. - - 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, - 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */ - -#include <my_global.h> -#include <m_string.h> -#include <stdlib.h> -#include <mysys_err.h> -#include <my_getopt.h> -#include <errno.h> -#include <m_string.h> -#include "my_default.h" -#include <m_ctype.h> -#include "../mysys/mysys_priv.h" - -typedef void (*init_func_p)(const struct my_option *option, void *variable, - longlong value); - -my_error_reporter my_getopt_error_reporter= &my_message_local; - -static bool findopt(char *, uint, const struct my_option **); -my_bool getopt_compare_strings(const char *, const char *, uint); -static longlong getopt_ll(char *arg, const struct my_option *optp, int *err); -static ulonglong getopt_ull(char *, const struct my_option *, int *); -static double getopt_double(char *arg, const struct my_option *optp, int *err); -static void init_variables(const struct my_option *, init_func_p); -static void init_one_value(const struct my_option *, void *, longlong); -static void fini_one_value(const struct my_option *, void *, longlong); -static int setval(const struct my_option *, void *, char *, my_bool); -static char *check_struct_option(char *cur_arg, char *key_name); -static my_bool get_bool_argument(const struct my_option *opts, - const char *argument, - bool *error); - -/* - 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"; -char *enabled_my_option= (char*) "1"; - -/* - 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 my_getopt_value getopt_get_addr; - -void my_getopt_register_get_addr(my_getopt_value func_addr) -{ - getopt_get_addr= func_addr; -} - - -/** - Wrapper around my_handle_options() for interface compatibility. - - @param argc [in, out] Command line options (count) - @param argv [in, out] Command line options (values) - @param longopts [in] Descriptor of all valid options - @param get_one_option [in] Optional callback function to process each option, - can be NULL. - - @return Error in case of ambiguous or unknown options, - 0 on success. -*/ -int handle_options(int *argc, char ***argv, - const struct my_option *longopts, - my_get_one_option get_one_option) -{ - return my_handle_options(argc, argv, longopts, get_one_option, NULL, FALSE); -} - -union ull_dbl -{ - ulonglong ull; - double dbl; -}; - -/** - Returns an ulonglong value containing a raw - representation of the given double value. -*/ -ulonglong getopt_double2ulonglong(double v) -{ - union ull_dbl u; - u.dbl= v; - compile_time_assert(sizeof(ulonglong) >= sizeof(double)); - return u.ull; -} - -/** - Returns the double value which corresponds to - the given raw representation. -*/ -double getopt_ulonglong2double(ulonglong v) -{ - union ull_dbl u; - u.ull= v; - return u.dbl; -} - -/** - Handle command line options. - Sort options. - Put options first, until special end of options (--), - or until the end of argv. Parse options, check that the given option - matches with one of the options in struct 'my_option'. - Check that option was given an argument if it requires one - Call the optional 'get_one_option()' function once for each option. - - Note that handle_options() can be invoked multiple times to - parse a command line in several steps. - In this case, use the global flag @c my_getopt_skip_unknown to indicate - that options unknown in the current step should be preserved in the - command line for later parsing in subsequent steps. - - For 'long' options (--a_long_option), @c my_getopt_skip_unknown is - fully supported. Command line parameters such as: - - "--a_long_option" - - "--a_long_option=value" - - "--a_long_option value" - will be preserved as is when the option is not known. - - For 'short' options (-S), support for @c my_getopt_skip_unknown - comes with some limitation, because several short options - can also be specified together in the same command line argument, - as in "-XYZ". - - The first use case supported is: all short options are declared. - handle_options() will be able to interpret "-XYZ" as one of: - - an unknown X option - - "-X -Y -Z", three short options with no arguments - - "-X -YZ", where Y is a short option with argument Z - - "-XYZ", where X is a short option with argument YZ - based on the full short options specifications. - - The second use case supported is: no short option is declared. - handle_options() will reject "-XYZ" as unknown, to be parsed later. - - The use case that is explicitly not supported is to provide - only a partial list of short options to handle_options(). - This function can not be expected to extract some option Y - in the middle of the string "-XYZ" in these conditions, - without knowing if X will be declared an option later. - - Note that this limitation only impacts parsing of several - short options from the same command line argument, - as in "mysqld -anW5". - When each short option is properly separated out in the command line - argument, for example in "mysqld -a -n -w5", the code would actually - work even with partial options specs given at each stage. - - @param [in, out] argc command line options (count) - @param [in, out] argv command line options (values) - @param [in] longopts descriptor of all valid options - @param [in] get_one_option optional callback function to process each option, - can be NULL. - @param [in] command_list NULL-terminated list of strings (commands) which - (if set) is looked up for all non-option strings - found while parsing the command line parameters. - The parsing terminates if a match is found. At - exit, argv [out] would contain all the remaining - unparsed options along with the matched command. - - @param [in] ignore_unknown_option When set to TRUE, options are continued to - be read even when unknown options are - encountered. - - @return error in case of ambiguous or unknown options, - 0 on success. -*/ -int my_handle_options(int *argc, char ***argv, - const struct my_option *longopts, - my_get_one_option get_one_option, - const char **command_list, my_bool ignore_unknown_option) -{ - uint argvpos= 0, length; - my_bool end_of_options= 0, must_be_var, set_maximum_value, - option_is_loose; - char **pos, **pos_end, *optend, *opt_str, key_name[FN_REFLEN]; - const struct my_option *optp; - void *value; - int error, i; - my_bool is_cmdline_arg= 1; - bool 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 (my_getopt_is_args_separator(*pos)) - { - is_cmdline_arg= 0; - break; - } - } - - for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++) - { - char **first= pos; - char *cur_arg= *pos; - opt_found= false; - if (!is_cmdline_arg && (my_getopt_is_args_separator(cur_arg))) - { - 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 == '-') /* check for long option, */ - { - 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 - */ - optp= longopts; - if (!(opt_found= findopt(opt_str, length, &optp))) - { - /* - 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))) - { - 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))) ? - enabled_my_option : disabled_my_option; - break; - case OPT_ENABLE: - optend= (optend && *optend == '0' && !(*(optend + 1))) ? - disabled_my_option : enabled_my_option; - 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. */ - 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, - "unknown variable '%s'", 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, - "unknown option '--%s'", cur_arg); - if (!(option_is_loose || ignore_unknown_option)) - return EXIT_UNKNOWN_OPTION; - } - if (option_is_loose || ignore_unknown_option) - { - (*argc)--; - continue; - } - } - } - if ((optp->var_type & GET_TYPE_MASK) == GET_DISABLED) - { - if (my_getopt_print_errors) - my_message_local(option_is_loose ? WARNING_LEVEL : ERROR_LEVEL, - "%s: Option '%s' used, but is disabled", - my_progname, opt_str); - if (option_is_loose) - { - (*argc)--; - continue; - } - return EXIT_OPTION_DISABLED; - } - error= 0; - value= optp->var_type & GET_ASK_ADDR ? - (*getopt_get_addr)(key_name, strlen(key_name), optp, &error) : - optp->value; - if (error) - return error; - - if (optp->arg_type == NO_ARG) - { - /* - Due to historical reasons GET_BOOL var_types still accepts arguments - despite the NO_ARG arg_type attribute. This can seems a bit unintuitive - and care should be taken when refactoring this code. - */ - 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) - *((my_bool*) value)= (my_bool) 1; - else - { - my_bool ret= 0; - bool error= 0; - ret= get_bool_argument(optp, optend, &error); - if(error) - { - my_getopt_error_reporter(WARNING_LEVEL, - "%s: ignoring option '--%s' " - "due to invalid value '%s'", - my_progname, optp->name, optend); - continue; - } - else - *((my_bool*) value)= ret; - } - if (get_one_option && get_one_option(optp->id, optp, - *((my_bool*) value) ? - enabled_my_option : disabled_my_option)) - return EXIT_ARGUMENT_INVALID; - continue; - } - 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; - - if (optp->var_type == GET_PASSWORD && is_cmdline_arg && argument) - print_cmdline_password_warning(); - } - else /* must be short option */ - { - for (optend= cur_arg; *optend; optend++) - { - opt_found= false; - for (optp= longopts; optp->name; optp++) - { - if (optp->id && optp->id == (int) (uchar) *optend) - { - /* Option recognized. Find next what to do with it */ - opt_found= true; - if ((optp->var_type & GET_TYPE_MASK) == GET_DISABLED) - { - if (my_getopt_print_errors) - my_message_local(ERROR_LEVEL, - "%s: Option '-%c' used, but is disabled", - 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 && 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*) " "; - if (optp->var_type == GET_PASSWORD && is_cmdline_arg) - print_cmdline_password_warning(); - } - else - { - if (optp->arg_type == OPT_ARG) - { - if (optp->var_type == GET_BOOL) - *((my_bool*) optp->value)= (my_bool) 1; - if (get_one_option && 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))) - return error; - if (get_one_option && get_one_option(optp->id, optp, argument)) - return EXIT_UNSPECIFIED_ERROR; - break; - } - } - if (!opt_found) - { - if (my_getopt_skip_unknown) - { - /* - We are currently parsing a single argv[] argument - of the form "-XYZ". - One or the argument found (say Y) is not an option. - Hack the string "-XYZ" to make a "-YZ" substring in it, - and push that to the output as an unrecognized parameter. - */ - DBUG_ASSERT(optend > *pos); - DBUG_ASSERT(optend >= cur_arg); - DBUG_ASSERT(optend <= *pos + strlen(*pos)); - DBUG_ASSERT(*optend); - optend--; - optend[0]= '-'; /* replace 'X' or '-' by '-' */ - (*argv)[argvpos++]= optend; - /* - Do not continue to parse at the current "-XYZ" argument, - skip to the next argv[] argument instead. - */ - optend= (char*) " "; - } - else - { - if (my_getopt_print_errors) - my_getopt_error_reporter(ERROR_LEVEL, - "%s: unknown option '-%c'", - my_progname, *optend); - return EXIT_UNKNOWN_OPTION; - } - } - } - if (opt_found) - (*argc)--; /* option handled (short), decrease argument count */ - continue; - } - if ((error= setval(optp, value, argument, set_maximum_value))) - return error; - if (get_one_option && get_one_option(optp->id, optp, argument)) - return EXIT_UNSPECIFIED_ERROR; - - (*argc)--; /* option handled (long), decrease argument count */ - } - else /* non-option found */ - { - if (command_list) - { - while (* command_list) - { - if (!strcmp(*command_list, cur_arg)) - { - /* Match found. */ - (*argv)[argvpos ++]= cur_arg; - - /* Copy rest of the un-parsed elements & return. */ - while ((++ pos) != pos_end) - (*argv)[argvpos ++]= *pos; - goto done; - } - command_list ++; - } - } - (*argv)[argvpos ++]= cur_arg; - } - } - -done: - /* - 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; -} - - -/** - * This function should be called to print a warning message - * if password string is specified on the command line. - */ - -void print_cmdline_password_warning() -{ - static my_bool password_warning_announced= FALSE; - - if (!password_warning_announced) - { - my_message_local(WARNING_LEVEL, "Using a password on the command line " - "interface can be insecure."); - password_warning_announced= TRUE; - } -} - - -/** - @brief Check for struct options - - @param[in] cur_arg Current argument under processing from argv - @param[in] key_name variable where to store the possible key name - - @details - 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. - - @return char* - If struct option Pointer to next character after dot. - If no struct option Pointer to the argument -*/ - -static char *check_struct_option(char *cur_arg, char *key_name) -{ - char *dot_pos, *equal_pos, *space_pos; - - dot_pos= strcend(cur_arg + 1, '.'); /* Skip the first character */ - equal_pos= strcend(cur_arg, '='); - space_pos= 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 ((equal_pos > dot_pos) && (space_pos > dot_pos)) - { - size_t len= (uint) (dot_pos - cur_arg); - set_if_smaller(len, FN_REFLEN-1); - strmake(key_name, cur_arg, len); - return ++dot_pos; - } - else - { - key_name[0]= 0; - return cur_arg; - } -} - - -/** - Parse a boolean command line argument - - "ON", "TRUE" and "1" will return true, - other values will return false. - - @param[in] argument The value argument - @return boolean value -*/ -static my_bool get_bool_argument(const struct my_option *opts, - const char *argument, - bool *error) -{ - if (!my_strcasecmp(&my_charset_latin1, argument, "true") || - !my_strcasecmp(&my_charset_latin1, argument, "on") || - !my_strcasecmp(&my_charset_latin1, argument, "1")) - return 1; - else if (!my_strcasecmp(&my_charset_latin1, argument, "false") || - !my_strcasecmp(&my_charset_latin1, argument, "off") || - !my_strcasecmp(&my_charset_latin1, argument, "0")) - return 0; - else - *error= 1; - return 0; -} - -/* - function: setval - - Arguments: opts, argument - Will set the option value to given value -*/ - -static int setval(const struct my_option *opts, void *value, char *argument, - my_bool set_maximum_value) -{ - int err= 0, res= 0; - bool error= 0; - ulong var_type= opts->var_type & GET_TYPE_MASK; - - if (!argument) - argument= enabled_my_option; - - /* - Thus check applies only to options that have a defined value - storage pointer. - We do it for numeric types only, as empty value is a valid - option for strings (the only way to reset back to default value). - Note: it does not relate to OPT_ARG/REQUIRED_ARG/NO_ARG, since - --param="" is not generally the same as --param. - TODO: Add an option definition flag to signify whether empty value - (i.e. --param="") is an acceptable value or an error and extend - the check to all options. - */ - if (!*argument && - ( - var_type == GET_INT || - var_type == GET_UINT || - var_type == GET_LONG || - var_type == GET_ULONG || - var_type == GET_LL || - var_type == GET_ULL || - var_type == GET_DOUBLE || - var_type == GET_ENUM - ) - ) - { - if (strncmp(opts->name, "port", 10) == 0) - { - my_getopt_error_reporter(WARNING_LEVEL, - "%s: Empty value for '%s' specified. Will throw an error in future versions", - my_progname, opts->name); - } - else - { - my_getopt_error_reporter(ERROR_LEVEL, - "%s: Empty value for '%s' specified", - my_progname, opts->name); - return EXIT_ARGUMENT_REQUIRED; - } - } - - if (value) - { - if (set_maximum_value && !(value= opts->u_max_value)) - { - my_getopt_error_reporter(ERROR_LEVEL, - "%s: Maximum value of '%s' cannot be set", - my_progname, opts->name); - return EXIT_NO_PTR_TO_VARIABLE; - } - - switch (var_type) { - case GET_BOOL: /* If argument differs from 0, enable option, else disable */ - *((my_bool*) value)= get_bool_argument(opts, argument, &error); - if(error) - my_getopt_error_reporter(WARNING_LEVEL, - "option '%s': boolean value '%s' wasn't recognized. Set to OFF.", - opts->name, argument); - break; - case GET_INT: - *((int*) value)= (int) getopt_ll(argument, opts, &err); - break; - case GET_UINT: - *((uint*) value)= (uint) getopt_ull(argument, opts, &err); - break; - case GET_LONG: - *((long*) value)= (long) getopt_ll(argument, opts, &err); - break; - case GET_ULONG: - *((long*) value)= (long) getopt_ull(argument, opts, &err); - break; - case GET_LL: - *((longlong*) value)= getopt_ll(argument, opts, &err); - break; - case GET_ULL: - *((ulonglong*) value)= getopt_ull(argument, opts, &err); - break; - case GET_DOUBLE: - *((double*) value)= getopt_double(argument, opts, &err); - break; - case GET_STR: - case GET_PASSWORD: - if (argument == enabled_my_option) - break; /* string options don't use this default of "1" */ - *((char**) value)= argument; - break; - case GET_STR_ALLOC: - if (argument == enabled_my_option) - break; /* string options don't use this default of "1" */ - my_free(*((char**) value)); - if (!(*((char**) value)= my_strdup(key_memory_defaults, - argument, MYF(MY_WME)))) - { - res= EXIT_OUT_OF_MEMORY; - goto ret; - }; - break; - case GET_ENUM: - { - int type= find_type(argument, opts->typelib, FIND_TYPE_BASIC); - if (type == 0) - { - /* - Accept an integer representation of the enumerated item. - */ - char *endptr; - ulong arg= strtoul(argument, &endptr, 10); - if (*endptr || arg >= opts->typelib->count) - { - res= EXIT_ARGUMENT_INVALID; - goto ret; - } - *(ulong*)value= arg; - } - else if (type < 0) - { - res= EXIT_AMBIGUOUS_OPTION; - goto ret; - } - else - *(ulong*)value= type - 1; - } - break; - case GET_SET: - *((ulonglong*)value)= find_typeset(argument, opts->typelib, &err); - if (err) - { - /* Accept an integer representation of the set */ - char *endptr; - ulonglong arg= (ulonglong) strtol(argument, &endptr, 10); - if (*endptr || (arg >> 1) >= (1ULL << (opts->typelib->count-1))) - { - res= EXIT_ARGUMENT_INVALID; - goto ret; - }; - *(ulonglong*)value= arg; - err= 0; - } - break; - case GET_FLAGSET: - { - char *error; - uint error_len; - - *((ulonglong*)value)= - find_set_from_flags(opts->typelib, opts->typelib->count, - *(ulonglong *)value, opts->def_value, - argument, (uint)strlen(argument), - &error, &error_len); - if (error) - { - res= EXIT_ARGUMENT_INVALID; - goto ret; - }; - } - break; - case GET_NO_ARG: /* get_one_option has taken care of the value already */ - default: /* dummy default to avoid compiler warnings */ - break; - } - if (err) - { - res= EXIT_UNKNOWN_SUFFIX; - goto ret; - }; - } - return 0; - -ret: - my_getopt_error_reporter(ERROR_LEVEL, - "%s: Error while setting value '%s' to '%s'", - my_progname, argument, opts->name); - return res; -} - - -/** - Find option - - IMPLEMENTATION - Go through all options in the my_option struct. Return true - if an option is found. sets opt_res to the option found, if any. - - @param optpat name of option to find (with - or _) - @param length Length of optpat - @param[in,out] opt_res Options - - @retval false No matching options - @retval true Found an option -*/ - -static bool findopt(char *optpat, uint length, - const struct my_option **opt_res) -{ - for (const struct my_option *opt= *opt_res; opt->name; opt++) - if (!getopt_compare_strings(opt->name, optpat, length) && - !opt->name[length]) - { - (*opt_res)= opt; - return true; - } - return false; -} - - -/* - 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(const char *s, 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= my_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) - { - my_message_local(ERROR_LEVEL, - "Unknown suffix '%c' used for variable '%s' (value '%s')", - *endchar, option_name, argument); - *error= 1; - return 0; - } - return num; -} - -/** - function: eval_num_suffix_ull - This is the same as eval_num_suffix, but is meant for unsigned long long - values. Transforms an unsigned number with a suffix to real number. Suffix can - be k|K for kilo, m|M for mega or g|G for giga. - @param [IN] argument argument value for option_name - @param [IN, OUT] error error no. - @param [IN] option_name name of option -*/ - -static ulonglong eval_num_suffix_ull(char *argument, int *error, char *option_name) -{ - char *endchar; - ulonglong num; - - *error= 0; - errno= 0; - num= my_strtoull(argument, &endchar, 10); - if (errno == ERANGE) - { - my_getopt_error_reporter(ERROR_LEVEL, - "Incorrect unsigned 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) - { - my_message_local(ERROR_LEVEL, - "Unknown suffix '%c' used for variable '%s' (value '%s')", - *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); -} - - -/** - Maximum possible value for an integer GET_* variable type - @param var_type type of integer variable (GET_*) - @returns maximum possible value for this type - */ -ulonglong max_of_int_range(int var_type) -{ - switch (var_type) - { - case GET_INT: - return INT_MAX; - case GET_LONG: - return LONG_MAX; - case GET_LL: - return LLONG_MAX; - case GET_UINT: - return UINT_MAX; - case GET_ULONG: - return ULONG_MAX; - case GET_ULL: - return ULLONG_MAX; - default: - DBUG_ASSERT(0); - return 0; - } -} - - -/* - 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); - const longlong max_of_type= - (longlong)max_of_int_range(optp->var_type & GET_TYPE_MASK); - - 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; - } - - if (num > max_of_type) - { - num= max_of_type; - adjusted= TRUE; - } - - num= (num / 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= old != num; - 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; -} - -static inline my_bool is_negative_num(char* num) -{ - while (my_isspace(&my_charset_latin1, *num)) - num++; - - 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) -{ - char buf[255]; - ulonglong num; - - /* If a negative number is specified as a value for the option. */ - if (arg == NULL || is_negative_num(arg) == TRUE) - { - num= (ulonglong) optp->min_value; - my_getopt_error_reporter(WARNING_LEVEL, - "option '%s': value %s adjusted to %s", - optp->name, arg, ullstr(num, buf)); - } - else - num= eval_num_suffix_ull(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]; - const ulonglong max_of_type= - max_of_int_range(optp->var_type & GET_TYPE_MASK); - - if (num > (ulonglong) optp->max_value && - optp->max_value) /* if max value is not set -> no upper limit */ - { - num= (ulonglong) optp->max_value; - adjusted= TRUE; - } - - if (num > max_of_type) - { - num= max_of_type; - adjusted= TRUE; - } - - 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= old != num; - 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; -} - -double getopt_double_limit_value(double num, const struct my_option *optp, - my_bool *fix) -{ - my_bool adjusted= FALSE; - double old= num; - double min, max; - - max= getopt_ulonglong2double(optp->max_value); - min= getopt_ulonglong2double(optp->min_value); - if (max && num > max) - { - num= max; - adjusted= TRUE; - } - if (num < min) - { - num= min; - adjusted= TRUE; - } - if (fix) - *fix= adjusted; - else if (adjusted) - my_getopt_error_reporter(WARNING_LEVEL, - "option '%s': value %g adjusted to %g", - optp->name, old, num); - 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) - { - my_getopt_error_reporter(ERROR_LEVEL, - "Invalid decimal value for option '%s'\n", optp->name); - *err= EXIT_ARGUMENT_INVALID; - return 0.0; - } - return getopt_double_limit_value(num, optp, NULL); -} - -/* - 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, void *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: - *((ulong*) variable)= (ulong) 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)= getopt_ll_limit_value(value, option, NULL); - break; - case GET_ULL: - *((ulonglong*) variable)= getopt_ull_limit_value((ulonglong) value, option, NULL); - break; - case GET_SET: - case GET_FLAGSET: - *((ulonglong*) variable)= (ulonglong) value; - break; - case GET_DOUBLE: - *((double*) variable)= getopt_ulonglong2double(value); - break; - case GET_STR: - case GET_PASSWORD: - /* - 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) - { - char **pstr= (char **) variable; - my_free(*pstr); - *pstr= my_strdup(key_memory_defaults, - (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, void *variable, - longlong value MY_ATTRIBUTE ((unused))) -{ - DBUG_ENTER("fini_one_value"); - switch ((option->var_type & GET_TYPE_MASK)) { - case GET_STR_ALLOC: - my_free(*((char**) variable)); - *((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 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++) - { - void *value; - 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); - value= (options->var_type & GET_ASK_ADDR ? - (*getopt_get_addr)("", 0, options, 0) : options->value); - if (value) - init_one_value(options, value, options->def_value); - } - DBUG_VOID_RETURN; -} - -/** - Prints variable or option name, replacing _ with - to given file stream - parameter (by default to stdout). - @param [IN] optp my_option parameter - @param [IN] file stream where the output of optp parameter name - goes (by default to stdout). -*/ -static uint print_name(const struct my_option *optp, FILE* file = stdout) -{ - const char *s= optp->name; - for (;*s;s++) - putc(*s == '_' ? '-' : *s, file); - return s - optp->name; -} - -/* - 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->name; optp++) - { - if (optp->id && optp->id < 256) - { - printf(" -%c%s", optp->id, strlen(optp->name) ? ", " : " "); - col= 6; - } - else - { - printf(" "); - col= 2; - } - if (strlen(optp->name)) - { - printf("--"); - col+= 2 + print_name(optp); - if (optp->arg_type == NO_ARG || - (optp->var_type & GET_TYPE_MASK) == GET_BOOL) - { - putchar(' '); - col++; - } - else if ((optp->var_type & GET_TYPE_MASK) == GET_STR || - (optp->var_type & GET_TYPE_MASK) == GET_PASSWORD || - (optp->var_type & GET_TYPE_MASK) == GET_STR_ALLOC || - (optp->var_type & GET_TYPE_MASK) == GET_ENUM || - (optp->var_type & GET_TYPE_MASK) == GET_SET || - (optp->var_type & GET_TYPE_MASK) == GET_FLAGSET ) - { - printf("%s=name%s ", optp->arg_type == OPT_ARG ? "[" : "", - optp->arg_type == OPT_ARG ? "]" : ""); - col+= (optp->arg_type == OPT_ARG) ? 8 : 6; - } - 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--) - {} - for (; comment != line_end; comment++) - putchar(*comment); - 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_BOOL) - { - if (optp->def_value != 0) - { - printf("%*s(Defaults to on; use --skip-", name_space, ""); - print_name(optp); - printf(" to disable.)\n"); - } - } - } -} - -/** - function: my_print_variables - Print variables. - @param [IN] options my_option list -*/ -void my_print_variables(const struct my_option *options) -{ - my_print_variables_ex(options, stdout); -} - -/** - function: my_print_variables_ex - Print variables to given file parameter stream (by default to stdout). - @param [IN] options my_options list - @param [IN] file stream where the output goes. -*/ - -void my_print_variables_ex(const struct my_option *options, FILE* file) -{ - uint name_space= 34, nr; - size_t length; - ulonglong llvalue; - char buff[255]; - const struct my_option *optp; - - for (optp= options; optp->name; optp++) - { - length= strlen(optp->name)+1; - if (length > name_space) - name_space= length; - } - - fprintf(file, "\nVariables (--variable-name=value)\n"); - fprintf(file, "%-*s%s", name_space, "and boolean options {FALSE|TRUE}", - "Value (after reading options)\n"); - for (length=1; length < 75; length++) - putc(length == name_space ? ' ' : '-', file); - putc('\n', file); - - for (optp= options; optp->name; optp++) - { - void *value= (optp->var_type & GET_ASK_ADDR ? - (*getopt_get_addr)("", 0, optp, 0) : optp->value); - if (value) - { - length= print_name(optp, file); - for (; length < name_space; length++) - putc(' ', file); - switch ((optp->var_type & GET_TYPE_MASK)) { - case GET_SET: - if (!(llvalue= *(ulonglong*) value)) - fprintf(file, "%s\n", ""); - else - for (nr= 0; llvalue && nr < optp->typelib->count; nr++, llvalue >>=1) - { - if (llvalue & 1) - fprintf(file, llvalue > 1 ? "%s," : "%s\n", - get_type(optp->typelib, nr)); - } - break; - case GET_FLAGSET: - llvalue= *(ulonglong*) value; - for (nr= 0; llvalue && nr < optp->typelib->count; nr++, llvalue >>=1) - { - fprintf(file, "%s%s=", (nr ? "," : ""), get_type(optp->typelib, nr)); - fprintf(file, llvalue & 1 ? "on" : "off"); - } - fprintf(file, "\n"); - break; - case GET_ENUM: - fprintf(file, "%s\n", get_type(optp->typelib, *(ulong*) value)); - break; - case GET_STR: - case GET_PASSWORD: - case GET_STR_ALLOC: /* fall through */ - fprintf(file, "%s\n", *((char**) value) ? *((char**) value) : - "(No default value)"); - break; - case GET_BOOL: - fprintf(file, "%s\n", *((my_bool*) value) ? "TRUE" : "FALSE"); - break; - case GET_INT: - fprintf(file, "%d\n", *((int*) value)); - break; - case GET_UINT: - fprintf(file, "%d\n", *((uint*) value)); - break; - case GET_LONG: - fprintf(file, "%ld\n", *((long*) value)); - break; - case GET_ULONG: - fprintf(file, "%lu\n", *((ulong*) value)); - break; - case GET_LL: - fprintf(file, "%s\n", llstr(*((longlong*) value), buff)); - break; - case GET_ULL: - longlong2str(*((ulonglong*) value), buff, 10); - fprintf(file, "%s\n", buff); - break; - case GET_DOUBLE: - fprintf(file, "%g\n", *(double*) value); - break; - case GET_NO_ARG: - fprintf(file, "(No default value)\n"); - break; - default: - fprintf(file, "(Disabled)\n"); - break; - } - } - } -} |