Drizzled Public API Documentation

option.cc
00001 /* Copyright (C) 2002-2006 MySQL AB
00002 
00003    This program is free software; you can redistribute it and/or modify
00004    it under the terms of the GNU General Public License as published by
00005    the Free Software Foundation; version 2 of the License.
00006 
00007    This program is distributed in the hope that it will be useful,
00008    but WITHOUT ANY WARRANTY; without even the implied warranty of
00009    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00010    GNU General Public License for more details.
00011 
00012    You should have received a copy of the GNU General Public License
00013    along with this program; if not, write to the Free Software
00014    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
00015 
00016 #include <config.h>
00017 #include <drizzled/internal/my_sys.h>
00018 #include <drizzled/gettext.h>
00019 
00020 #include <drizzled/internal/m_string.h>
00021 #include <drizzled/internal/my_sys.h>
00022 #include <drizzled/error.h>
00023 #include <drizzled/option.h>
00024 #include <drizzled/typelib.h>
00025 
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <errno.h>
00029 #include <iostream>
00030 #include <algorithm>
00031 
00032 using namespace std;
00033 namespace drizzled
00034 {
00035 
00036   typedef void (*init_func_p)(const struct option *option, char **variable,
00037       int64_t value);
00038 
00039   void default_reporter(enum loglevel level, const char *format, ...);
00040   my_error_reporter my_getopt_error_reporter= &default_reporter;
00041 
00042   static int findopt(char *optpat, uint32_t length,
00043       const struct option **opt_res,
00044       char **ffname);
00045   static int64_t getopt_ll(char *arg, const struct option *optp, int *err);
00046   static uint64_t getopt_ull(char *arg, const struct option *optp,
00047       int *err);
00048   static size_t getopt_size(char *arg, const struct option *optp, int *err);
00049   static double getopt_double(char *arg, const struct option *optp, int *err);
00050   static void init_variables(const struct option *options,
00051       init_func_p init_one_value);
00052   static void init_one_value(const struct option *option, char **variable,
00053       int64_t value);
00054   static void fini_one_value(const struct option *option, char **variable,
00055       int64_t value);
00056   static int setval(const struct option *opts, char* *value, char *argument,
00057       bool set_maximum_value);
00058   static char *check_struct_option(char *cur_arg, char *key_name);
00059 
00060   /*
00061      The following three variables belong to same group and the number and
00062      order of their arguments must correspond to each other.
00063    */
00064   static const char *special_opt_prefix[]=
00065   {"skip", "disable", "enable", "maximum", "loose", 0};
00066   static const uint32_t special_opt_prefix_lengths[]=
00067   { 4,      7,         6,        7,         5,      0};
00068   enum enum_special_opt
00069   { OPT_SKIP, OPT_DISABLE, OPT_ENABLE, OPT_MAXIMUM, OPT_LOOSE};
00070 
00071   char *disabled_my_option= (char*) "0";
00072 
00073   /*
00074      This is a flag that can be set in client programs. 1 means that
00075      my_getopt will skip over options it does not know how to handle.
00076    */
00077 
00078   bool my_getopt_skip_unknown= 0;
00079 
00080   void default_reporter(enum loglevel level, const char *format, ...)
00081   {
00082     va_list args;
00083     va_start(args, format);
00084     if (level == WARNING_LEVEL)
00085       fprintf(stderr, "%s", _("Warning: "));
00086     else if (level == INFORMATION_LEVEL)
00087       fprintf(stderr, "%s", _("Info: "));
00088     vfprintf(stderr, format, args);
00089     va_end(args);
00090     fputc('\n', stderr);
00091     fflush(stderr);
00092   }
00093 
00094   /*
00095 function: handle_options
00096 
00097 Sort options; put options first, until special end of options (--), or
00098 until end of argv. Parse options; check that the given option matches with
00099 one of the options in struct 'option', return error in case of ambiguous
00100 or unknown option. Check that option was given an argument if it requires
00101 one. Call function 'get_one_option()' once for each option.
00102    */
00103 
00104   static getopt_get_addr_func getopt_get_addr;
00105 
00106   int handle_options(int *argc, char ***argv,
00107       const struct option *longopts,
00108       my_get_one_option get_one_option)
00109   {
00110     uint32_t opt_found, argvpos= 0, length;
00111     bool end_of_options= 0, must_be_var, set_maximum_value=false,
00112          option_is_loose;
00113     char **pos, **pos_end, *optend, *prev_found=NULL,
00114          *opt_str, key_name[FN_REFLEN];
00115     const struct option *optp;
00116     char* *value;
00117     int error, i;
00118 
00119     /* handle_options() assumes arg0 (program name) always exists */
00120     assert(argc && *argc >= 1);
00121     assert(argv && *argv);
00122     (*argc)--; /* Skip the program name */
00123     (*argv)++; /*      --- || ----      */
00124     init_variables(longopts, init_one_value);
00125 
00126     for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++)
00127     {
00128       char **first= pos;
00129       char *cur_arg= *pos;
00130       if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */
00131       {
00132         char *argument=    0;
00133         must_be_var=       0;
00134         set_maximum_value= 0;
00135         option_is_loose=   0;
00136 
00137         cur_arg++;  /* skip '-' */
00138         if (*cur_arg == '-' || *cur_arg == 'O') /* check for long option, */
00139         {                                       /* --set-variable, or -O  */
00140           if (*cur_arg == 'O')
00141           {
00142             must_be_var= 1;
00143 
00144             if (!(*++cur_arg))  /* If not -Ovar=# */
00145             {
00146               /* the argument must be in next argv */
00147               if (!*++pos)
00148               {
00149                 my_getopt_error_reporter(ERROR_LEVEL,
00150                     "%s: Option '-O' requires an argument",
00151                     internal::my_progname);
00152                 return EXIT_ARGUMENT_REQUIRED;
00153               }
00154               cur_arg= *pos;
00155               (*argc)--;
00156             }
00157           }
00158           else if (!getopt_compare_strings(cur_arg, "-set-variable", 13))
00159           {
00160             must_be_var= 1;
00161             if (cur_arg[13] == '=')
00162             {
00163               cur_arg+= 14;
00164               if (!*cur_arg)
00165               {
00166                 my_getopt_error_reporter(ERROR_LEVEL,
00167                     "%s: Option '--set-variable' requires an argument",
00168                     internal::my_progname);
00169                 return EXIT_ARGUMENT_REQUIRED;
00170               }
00171             }
00172             else if (cur_arg[14]) /* garbage, or another option. break out */
00173               must_be_var= 0;
00174             else
00175             {
00176               /* the argument must be in next argv */
00177               if (!*++pos)
00178               {
00179                 my_getopt_error_reporter(ERROR_LEVEL,
00180                     "%s: Option '--set-variable' requires an argument",
00181                     internal::my_progname);
00182                 return EXIT_ARGUMENT_REQUIRED;
00183               }
00184               cur_arg= *pos;
00185               (*argc)--;
00186             }
00187           }
00188           else if (!must_be_var)
00189           {
00190             if (!*++cur_arg)  /* skip the double dash */
00191             {
00192               /* '--' means end of options, look no further */
00193               end_of_options= 1;
00194               (*argc)--;
00195               continue;
00196             }
00197           }
00198           opt_str= check_struct_option(cur_arg, key_name);
00199           optend= strchr(opt_str, '=');
00200           if (optend != NULL)
00201           {
00202             length= (uint32_t) (optend - opt_str);
00203             optend++;
00204           }
00205           else
00206           {
00207             length= static_cast<uint32_t>(strlen(opt_str));
00208             optend= 0;
00209           }
00210 
00211           /*
00212              Find first the right option. Return error in case of an ambiguous,
00213              or unknown option
00214            */
00215           optp= longopts;
00216           if (!(opt_found= findopt(opt_str, length, &optp, &prev_found)))
00217           {
00218             /*
00219                Didn't find any matching option. Let's see if someone called
00220                option with a special option prefix
00221              */
00222             if (!must_be_var)
00223             {
00224               if (optend)
00225                 must_be_var= 1; /* option is followed by an argument */
00226               for (i= 0; special_opt_prefix[i]; i++)
00227               {
00228                 if (!getopt_compare_strings(special_opt_prefix[i], opt_str,
00229                       special_opt_prefix_lengths[i]) &&
00230                     (opt_str[special_opt_prefix_lengths[i]] == '-' ||
00231                      opt_str[special_opt_prefix_lengths[i]] == '_'))
00232                 {
00233                   /*
00234                      We were called with a special prefix, we can reuse opt_found
00235                    */
00236                   opt_str+= special_opt_prefix_lengths[i] + 1;
00237                   length-= special_opt_prefix_lengths[i] + 1;
00238                   if (i == OPT_LOOSE)
00239                     option_is_loose= 1;
00240                   if ((opt_found= findopt(opt_str, length, &optp, &prev_found)))
00241                   {
00242                     if (opt_found > 1)
00243                     {
00244                       my_getopt_error_reporter(ERROR_LEVEL,
00245                           "%s: ambiguous option '--%s-%s' (--%s-%s)",
00246                           internal::my_progname,
00247                           special_opt_prefix[i],
00248                           cur_arg, special_opt_prefix[i],
00249                           prev_found);
00250                       return EXIT_AMBIGUOUS_OPTION;
00251                     }
00252                     switch (i) {
00253                       case OPT_SKIP:
00254                       case OPT_DISABLE: /* fall through */
00255                         /*
00256                            double negation is actually enable again,
00257                            for example: --skip-option=0 -> option = true
00258                          */
00259                         optend= (optend && *optend == '0' && !(*(optend + 1))) ?
00260                           (char*) "1" : disabled_my_option;
00261                         break;
00262                       case OPT_ENABLE:
00263                         optend= (optend && *optend == '0' && !(*(optend + 1))) ?
00264                           disabled_my_option : (char*) "1";
00265                         break;
00266                       case OPT_MAXIMUM:
00267                         set_maximum_value= true;
00268                         must_be_var= true;
00269                         break;
00270                     }
00271                     break; /* break from the inner loop, main loop continues */
00272                   }
00273                   i= -1; /* restart the loop */
00274                 }
00275               }
00276             }
00277             if (!opt_found)
00278             {
00279               if (my_getopt_skip_unknown)
00280               {
00281                 /*
00282                    preserve all the components of this unknown option, this may
00283                    occurr when the user provides options like: "-O foo" or
00284                    "--set-variable foo" (note that theres a space in there)
00285                    Generally, these kind of options are to be avoided
00286                  */
00287                 do {
00288                   (*argv)[argvpos++]= *first++;
00289                 } while (first <= pos);
00290                 continue;
00291               }
00292               if (must_be_var)
00293               {
00294                 my_getopt_error_reporter(option_is_loose ?
00295                     WARNING_LEVEL : ERROR_LEVEL,
00296                     "%s: unknown variable '%s'",
00297                     internal::my_progname, cur_arg);
00298                 if (!option_is_loose)
00299                   return EXIT_UNKNOWN_VARIABLE;
00300               }
00301               else
00302               {
00303                 my_getopt_error_reporter(option_is_loose ?
00304                     WARNING_LEVEL : ERROR_LEVEL,
00305                     "%s: unknown option '--%s'",
00306                     internal::my_progname, cur_arg);
00307                 if (!option_is_loose)
00308                   return EXIT_UNKNOWN_OPTION;
00309               }
00310               if (option_is_loose)
00311               {
00312                 (*argc)--;
00313                 continue;
00314               }
00315             }
00316           }
00317           if (opt_found > 1)
00318           {
00319             if (must_be_var)
00320             {
00321               my_getopt_error_reporter(ERROR_LEVEL,
00322                   "%s: variable prefix '%s' is not unique",
00323                   internal::my_progname, opt_str);
00324               return EXIT_VAR_PREFIX_NOT_UNIQUE;
00325             }
00326             else
00327             {
00328               my_getopt_error_reporter(ERROR_LEVEL,
00329                   "%s: ambiguous option '--%s' (%s, %s)",
00330                   internal::my_progname, opt_str, prev_found,
00331                   optp->name);
00332               return EXIT_AMBIGUOUS_OPTION;
00333             }
00334           }
00335           if ((optp->var_type & GET_TYPE_MASK) == GET_DISABLED)
00336           {
00337             fprintf(stderr,
00338                 _("%s: %s: Option '%s' used, but is disabled\n"),
00339                 internal::my_progname,
00340                 option_is_loose ? _("WARNING") : _("ERROR"), opt_str);
00341             if (option_is_loose)
00342             {
00343               (*argc)--;
00344               continue;
00345             }
00346             return EXIT_OPTION_DISABLED;
00347           }
00348           if (must_be_var && (optp->var_type & GET_TYPE_MASK) == GET_NO_ARG)
00349           {
00350             my_getopt_error_reporter(ERROR_LEVEL,
00351                 "%s: option '%s' cannot take an argument",
00352                 internal::my_progname, optp->name);
00353             return EXIT_NO_ARGUMENT_ALLOWED;
00354           }
00355           value= optp->var_type & GET_ASK_ADDR ?
00356             (*getopt_get_addr)(key_name, (uint32_t) strlen(key_name), optp) : optp->value;
00357 
00358           if (optp->arg_type == NO_ARG)
00359           {
00360             if (optend && (optp->var_type & GET_TYPE_MASK) != GET_BOOL)
00361             {
00362               my_getopt_error_reporter(ERROR_LEVEL,
00363                   "%s: option '--%s' cannot take an argument",
00364                   internal::my_progname, optp->name);
00365               return EXIT_NO_ARGUMENT_ALLOWED;
00366             }
00367             if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL)
00368             {
00369               /*
00370                  Set bool to 1 if no argument or if the user has used
00371                  --enable-'option-name'.
00372                *optend was set to '0' if one used --disable-option
00373                */
00374               (*argc)--;
00375               if (!optend || *optend == '1' ||
00376                   !my_strcasecmp(&my_charset_utf8_general_ci, optend, "true"))
00377                 *((bool*) value)= (bool) 1;
00378               else if (*optend == '0' ||
00379                   !my_strcasecmp(&my_charset_utf8_general_ci, optend, "false"))
00380                 *((bool*) value)= (bool) 0;
00381               else
00382               {
00383                 my_getopt_error_reporter(WARNING_LEVEL,
00384                     "%s: ignoring option '--%s' due to "
00385                     "invalid value '%s'",
00386                     internal::my_progname,
00387                     optp->name, optend);
00388                 continue;
00389               }
00390               error= get_one_option(optp->id, optp, *((bool*) value) ?
00391                                     (char*) "1" : disabled_my_option);
00392               if (error != 0)
00393                 return error;
00394               else
00395                 continue;
00396             }
00397             argument= optend;
00398           }
00399           else if (optp->arg_type == OPT_ARG &&
00400               (optp->var_type & GET_TYPE_MASK) == GET_BOOL)
00401           {
00402             if (optend == disabled_my_option)
00403               *((bool*) value)= (bool) 0;
00404             else
00405             {
00406               if (!optend) /* No argument -> enable option */
00407                 *((bool*) value)= (bool) 1;
00408               else
00409                 argument= optend;
00410             }
00411           }
00412           else if (optp->arg_type == REQUIRED_ARG && !optend)
00413           {
00414             /* Check if there are more arguments after this one */
00415             if (!*++pos)
00416             {
00417               my_getopt_error_reporter(ERROR_LEVEL,
00418                   "%s: option '--%s' requires an argument",
00419                   internal::my_progname, optp->name);
00420               return EXIT_ARGUMENT_REQUIRED;
00421             }
00422             argument= *pos;
00423             (*argc)--;
00424           }
00425           else
00426             argument= optend;
00427         }
00428         else  /* must be short option */
00429         {
00430           for (optend= cur_arg; *optend; optend++)
00431           {
00432             opt_found= 0;
00433             for (optp= longopts; optp->id; optp++)
00434             {
00435               if (optp->id == (int) (unsigned char) *optend)
00436               {
00437                 /* Option recognized. Find next what to do with it */
00438                 opt_found= 1;
00439                 if ((optp->var_type & GET_TYPE_MASK) == GET_DISABLED)
00440                 {
00441                   fprintf(stderr,
00442                       _("%s: ERROR: Option '-%c' used, but is disabled\n"),
00443                       internal::my_progname, optp->id);
00444                   return EXIT_OPTION_DISABLED;
00445                 }
00446                 if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL &&
00447                     optp->arg_type == NO_ARG)
00448                 {
00449                   *((bool*) optp->value)= (bool) 1;
00450                   error= get_one_option(optp->id, optp, argument);
00451                   if (error != 0)
00452                     return error;
00453                   else
00454                     continue;
00455 
00456                 }
00457                 else if (optp->arg_type == REQUIRED_ARG ||
00458                     optp->arg_type == OPT_ARG)
00459                 {
00460                   if (*(optend + 1))
00461                   {
00462                     /* The rest of the option is option argument */
00463                     argument= optend + 1;
00464                     /* This is in effect a jump out of the outer loop */
00465                     optend= (char*) " ";
00466                   }
00467                   else
00468                   {
00469                     if (optp->arg_type == OPT_ARG)
00470                     {
00471                       if (optp->var_type == GET_BOOL)
00472                         *((bool*) optp->value)= (bool) 1;
00473                       error= get_one_option(optp->id, optp, argument);
00474                       if (error != 0)
00475                         return error;
00476                       else
00477                         continue;
00478                     }
00479                     /* Check if there are more arguments after this one */
00480                     if (!pos[1])
00481                     {
00482                       my_getopt_error_reporter(ERROR_LEVEL,
00483                           "%s: option '-%c' requires "
00484                           "an argument",
00485                           internal::my_progname, optp->id);
00486                       return EXIT_ARGUMENT_REQUIRED;
00487                     }
00488                     argument= *++pos;
00489                     (*argc)--;
00490                     /* the other loop will break, because *optend + 1 == 0 */
00491                   }
00492                 }
00493                 if ((error= setval(optp, optp->value, argument,
00494                         set_maximum_value)))
00495                 {
00496                   my_getopt_error_reporter(ERROR_LEVEL,
00497                       "%s: Error while setting value '%s' "
00498                       "to '%s'",
00499                       internal::my_progname,
00500                       argument, optp->name);
00501                   return error;
00502                 }
00503                 error= get_one_option(optp->id, optp, argument);
00504                 if (error != 0)
00505                   return error;
00506                 else
00507                   break;
00508               }
00509             }
00510             if (!opt_found)
00511             {
00512               my_getopt_error_reporter(ERROR_LEVEL,
00513                   "%s: unknown option '-%c'",
00514                   internal::my_progname, *optend);
00515               return EXIT_UNKNOWN_OPTION;
00516             }
00517           }
00518           (*argc)--; /* option handled (short), decrease argument count */
00519           continue;
00520         }
00521         if ((error= setval(optp, value, argument, set_maximum_value)))
00522         {
00523           my_getopt_error_reporter(ERROR_LEVEL,
00524               "%s: Error while setting value '%s' to '%s'",
00525               internal::my_progname, argument, optp->name);
00526           return error;
00527         }
00528         error= get_one_option(optp->id, optp, argument);
00529         if (error != 0)
00530           return error;
00531 
00532         (*argc)--; /* option handled (short or long), decrease argument count */
00533       }
00534       else /* non-option found */
00535         (*argv)[argvpos++]= cur_arg;
00536     }
00537     /*
00538        Destroy the first, already handled option, so that programs that look
00539        for arguments in 'argv', without checking 'argc', know when to stop.
00540        Items in argv, before the destroyed one, are all non-option -arguments
00541        to the program, yet to be (possibly) handled.
00542      */
00543     (*argv)[argvpos]= 0;
00544     return 0;
00545   }
00546 
00547 
00548   /*
00549 function: check_struct_option
00550 
00551 Arguments: Current argument under processing from argv and a variable
00552 where to store the possible key name.
00553 
00554 Return value: In case option is a struct option, returns a pointer to
00555 the current argument at the position where the struct option (key_name)
00556 ends, the next character after the dot. In case argument is not a struct
00557 option, returns a pointer to the argument.
00558 
00559 key_name will hold the name of the key, or 0 if not found.
00560    */
00561 
00562   static char *check_struct_option(char *cur_arg, char *key_name)
00563   {
00564     char *ptr, *end;
00565 
00566     ptr= NULL; //Options with '.' are now supported.
00567     end= strrchr(cur_arg, '=');
00568 
00569     /*
00570        If the first dot is after an equal sign, then it is part
00571        of a variable value and the option is not a struct option.
00572        Also, if the last character in the string before the ending
00573        NULL, or the character right before equal sign is the first
00574        dot found, the option is not a struct option.
00575      */
00576     if ((ptr != NULL) && (end != NULL) && (end - ptr > 1))
00577     {
00578       uint32_t len= (uint32_t) (ptr - cur_arg);
00579       set_if_smaller(len, (uint32_t)FN_REFLEN-1);
00580       strncpy(key_name, cur_arg, len);
00581       return ++ptr;
00582     }
00583     key_name[0]= 0;
00584     return cur_arg;
00585   }
00586 
00587   /*
00588 function: setval
00589 
00590 Arguments: opts, argument
00591 Will set the option value to given value
00592    */
00593 
00594   static int setval(const struct option *opts, char **value, char *argument,
00595       bool set_maximum_value)
00596   {
00597     int err= 0;
00598 
00599     if (value && argument)
00600     {
00601       char* *result_pos= ((set_maximum_value) ?
00602           opts->u_max_value : value);
00603 
00604       if (!result_pos)
00605         return EXIT_NO_PTR_TO_VARIABLE;
00606 
00607       switch ((opts->var_type & GET_TYPE_MASK)) {
00608         case GET_BOOL: /* If argument differs from 0, enable option, else disable */
00609           *((bool*) result_pos)= (bool) atoi(argument) != 0;
00610           break;
00611         case GET_INT:
00612           *((int32_t*) result_pos)= (int) getopt_ll(argument, opts, &err);
00613           break;
00614         case GET_UINT:
00615         case GET_UINT32:
00616           *((uint32_t*) result_pos)= (uint32_t) getopt_ull(argument, opts, &err);
00617           break;
00618         case GET_ULONG_IS_FAIL:
00619           *((ulong*) result_pos)= (ulong) getopt_ull(argument, opts, &err);
00620           break;
00621         case GET_LONG:
00622           *((long*) result_pos)= (long) getopt_ll(argument, opts, &err);
00623           break;
00624         case GET_LL:
00625           *((int64_t*) result_pos)= getopt_ll(argument, opts, &err);
00626           break;
00627         case GET_ULL:
00628         case GET_UINT64:
00629           *((uint64_t*) result_pos)= getopt_ull(argument, opts, &err);
00630           break;
00631         case GET_SIZE:
00632           *((size_t*) result_pos)= getopt_size(argument, opts, &err);
00633           break;
00634         case GET_DOUBLE:
00635           *((double*) result_pos)= getopt_double(argument, opts, &err);
00636           break;
00637         case GET_STR:
00638           *((char**) result_pos)= argument;
00639           break;
00640         case GET_STR_ALLOC:
00641           if ((*((char**) result_pos)))
00642             free((*(char**) result_pos));
00643           if (!(*((char**) result_pos)= strdup(argument)))
00644             return EXIT_OUT_OF_MEMORY;
00645           break;
00646         case GET_ENUM:
00647           if (((*(int*)result_pos)= opts->typelib->find_type(argument, 2) - 1) < 0)
00648             return EXIT_ARGUMENT_INVALID;
00649           break;
00650         case GET_SET:
00651           *((uint64_t*)result_pos)= opts->typelib->find_typeset(argument, &err);
00652           if (err)
00653             return EXIT_ARGUMENT_INVALID;
00654           break;
00655         default:    /* dummy default to avoid compiler warnings */
00656           break;
00657       }
00658       if (err)
00659         return EXIT_UNKNOWN_SUFFIX;
00660     }
00661     return 0;
00662   }
00663 
00664 
00665   /*
00666      Find option
00667 
00668      SYNOPSIS
00669      findopt()
00670      optpat Prefix of option to find (with - or _)
00671      length Length of optpat
00672      opt_res  Options
00673      ffname Place for pointer to first found name
00674 
00675      IMPLEMENTATION
00676      Go through all options in the option struct. Return number
00677      of options found that match the pattern and in the argument
00678      list the option found, if any. In case of ambiguous option, store
00679      the name in ffname argument
00680 
00681      RETURN
00682      0    No matching options
00683 #   Number of matching options
00684 ffname points to first matching option
00685    */
00686 
00687   static int findopt(char *optpat, uint32_t length,
00688       const struct option **opt_res,
00689       char **ffname)
00690   {
00691     uint32_t count;
00692     struct option *opt= (struct option *) *opt_res;
00693 
00694     for (count= 0; opt->name; opt++)
00695     {
00696       if (!getopt_compare_strings(opt->name, optpat, length)) /* match found */
00697       {
00698         (*opt_res)= opt;
00699         if (!opt->name[length])   /* Exact match */
00700           return 1;
00701         if (!count)
00702         {
00703           count= 1;
00704           *ffname= (char *) opt->name;  /* We only need to know one prev */
00705         }
00706         else if (strcmp(*ffname, opt->name))
00707         {
00708           /*
00709              The above test is to not count same option twice
00710              (see mysql.cc, option "help")
00711            */
00712           count++;
00713         }
00714       }
00715     }
00716     return count;
00717   }
00718 
00719 
00720   /*
00721 function: compare_strings
00722 
00723 Works like strncmp, other than 1.) considers '-' and '_' the same.
00724 2.) Returns -1 if strings differ, 0 if they are equal
00725    */
00726 
00727   bool getopt_compare_strings(const char *s, const char *t,
00728       uint32_t length)
00729   {
00730     char const *end= s + length;
00731     for (;s != end ; s++, t++)
00732     {
00733       if ((*s != '-' ? *s : '_') != (*t != '-' ? *t : '_'))
00734         return 1;
00735     }
00736     return 0;
00737   }
00738 
00739   /*
00740 function: eval_num_suffix
00741 
00742 Transforms a number with a suffix to real number. Suffix can
00743 be k|K for kilo, m|M for mega or g|G for giga.
00744    */
00745 
00746   static int64_t eval_num_suffix(char *argument, int *error, char *option_name)
00747   {
00748     char *endchar;
00749     int64_t num;
00750 
00751     *error= 0;
00752     errno= 0;
00753     num= strtoll(argument, &endchar, 10);
00754     if (errno == ERANGE)
00755     {
00756       my_getopt_error_reporter(ERROR_LEVEL,
00757           "Incorrect integer value: '%s'", argument);
00758       *error= 1;
00759       return 0;
00760     }
00761     if (*endchar == 'k' || *endchar == 'K')
00762       num*= 1024L;
00763     else if (*endchar == 'm' || *endchar == 'M')
00764       num*= 1024L * 1024L;
00765     else if (*endchar == 'g' || *endchar == 'G')
00766       num*= 1024L * 1024L * 1024L;
00767     else if (*endchar)
00768     {
00769       fprintf(stderr,
00770           _("Unknown suffix '%c' used for variable '%s' (value '%s')\n"),
00771           *endchar, option_name, argument);
00772       *error= 1;
00773       return 0;
00774     }
00775     return num;
00776   }
00777 
00778   /*
00779 function: getopt_ll
00780 
00781 Evaluates and returns the value that user gave as an argument
00782 to a variable. Recognizes (case insensitive) K as KILO, M as MEGA
00783 and G as GIGA bytes. Some values must be in certain blocks, as
00784 defined in the given option struct, this function will check
00785 that those values are honored.
00786 In case of an error, set error value in *err.
00787    */
00788 
00789   static int64_t getopt_ll(char *arg, const struct option *optp, int *err)
00790   {
00791     int64_t num=eval_num_suffix(arg, err, (char*) optp->name);
00792     return getopt_ll_limit_value(num, optp, NULL);
00793   }
00794 
00795   /*
00796 function: getopt_ll_limit_value
00797 
00798 Applies min/max/block_size to a numeric value of an option.
00799 Returns "fixed" value.
00800    */
00801 
00802   int64_t getopt_ll_limit_value(int64_t num, const struct option *optp,
00803       bool *fix)
00804   {
00805     int64_t old= num;
00806     bool adjusted= false;
00807     char buf1[255], buf2[255];
00808     uint64_t block_size= (optp->block_size ? (uint64_t) optp->block_size : 1L);
00809 
00810     if (num > 0 && ((uint64_t) num > (uint64_t) optp->max_value) &&
00811         optp->max_value) /* if max value is not set -> no upper limit */
00812     {
00813       num= (uint64_t) optp->max_value;
00814       adjusted= true;
00815     }
00816 
00817     switch ((optp->var_type & GET_TYPE_MASK)) {
00818       case GET_INT:
00819         if (num > (int64_t) INT_MAX)
00820         {
00821           num= ((int64_t) INT_MAX);
00822           adjusted= true;
00823         }
00824         break;
00825       case GET_LONG:
00826         if (num > (int64_t) INT32_MAX)
00827         {
00828           num= ((int64_t) INT32_MAX);
00829           adjusted= true;
00830         }
00831         break;
00832       default:
00833         assert((optp->var_type & GET_TYPE_MASK) == GET_LL);
00834         break;
00835     }
00836 
00837     num= ((num - optp->sub_size) / block_size);
00838     num= (int64_t) (num * block_size);
00839 
00840     if (num < optp->min_value)
00841     {
00842       num= optp->min_value;
00843       adjusted= true;
00844     }
00845 
00846     if (fix)
00847       *fix= adjusted;
00848     else if (adjusted)
00849       my_getopt_error_reporter(WARNING_LEVEL,
00850           "option '%s': signed value %s adjusted to %s",
00851           optp->name, internal::llstr(old, buf1), internal::llstr(num, buf2));
00852     return num;
00853   }
00854 
00855   /*
00856 function: getopt_ull
00857 
00858 This is the same as getopt_ll, but is meant for uint64_t
00859 values.
00860    */
00861 
00862   static uint64_t getopt_ull(char *arg, const struct option *optp, int *err)
00863   {
00864     uint64_t num= eval_num_suffix(arg, err, (char*) optp->name);
00865     return getopt_ull_limit_value(num, optp, NULL);
00866   }
00867 
00868 
00869   static size_t getopt_size(char *arg, const struct option *optp, int *err)
00870   {
00871     return (size_t)getopt_ull(arg, optp, err);
00872   }
00873 
00874 
00875 
00876   uint64_t getopt_ull_limit_value(uint64_t num, const struct option *optp,
00877       bool *fix)
00878   {
00879     bool adjusted= false;
00880     uint64_t old= num;
00881     char buf1[255], buf2[255];
00882 
00883     if ((uint64_t) num > (uint64_t) optp->max_value &&
00884         optp->max_value) /* if max value is not set -> no upper limit */
00885     {
00886       num= (uint64_t) optp->max_value;
00887       adjusted= true;
00888     }
00889 
00890     switch ((optp->var_type & GET_TYPE_MASK)) {
00891       case GET_UINT:
00892         if (num > (uint64_t) UINT_MAX)
00893         {
00894           num= ((uint64_t) UINT_MAX);
00895           adjusted= true;
00896         }
00897         break;
00898       case GET_UINT32:
00899       case GET_ULONG_IS_FAIL:
00900         if (num > (uint64_t) UINT32_MAX)
00901         {
00902           num= ((uint64_t) UINT32_MAX);
00903           adjusted= true;
00904         }
00905         break;
00906       case GET_SIZE:
00907         if (num > (uint64_t) SIZE_MAX)
00908         {
00909           num= ((uint64_t) SIZE_MAX);
00910           adjusted= true;
00911         }
00912         break;
00913       default:
00914         assert(((optp->var_type & GET_TYPE_MASK) == GET_ULL)
00915             || ((optp->var_type & GET_TYPE_MASK) == GET_UINT64));
00916         break;
00917     }
00918 
00919     if (optp->block_size > 1)
00920     {
00921       num/= (uint64_t) optp->block_size;
00922       num*= (uint64_t) optp->block_size;
00923     }
00924 
00925     if (num < (uint64_t) optp->min_value)
00926     {
00927       num= (uint64_t) optp->min_value;
00928       adjusted= true;
00929     }
00930 
00931     if (fix)
00932       *fix= adjusted;
00933     else if (adjusted)
00934       my_getopt_error_reporter(WARNING_LEVEL,
00935           "option '%s': unsigned value %s adjusted to %s",
00936           optp->name, internal::ullstr(old, buf1), internal::ullstr(num, buf2));
00937 
00938     return num;
00939   }
00940 
00941 
00942   /*
00943      Get double value withing ranges
00944 
00945      Evaluates and returns the value that user gave as an argument to a variable.
00946 
00947      RETURN
00948      decimal value of arg
00949 
00950      In case of an error, prints an error message and sets *err to
00951      EXIT_ARGUMENT_INVALID.  Otherwise err is not touched
00952    */
00953 
00954   static double getopt_double(char *arg, const struct option *optp, int *err)
00955   {
00956     double num;
00957     int error;
00958     char *end= arg + 1000;                     /* Big enough as *arg is \0 terminated */
00959     num= internal::my_strtod(arg, &end, &error);
00960     if (end[0] != 0 || error)
00961     {
00962       fprintf(stderr,
00963           _("%s: ERROR: Invalid decimal value for option '%s'\n"),
00964           internal::my_progname, optp->name);
00965       *err= EXIT_ARGUMENT_INVALID;
00966       return 0.0;
00967     }
00968     if (optp->max_value && num > (double) optp->max_value)
00969       num= (double) optp->max_value;
00970     return max(num, (double) optp->min_value);
00971   }
00972 
00973   /*
00974      Init one value to it's default values
00975 
00976      SYNOPSIS
00977      init_one_value()
00978      option   Option to initialize
00979      value    Pointer to variable
00980    */
00981 
00982   static void init_one_value(const struct option *option, char** variable,
00983       int64_t value)
00984   {
00985     switch ((option->var_type & GET_TYPE_MASK)) {
00986       case GET_BOOL:
00987         *((bool*) variable)= (bool) value;
00988         break;
00989       case GET_INT:
00990         *((int*) variable)= (int) value;
00991         break;
00992       case GET_UINT:
00993       case GET_ENUM:
00994         *((uint*) variable)= (uint32_t) value;
00995         break;
00996       case GET_LONG:
00997         *((long*) variable)= (long) value;
00998         break;
00999       case GET_UINT32:
01000         *((uint32_t*) variable)= (uint32_t) value;
01001         break;
01002       case GET_ULONG_IS_FAIL:
01003         *((ulong*) variable)= (ulong) value;
01004         break;
01005       case GET_LL:
01006         *((int64_t*) variable)= (int64_t) value;
01007         break;
01008       case GET_SIZE:
01009         *((size_t*) variable)= (size_t) value;
01010         break;
01011       case GET_ULL:
01012       case GET_SET:
01013       case GET_UINT64:
01014         *((uint64_t*) variable)=  (uint64_t) value;
01015         break;
01016       case GET_DOUBLE:
01017         *((double*) variable)=  (double) value;
01018         break;
01019       case GET_STR:
01020         /*
01021            Do not clear variable value if it has no default value.
01022            The default value may already be set.
01023 NOTE: To avoid compiler warnings, we first cast int64_t to intptr_t,
01024 so that the value has the same size as a pointer.
01025          */
01026         if ((char*) (intptr_t) value)
01027           *((char**) variable)= (char*) (intptr_t) value;
01028         break;
01029       case GET_STR_ALLOC:
01030         /*
01031            Do not clear variable value if it has no default value.
01032            The default value may already be set.
01033 NOTE: To avoid compiler warnings, we first cast int64_t to intptr_t,
01034 so that the value has the same size as a pointer.
01035          */
01036         if ((char*) (intptr_t) value)
01037         {
01038           free((*(char**) variable));
01039           char *tmpptr= strdup((char *) (intptr_t) value);
01040           if (tmpptr != NULL)
01041             *((char**) variable)= tmpptr;
01042         }
01043         break;
01044       default: /* dummy default to avoid compiler warnings */
01045         break;
01046     }
01047     return;
01048   }
01049 
01050 
01051   /*
01052      Init one value to it's default values
01053 
01054      SYNOPSIS
01055      init_one_value()
01056      option   Option to initialize
01057      value    Pointer to variable
01058    */
01059 
01060   static void fini_one_value(const struct option *option, char **variable,
01061       int64_t)
01062   {
01063     switch ((option->var_type & GET_TYPE_MASK)) {
01064       case GET_STR_ALLOC:
01065         free((*(char**) variable));
01066         *((char**) variable)= NULL;
01067         break;
01068       default: /* dummy default to avoid compiler warnings */
01069         break;
01070     }
01071     return;
01072   }
01073 
01074 
01075   void my_cleanup_options(const struct option *options)
01076   {
01077     init_variables(options, fini_one_value);
01078   }
01079 
01080 
01081   /*
01082      initialize all variables to their default values
01083 
01084      SYNOPSIS
01085      init_variables()
01086      options    Array of options
01087 
01088      NOTES
01089      We will initialize the value that is pointed to by options->value.
01090      If the value is of type GET_ASK_ADDR, we will also ask for the address
01091      for a value and initialize.
01092    */
01093 
01094   static void init_variables(const struct option *options,
01095       init_func_p init_one_value)
01096   {
01097     for (; options->name; options++)
01098     {
01099       char* *variable;
01100       /*
01101          We must set u_max_value first as for some variables
01102          options->u_max_value == options->value and in this case we want to
01103          set the value to default value.
01104        */
01105       if (options->u_max_value)
01106         init_one_value(options, options->u_max_value, options->max_value);
01107       if (options->value)
01108         init_one_value(options, options->value, options->def_value);
01109       if (options->var_type & GET_ASK_ADDR &&
01110           (variable= (*getopt_get_addr)("", 0, options)))
01111         init_one_value(options, variable, options->def_value);
01112     }
01113     return;
01114   }
01115 
01116 
01117   /*
01118 function: my_print_options
01119 
01120 Print help for all options and variables.
01121    */
01122 
01123   void my_print_help(const struct option *options)
01124   {
01125     uint32_t col, name_space= 22, comment_space= 57;
01126     const char *line_end;
01127     const struct option *optp;
01128 
01129     for (optp= options; optp->id; optp++)
01130     {
01131       if (optp->id < 256)
01132       {
01133         printf("  -%c%s", optp->id, strlen(optp->name) ? ", " : "  ");
01134         col= 6;
01135       }
01136       else
01137       {
01138         printf("  ");
01139         col= 2;
01140       }
01141       if (strlen(optp->name))
01142       {
01143         printf("--%s", optp->name);
01144         col+= 2 + (uint32_t) strlen(optp->name);
01145         if ((optp->var_type & GET_TYPE_MASK) == GET_STR ||
01146             (optp->var_type & GET_TYPE_MASK) == GET_STR_ALLOC)
01147         {
01148           printf("%s=name%s ", optp->arg_type == OPT_ARG ? "[" : "",
01149               optp->arg_type == OPT_ARG ? "]" : "");
01150           col+= (optp->arg_type == OPT_ARG) ? 8 : 6;
01151         }
01152         else if ((optp->var_type & GET_TYPE_MASK) == GET_NO_ARG ||
01153             (optp->var_type & GET_TYPE_MASK) == GET_BOOL)
01154         {
01155           putchar(' ');
01156           col++;
01157         }
01158         else
01159         {
01160           printf("%s=#%s ", optp->arg_type == OPT_ARG ? "[" : "",
01161               optp->arg_type == OPT_ARG ? "]" : "");
01162           col+= (optp->arg_type == OPT_ARG) ? 5 : 3;
01163         }
01164         if (col > name_space && optp->comment && *optp->comment)
01165         {
01166           putchar('\n');
01167           col= 0;
01168         }
01169       }
01170       for (; col < name_space; col++)
01171         putchar(' ');
01172       if (optp->comment && *optp->comment)
01173       {
01174         const char *comment= _(optp->comment), *end= strchr(comment, '\0');
01175 
01176         while ((uint32_t) (end - comment) > comment_space)
01177         {
01178           for (line_end= comment + comment_space; *line_end != ' '; line_end--)
01179           {}
01180           for (; comment != line_end; comment++)
01181             putchar(*comment);
01182           comment++; /* skip the space, as a newline will take it's place now */
01183           putchar('\n');
01184           for (col= 0; col < name_space; col++)
01185             putchar(' ');
01186         }
01187         printf("%s", comment);
01188       }
01189       putchar('\n');
01190       if ((optp->var_type & GET_TYPE_MASK) == GET_NO_ARG ||
01191           (optp->var_type & GET_TYPE_MASK) == GET_BOOL)
01192       {
01193         if (optp->def_value != 0)
01194         {
01195           printf(_("%*s(Defaults to on; use --skip-%s to disable.)\n"), name_space, "", optp->name);
01196         }
01197       }
01198     }
01199   }
01200 
01201 
01202   /*
01203 function: my_print_options
01204 
01205 Print variables.
01206    */
01207 
01208   void my_print_variables(const struct option *options)
01209   {
01210     uint32_t name_space= 34, length, nr;
01211     uint64_t bit, llvalue;
01212     char buff[255];
01213     const struct option *optp;
01214 
01215     printf(_("\nVariables (--variable-name=value)\n"
01216           "and boolean options {false|true}  Value (after reading options)\n"
01217           "--------------------------------- -----------------------------\n"));
01218     for (optp= options; optp->id; optp++)
01219     {
01220       char* *value= (optp->var_type & GET_ASK_ADDR ?
01221           (*getopt_get_addr)("", 0, optp) : optp->value);
01222       if (value)
01223       {
01224         printf("%s ", optp->name);
01225         length= (uint32_t) strlen(optp->name)+1;
01226         for (; length < name_space; length++)
01227           putchar(' ');
01228         switch ((optp->var_type & GET_TYPE_MASK)) {
01229           case GET_SET:
01230             if (!(llvalue= *(uint64_t*) value))
01231               printf("%s\n", _("(No default value)"));
01232             else
01233               for (nr= 0, bit= 1; llvalue && nr < optp->typelib->count; nr++, bit<<=1)
01234               {
01235                 if (!(bit & llvalue))
01236                   continue;
01237                 llvalue&= ~bit;
01238                 printf( llvalue ? "%s," : "%s\n", optp->typelib->get_type(nr));
01239               }
01240             break;
01241           case GET_ENUM:
01242             printf("%s\n", optp->typelib->get_type(*(uint*) value));
01243             break;
01244           case GET_STR:
01245           case GET_STR_ALLOC:                    /* fall through */
01246             printf("%s\n", *((char**) value) ? *((char**) value) :
01247                 _("(No default value)"));
01248             break;
01249           case GET_BOOL:
01250             printf("%s\n", *((bool*) value) ? _("true") : _("false"));
01251             break;
01252           case GET_INT:
01253             printf("%d\n", *((int*) value));
01254             break;
01255           case GET_UINT:
01256             printf("%d\n", *((uint*) value));
01257             break;
01258           case GET_LONG:
01259             printf("%ld\n", *((long*) value));
01260             break;
01261           case GET_UINT32:
01262             printf("%u\n", *((uint32_t*) value));
01263             break;
01264           case GET_ULONG_IS_FAIL:
01265             printf("%lu\n", *((ulong*) value));
01266             break;
01267           case GET_SIZE:
01268             internal::int64_t2str((uint64_t)(*(size_t*)value), buff, 10);
01269             printf("%s\n", buff);
01270             break;
01271           case GET_LL:
01272             printf("%s\n", internal::llstr(*((int64_t*) value), buff));
01273             break;
01274           case GET_ULL:
01275           case GET_UINT64:
01276             internal::int64_t2str(*((uint64_t*) value), buff, 10);
01277             printf("%s\n", buff);
01278             break;
01279           case GET_DOUBLE:
01280             printf("%g\n", *(double*) value);
01281             break;
01282           default:
01283             printf(_("(Disabled)\n"));
01284             break;
01285         }
01286       }
01287     }
01288   }
01289 
01290 } /* namespace drizzled */