~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/option.cc

  • Committer: Monty Taylor
  • Date: 2011-02-13 17:26:39 UTC
  • mfrom: (2157.2.2 give-in-to-pkg-config)
  • mto: This revision was merged to the branch mainline in revision 2166.
  • Revision ID: mordred@inaugust.com-20110213172639-nhy7i72sfhoq13ms
Merged in pkg-config fixes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
13
13
   along with this program; if not, write to the Free Software
14
14
   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
15
15
 
16
 
#include <config.h>
17
 
#include <drizzled/definitions.h>
18
 
#include <drizzled/charset.h>
19
 
#include <drizzled/internal/my_sys.h>
 
16
#include "config.h"
 
17
#include "drizzled/internal/my_sys.h"
20
18
#include <drizzled/gettext.h>
21
19
 
22
 
#include <drizzled/internal/m_string.h>
23
 
#include <drizzled/internal/my_sys.h>
24
 
#include <drizzled/error.h>
25
 
#include <drizzled/option.h>
26
 
#include <drizzled/typelib.h>
 
20
#include "drizzled/internal/m_string.h"
 
21
#include "drizzled/internal/my_sys.h"
 
22
#include "drizzled/error.h"
 
23
#include "drizzled/option.h"
 
24
#include "drizzled/typelib.h"
27
25
 
28
26
#include <stdio.h>
29
27
#include <stdlib.h>
32
30
#include <algorithm>
33
31
 
34
32
using namespace std;
35
 
 
36
 
namespace drizzled {
 
33
namespace drizzled
 
34
{
37
35
 
38
36
  typedef void (*init_func_p)(const struct option *option, char **variable,
39
37
      int64_t value);
41
39
  void default_reporter(enum loglevel level, const char *format, ...);
42
40
  my_error_reporter my_getopt_error_reporter= &default_reporter;
43
41
 
 
42
  static int findopt(char *optpat, uint32_t length,
 
43
      const struct option **opt_res,
 
44
      char **ffname);
 
45
  static int64_t getopt_ll(char *arg, const struct option *optp, int *err);
 
46
  static uint64_t getopt_ull(char *arg, const struct option *optp,
 
47
      int *err);
 
48
  static size_t getopt_size(char *arg, const struct option *optp, int *err);
 
49
  static double getopt_double(char *arg, const struct option *optp, int *err);
 
50
  static void init_variables(const struct option *options,
 
51
      init_func_p init_one_value);
 
52
  static void init_one_value(const struct option *option, char **variable,
 
53
      int64_t value);
 
54
  static void fini_one_value(const struct option *option, char **variable,
 
55
      int64_t value);
 
56
  static int setval(const struct option *opts, char* *value, char *argument,
 
57
      bool set_maximum_value);
 
58
  static char *check_struct_option(char *cur_arg, char *key_name);
 
59
 
44
60
  /*
45
61
     The following three variables belong to same group and the number and
46
62
     order of their arguments must correspond to each other.
47
63
   */
 
64
  static const char *special_opt_prefix[]=
 
65
  {"skip", "disable", "enable", "maximum", "loose", 0};
48
66
  static const uint32_t special_opt_prefix_lengths[]=
49
67
  { 4,      7,         6,        7,         5,      0};
50
68
  enum enum_special_opt
74
92
  }
75
93
 
76
94
  /*
 
95
function: handle_options
 
96
 
 
97
Sort options; put options first, until special end of options (--), or
 
98
until end of argv. Parse options; check that the given option matches with
 
99
one of the options in struct 'option', return error in case of ambiguous
 
100
or unknown option. Check that option was given an argument if it requires
 
101
one. Call function 'get_one_option()' once for each option.
 
102
   */
 
103
 
 
104
  static getopt_get_addr_func getopt_get_addr;
 
105
 
 
106
  int handle_options(int *argc, char ***argv,
 
107
      const struct option *longopts,
 
108
      my_get_one_option get_one_option)
 
109
  {
 
110
    uint32_t opt_found, argvpos= 0, length;
 
111
    bool end_of_options= 0, must_be_var, set_maximum_value=false,
 
112
         option_is_loose;
 
113
    char **pos, **pos_end, *optend, *prev_found=NULL,
 
114
         *opt_str, key_name[FN_REFLEN];
 
115
    const struct option *optp;
 
116
    char* *value;
 
117
    int error, i;
 
118
 
 
119
    /* handle_options() assumes arg0 (program name) always exists */
 
120
    assert(argc && *argc >= 1);
 
121
    assert(argv && *argv);
 
122
    (*argc)--; /* Skip the program name */
 
123
    (*argv)++; /*      --- || ----      */
 
124
    init_variables(longopts, init_one_value);
 
125
 
 
126
    for (pos= *argv, pos_end=pos+ *argc; pos != pos_end ; pos++)
 
127
    {
 
128
      char **first= pos;
 
129
      char *cur_arg= *pos;
 
130
      if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */
 
131
      {
 
132
        char *argument=    0;
 
133
        must_be_var=       0;
 
134
        set_maximum_value= 0;
 
135
        option_is_loose=   0;
 
136
 
 
137
        cur_arg++;  /* skip '-' */
 
138
        if (*cur_arg == '-' || *cur_arg == 'O') /* check for long option, */
 
139
        {                                       /* --set-variable, or -O  */
 
140
          if (*cur_arg == 'O')
 
141
          {
 
142
            must_be_var= 1;
 
143
 
 
144
            if (!(*++cur_arg))  /* If not -Ovar=# */
 
145
            {
 
146
              /* the argument must be in next argv */
 
147
              if (!*++pos)
 
148
              {
 
149
                my_getopt_error_reporter(ERROR_LEVEL,
 
150
                    "%s: Option '-O' requires an argument",
 
151
                    internal::my_progname);
 
152
                return EXIT_ARGUMENT_REQUIRED;
 
153
              }
 
154
              cur_arg= *pos;
 
155
              (*argc)--;
 
156
            }
 
157
          }
 
158
          else if (!getopt_compare_strings(cur_arg, "-set-variable", 13))
 
159
          {
 
160
            must_be_var= 1;
 
161
            if (cur_arg[13] == '=')
 
162
            {
 
163
              cur_arg+= 14;
 
164
              if (!*cur_arg)
 
165
              {
 
166
                my_getopt_error_reporter(ERROR_LEVEL,
 
167
                    "%s: Option '--set-variable' requires an argument",
 
168
                    internal::my_progname);
 
169
                return EXIT_ARGUMENT_REQUIRED;
 
170
              }
 
171
            }
 
172
            else if (cur_arg[14]) /* garbage, or another option. break out */
 
173
              must_be_var= 0;
 
174
            else
 
175
            {
 
176
              /* the argument must be in next argv */
 
177
              if (!*++pos)
 
178
              {
 
179
                my_getopt_error_reporter(ERROR_LEVEL,
 
180
                    "%s: Option '--set-variable' requires an argument",
 
181
                    internal::my_progname);
 
182
                return EXIT_ARGUMENT_REQUIRED;
 
183
              }
 
184
              cur_arg= *pos;
 
185
              (*argc)--;
 
186
            }
 
187
          }
 
188
          else if (!must_be_var)
 
189
          {
 
190
            if (!*++cur_arg)    /* skip the double dash */
 
191
            {
 
192
              /* '--' means end of options, look no further */
 
193
              end_of_options= 1;
 
194
              (*argc)--;
 
195
              continue;
 
196
            }
 
197
          }
 
198
          opt_str= check_struct_option(cur_arg, key_name);
 
199
          optend= strchr(opt_str, '=');
 
200
          if (optend != NULL)
 
201
          {
 
202
            length= (uint32_t) (optend - opt_str);
 
203
            optend++;
 
204
          }
 
205
          else
 
206
          {
 
207
            length= static_cast<uint32_t>(strlen(opt_str));
 
208
            optend= 0;
 
209
          }
 
210
 
 
211
          /*
 
212
             Find first the right option. Return error in case of an ambiguous,
 
213
             or unknown option
 
214
           */
 
215
          optp= longopts;
 
216
          if (!(opt_found= findopt(opt_str, length, &optp, &prev_found)))
 
217
          {
 
218
            /*
 
219
               Didn't find any matching option. Let's see if someone called
 
220
               option with a special option prefix
 
221
             */
 
222
            if (!must_be_var)
 
223
            {
 
224
              if (optend)
 
225
                must_be_var= 1; /* option is followed by an argument */
 
226
              for (i= 0; special_opt_prefix[i]; i++)
 
227
              {
 
228
                if (!getopt_compare_strings(special_opt_prefix[i], opt_str,
 
229
                      special_opt_prefix_lengths[i]) &&
 
230
                    (opt_str[special_opt_prefix_lengths[i]] == '-' ||
 
231
                     opt_str[special_opt_prefix_lengths[i]] == '_'))
 
232
                {
 
233
                  /*
 
234
                     We were called with a special prefix, we can reuse opt_found
 
235
                   */
 
236
                  opt_str+= special_opt_prefix_lengths[i] + 1;
 
237
                  length-= special_opt_prefix_lengths[i] + 1;
 
238
                  if (i == OPT_LOOSE)
 
239
                    option_is_loose= 1;
 
240
                  if ((opt_found= findopt(opt_str, length, &optp, &prev_found)))
 
241
                  {
 
242
                    if (opt_found > 1)
 
243
                    {
 
244
                      my_getopt_error_reporter(ERROR_LEVEL,
 
245
                          "%s: ambiguous option '--%s-%s' (--%s-%s)",
 
246
                          internal::my_progname,
 
247
                          special_opt_prefix[i],
 
248
                          cur_arg, special_opt_prefix[i],
 
249
                          prev_found);
 
250
                      return EXIT_AMBIGUOUS_OPTION;
 
251
                    }
 
252
                    switch (i) {
 
253
                      case OPT_SKIP:
 
254
                      case OPT_DISABLE: /* fall through */
 
255
                        /*
 
256
                           double negation is actually enable again,
 
257
                           for example: --skip-option=0 -> option = true
 
258
                         */
 
259
                        optend= (optend && *optend == '0' && !(*(optend + 1))) ?
 
260
                          (char*) "1" : disabled_my_option;
 
261
                        break;
 
262
                      case OPT_ENABLE:
 
263
                        optend= (optend && *optend == '0' && !(*(optend + 1))) ?
 
264
                          disabled_my_option : (char*) "1";
 
265
                        break;
 
266
                      case OPT_MAXIMUM:
 
267
                        set_maximum_value= true;
 
268
                        must_be_var= true;
 
269
                        break;
 
270
                    }
 
271
                    break; /* break from the inner loop, main loop continues */
 
272
                  }
 
273
                  i= -1; /* restart the loop */
 
274
                }
 
275
              }
 
276
            }
 
277
            if (!opt_found)
 
278
            {
 
279
              if (my_getopt_skip_unknown)
 
280
              {
 
281
                /*
 
282
                   preserve all the components of this unknown option, this may
 
283
                   occurr when the user provides options like: "-O foo" or
 
284
                   "--set-variable foo" (note that theres a space in there)
 
285
                   Generally, these kind of options are to be avoided
 
286
                 */
 
287
                do {
 
288
                  (*argv)[argvpos++]= *first++;
 
289
                } while (first <= pos);
 
290
                continue;
 
291
              }
 
292
              if (must_be_var)
 
293
              {
 
294
                my_getopt_error_reporter(option_is_loose ?
 
295
                    WARNING_LEVEL : ERROR_LEVEL,
 
296
                    "%s: unknown variable '%s'",
 
297
                    internal::my_progname, cur_arg);
 
298
                if (!option_is_loose)
 
299
                  return EXIT_UNKNOWN_VARIABLE;
 
300
              }
 
301
              else
 
302
              {
 
303
                my_getopt_error_reporter(option_is_loose ?
 
304
                    WARNING_LEVEL : ERROR_LEVEL,
 
305
                    "%s: unknown option '--%s'",
 
306
                    internal::my_progname, cur_arg);
 
307
                if (!option_is_loose)
 
308
                  return EXIT_UNKNOWN_OPTION;
 
309
              }
 
310
              if (option_is_loose)
 
311
              {
 
312
                (*argc)--;
 
313
                continue;
 
314
              }
 
315
            }
 
316
          }
 
317
          if (opt_found > 1)
 
318
          {
 
319
            if (must_be_var)
 
320
            {
 
321
              my_getopt_error_reporter(ERROR_LEVEL,
 
322
                  "%s: variable prefix '%s' is not unique",
 
323
                  internal::my_progname, opt_str);
 
324
              return EXIT_VAR_PREFIX_NOT_UNIQUE;
 
325
            }
 
326
            else
 
327
            {
 
328
              my_getopt_error_reporter(ERROR_LEVEL,
 
329
                  "%s: ambiguous option '--%s' (%s, %s)",
 
330
                  internal::my_progname, opt_str, prev_found,
 
331
                  optp->name);
 
332
              return EXIT_AMBIGUOUS_OPTION;
 
333
            }
 
334
          }
 
335
          if ((optp->var_type & GET_TYPE_MASK) == GET_DISABLED)
 
336
          {
 
337
            fprintf(stderr,
 
338
                _("%s: %s: Option '%s' used, but is disabled\n"),
 
339
                internal::my_progname,
 
340
                option_is_loose ? _("WARNING") : _("ERROR"), opt_str);
 
341
            if (option_is_loose)
 
342
            {
 
343
              (*argc)--;
 
344
              continue;
 
345
            }
 
346
            return EXIT_OPTION_DISABLED;
 
347
          }
 
348
          if (must_be_var && (optp->var_type & GET_TYPE_MASK) == GET_NO_ARG)
 
349
          {
 
350
            my_getopt_error_reporter(ERROR_LEVEL,
 
351
                "%s: option '%s' cannot take an argument",
 
352
                internal::my_progname, optp->name);
 
353
            return EXIT_NO_ARGUMENT_ALLOWED;
 
354
          }
 
355
          value= optp->var_type & GET_ASK_ADDR ?
 
356
            (*getopt_get_addr)(key_name, (uint32_t) strlen(key_name), optp) : optp->value;
 
357
 
 
358
          if (optp->arg_type == NO_ARG)
 
359
          {
 
360
            if (optend && (optp->var_type & GET_TYPE_MASK) != GET_BOOL)
 
361
            {
 
362
              my_getopt_error_reporter(ERROR_LEVEL,
 
363
                  "%s: option '--%s' cannot take an argument",
 
364
                  internal::my_progname, optp->name);
 
365
              return EXIT_NO_ARGUMENT_ALLOWED;
 
366
            }
 
367
            if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL)
 
368
            {
 
369
              /*
 
370
                 Set bool to 1 if no argument or if the user has used
 
371
                 --enable-'option-name'.
 
372
               *optend was set to '0' if one used --disable-option
 
373
               */
 
374
              (*argc)--;
 
375
              if (!optend || *optend == '1' ||
 
376
                  !my_strcasecmp(&my_charset_utf8_general_ci, optend, "true"))
 
377
                *((bool*) value)= (bool) 1;
 
378
              else if (*optend == '0' ||
 
379
                  !my_strcasecmp(&my_charset_utf8_general_ci, optend, "false"))
 
380
                *((bool*) value)= (bool) 0;
 
381
              else
 
382
              {
 
383
                my_getopt_error_reporter(WARNING_LEVEL,
 
384
                    "%s: ignoring option '--%s' due to "
 
385
                    "invalid value '%s'",
 
386
                    internal::my_progname,
 
387
                    optp->name, optend);
 
388
                continue;
 
389
              }
 
390
              error= get_one_option(optp->id, optp, *((bool*) value) ?
 
391
                                    (char*) "1" : disabled_my_option);
 
392
              if (error != 0)
 
393
                return error;
 
394
              else
 
395
                continue;
 
396
            }
 
397
            argument= optend;
 
398
          }
 
399
          else if (optp->arg_type == OPT_ARG &&
 
400
              (optp->var_type & GET_TYPE_MASK) == GET_BOOL)
 
401
          {
 
402
            if (optend == disabled_my_option)
 
403
              *((bool*) value)= (bool) 0;
 
404
            else
 
405
            {
 
406
              if (!optend) /* No argument -> enable option */
 
407
                *((bool*) value)= (bool) 1;
 
408
              else
 
409
                argument= optend;
 
410
            }
 
411
          }
 
412
          else if (optp->arg_type == REQUIRED_ARG && !optend)
 
413
          {
 
414
            /* Check if there are more arguments after this one */
 
415
            if (!*++pos)
 
416
            {
 
417
              my_getopt_error_reporter(ERROR_LEVEL,
 
418
                  "%s: option '--%s' requires an argument",
 
419
                  internal::my_progname, optp->name);
 
420
              return EXIT_ARGUMENT_REQUIRED;
 
421
            }
 
422
            argument= *pos;
 
423
            (*argc)--;
 
424
          }
 
425
          else
 
426
            argument= optend;
 
427
        }
 
428
        else  /* must be short option */
 
429
        {
 
430
          for (optend= cur_arg; *optend; optend++)
 
431
          {
 
432
            opt_found= 0;
 
433
            for (optp= longopts; optp->id; optp++)
 
434
            {
 
435
              if (optp->id == (int) (unsigned char) *optend)
 
436
              {
 
437
                /* Option recognized. Find next what to do with it */
 
438
                opt_found= 1;
 
439
                if ((optp->var_type & GET_TYPE_MASK) == GET_DISABLED)
 
440
                {
 
441
                  fprintf(stderr,
 
442
                      _("%s: ERROR: Option '-%c' used, but is disabled\n"),
 
443
                      internal::my_progname, optp->id);
 
444
                  return EXIT_OPTION_DISABLED;
 
445
                }
 
446
                if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL &&
 
447
                    optp->arg_type == NO_ARG)
 
448
                {
 
449
                  *((bool*) optp->value)= (bool) 1;
 
450
                  error= get_one_option(optp->id, optp, argument);
 
451
                  if (error != 0)
 
452
                    return error;
 
453
                  else
 
454
                    continue;
 
455
 
 
456
                }
 
457
                else if (optp->arg_type == REQUIRED_ARG ||
 
458
                    optp->arg_type == OPT_ARG)
 
459
                {
 
460
                  if (*(optend + 1))
 
461
                  {
 
462
                    /* The rest of the option is option argument */
 
463
                    argument= optend + 1;
 
464
                    /* This is in effect a jump out of the outer loop */
 
465
                    optend= (char*) " ";
 
466
                  }
 
467
                  else
 
468
                  {
 
469
                    if (optp->arg_type == OPT_ARG)
 
470
                    {
 
471
                      if (optp->var_type == GET_BOOL)
 
472
                        *((bool*) optp->value)= (bool) 1;
 
473
                      error= get_one_option(optp->id, optp, argument);
 
474
                      if (error != 0)
 
475
                        return error;
 
476
                      else
 
477
                        continue;
 
478
                    }
 
479
                    /* Check if there are more arguments after this one */
 
480
                    if (!pos[1])
 
481
                    {
 
482
                      my_getopt_error_reporter(ERROR_LEVEL,
 
483
                          "%s: option '-%c' requires "
 
484
                          "an argument",
 
485
                          internal::my_progname, optp->id);
 
486
                      return EXIT_ARGUMENT_REQUIRED;
 
487
                    }
 
488
                    argument= *++pos;
 
489
                    (*argc)--;
 
490
                    /* the other loop will break, because *optend + 1 == 0 */
 
491
                  }
 
492
                }
 
493
                if ((error= setval(optp, optp->value, argument,
 
494
                        set_maximum_value)))
 
495
                {
 
496
                  my_getopt_error_reporter(ERROR_LEVEL,
 
497
                      "%s: Error while setting value '%s' "
 
498
                      "to '%s'",
 
499
                      internal::my_progname,
 
500
                      argument, optp->name);
 
501
                  return error;
 
502
                }
 
503
                error= get_one_option(optp->id, optp, argument);
 
504
                if (error != 0)
 
505
                  return error;
 
506
                else
 
507
                  break;
 
508
              }
 
509
            }
 
510
            if (!opt_found)
 
511
            {
 
512
              my_getopt_error_reporter(ERROR_LEVEL,
 
513
                  "%s: unknown option '-%c'",
 
514
                  internal::my_progname, *optend);
 
515
              return EXIT_UNKNOWN_OPTION;
 
516
            }
 
517
          }
 
518
          (*argc)--; /* option handled (short), decrease argument count */
 
519
          continue;
 
520
        }
 
521
        if ((error= setval(optp, value, argument, set_maximum_value)))
 
522
        {
 
523
          my_getopt_error_reporter(ERROR_LEVEL,
 
524
              "%s: Error while setting value '%s' to '%s'",
 
525
              internal::my_progname, argument, optp->name);
 
526
          return error;
 
527
        }
 
528
        error= get_one_option(optp->id, optp, argument);
 
529
        if (error != 0)
 
530
          return error;
 
531
 
 
532
        (*argc)--; /* option handled (short or long), decrease argument count */
 
533
      }
 
534
      else /* non-option found */
 
535
        (*argv)[argvpos++]= cur_arg;
 
536
    }
 
537
    /*
 
538
       Destroy the first, already handled option, so that programs that look
 
539
       for arguments in 'argv', without checking 'argc', know when to stop.
 
540
       Items in argv, before the destroyed one, are all non-option -arguments
 
541
       to the program, yet to be (possibly) handled.
 
542
     */
 
543
    (*argv)[argvpos]= 0;
 
544
    return 0;
 
545
  }
 
546
 
 
547
 
 
548
  /*
 
549
function: check_struct_option
 
550
 
 
551
Arguments: Current argument under processing from argv and a variable
 
552
where to store the possible key name.
 
553
 
 
554
Return value: In case option is a struct option, returns a pointer to
 
555
the current argument at the position where the struct option (key_name)
 
556
ends, the next character after the dot. In case argument is not a struct
 
557
option, returns a pointer to the argument.
 
558
 
 
559
key_name will hold the name of the key, or 0 if not found.
 
560
   */
 
561
 
 
562
  static char *check_struct_option(char *cur_arg, char *key_name)
 
563
  {
 
564
    char *ptr, *end;
 
565
 
 
566
    ptr= NULL; //Options with '.' are now supported.
 
567
    end= strrchr(cur_arg, '=');
 
568
 
 
569
    /*
 
570
       If the first dot is after an equal sign, then it is part
 
571
       of a variable value and the option is not a struct option.
 
572
       Also, if the last character in the string before the ending
 
573
       NULL, or the character right before equal sign is the first
 
574
       dot found, the option is not a struct option.
 
575
     */
 
576
    if ((ptr != NULL) && (end != NULL) && (end - ptr > 1))
 
577
    {
 
578
      uint32_t len= (uint32_t) (ptr - cur_arg);
 
579
      set_if_smaller(len, (uint32_t)FN_REFLEN-1);
 
580
      strncpy(key_name, cur_arg, len);
 
581
      return ++ptr;
 
582
    }
 
583
    key_name[0]= 0;
 
584
    return cur_arg;
 
585
  }
 
586
 
 
587
  /*
 
588
function: setval
 
589
 
 
590
Arguments: opts, argument
 
591
Will set the option value to given value
 
592
   */
 
593
 
 
594
  static int setval(const struct option *opts, char **value, char *argument,
 
595
      bool set_maximum_value)
 
596
  {
 
597
    int err= 0;
 
598
 
 
599
    if (value && argument)
 
600
    {
 
601
      char* *result_pos= ((set_maximum_value) ?
 
602
          opts->u_max_value : value);
 
603
 
 
604
      if (!result_pos)
 
605
        return EXIT_NO_PTR_TO_VARIABLE;
 
606
 
 
607
      switch ((opts->var_type & GET_TYPE_MASK)) {
 
608
        case GET_BOOL: /* If argument differs from 0, enable option, else disable */
 
609
          *((bool*) result_pos)= (bool) atoi(argument) != 0;
 
610
          break;
 
611
        case GET_INT:
 
612
          *((int32_t*) result_pos)= (int) getopt_ll(argument, opts, &err);
 
613
          break;
 
614
        case GET_UINT:
 
615
        case GET_UINT32:
 
616
          *((uint32_t*) result_pos)= (uint32_t) getopt_ull(argument, opts, &err);
 
617
          break;
 
618
        case GET_ULONG_IS_FAIL:
 
619
          *((ulong*) result_pos)= (ulong) getopt_ull(argument, opts, &err);
 
620
          break;
 
621
        case GET_LONG:
 
622
          *((long*) result_pos)= (long) getopt_ll(argument, opts, &err);
 
623
          break;
 
624
        case GET_LL:
 
625
          *((int64_t*) result_pos)= getopt_ll(argument, opts, &err);
 
626
          break;
 
627
        case GET_ULL:
 
628
        case GET_UINT64:
 
629
          *((uint64_t*) result_pos)= getopt_ull(argument, opts, &err);
 
630
          break;
 
631
        case GET_SIZE:
 
632
          *((size_t*) result_pos)= getopt_size(argument, opts, &err);
 
633
          break;
 
634
        case GET_DOUBLE:
 
635
          *((double*) result_pos)= getopt_double(argument, opts, &err);
 
636
          break;
 
637
        case GET_STR:
 
638
          *((char**) result_pos)= argument;
 
639
          break;
 
640
        case GET_STR_ALLOC:
 
641
          if ((*((char**) result_pos)))
 
642
            free((*(char**) result_pos));
 
643
          if (!(*((char**) result_pos)= strdup(argument)))
 
644
            return EXIT_OUT_OF_MEMORY;
 
645
          break;
 
646
        case GET_ENUM:
 
647
          if (((*(int*)result_pos)= opts->typelib->find_type(argument, 2) - 1) < 0)
 
648
            return EXIT_ARGUMENT_INVALID;
 
649
          break;
 
650
        case GET_SET:
 
651
          *((uint64_t*)result_pos)= opts->typelib->find_typeset(argument, &err);
 
652
          if (err)
 
653
            return EXIT_ARGUMENT_INVALID;
 
654
          break;
 
655
        default:    /* dummy default to avoid compiler warnings */
 
656
          break;
 
657
      }
 
658
      if (err)
 
659
        return EXIT_UNKNOWN_SUFFIX;
 
660
    }
 
661
    return 0;
 
662
  }
 
663
 
 
664
 
 
665
  /*
 
666
     Find option
 
667
 
 
668
     SYNOPSIS
 
669
     findopt()
 
670
     optpat     Prefix of option to find (with - or _)
 
671
     length     Length of optpat
 
672
     opt_res    Options
 
673
     ffname     Place for pointer to first found name
 
674
 
 
675
     IMPLEMENTATION
 
676
     Go through all options in the option struct. Return number
 
677
     of options found that match the pattern and in the argument
 
678
     list the option found, if any. In case of ambiguous option, store
 
679
     the name in ffname argument
 
680
 
 
681
     RETURN
 
682
     0    No matching options
 
683
#   Number of matching options
 
684
ffname points to first matching option
 
685
   */
 
686
 
 
687
  static int findopt(char *optpat, uint32_t length,
 
688
      const struct option **opt_res,
 
689
      char **ffname)
 
690
  {
 
691
    uint32_t count;
 
692
    struct option *opt= (struct option *) *opt_res;
 
693
 
 
694
    for (count= 0; opt->name; opt++)
 
695
    {
 
696
      if (!getopt_compare_strings(opt->name, optpat, length)) /* match found */
 
697
      {
 
698
        (*opt_res)= opt;
 
699
        if (!opt->name[length])         /* Exact match */
 
700
          return 1;
 
701
        if (!count)
 
702
        {
 
703
          count= 1;
 
704
          *ffname= (char *) opt->name;  /* We only need to know one prev */
 
705
        }
 
706
        else if (strcmp(*ffname, opt->name))
 
707
        {
 
708
          /*
 
709
             The above test is to not count same option twice
 
710
             (see mysql.cc, option "help")
 
711
           */
 
712
          count++;
 
713
        }
 
714
      }
 
715
    }
 
716
    return count;
 
717
  }
 
718
 
 
719
 
 
720
  /*
77
721
function: compare_strings
78
722
 
79
723
Works like strncmp, other than 1.) considers '-' and '_' the same.
80
724
2.) Returns -1 if strings differ, 0 if they are equal
81
725
   */
82
726
 
83
 
  bool getopt_compare_strings(const char *s, const char *t,
 
727
  bool getopt_compare_strings(register const char *s, register const char *t,
84
728
      uint32_t length)
85
729
  {
86
730
    char const *end= s + length;
93
737
  }
94
738
 
95
739
  /*
 
740
function: eval_num_suffix
 
741
 
 
742
Transforms a number with a suffix to real number. Suffix can
 
743
be k|K for kilo, m|M for mega or g|G for giga.
 
744
   */
 
745
 
 
746
  static int64_t eval_num_suffix(char *argument, int *error, char *option_name)
 
747
  {
 
748
    char *endchar;
 
749
    int64_t num;
 
750
 
 
751
    *error= 0;
 
752
    errno= 0;
 
753
    num= strtoll(argument, &endchar, 10);
 
754
    if (errno == ERANGE)
 
755
    {
 
756
      my_getopt_error_reporter(ERROR_LEVEL,
 
757
          "Incorrect integer value: '%s'", argument);
 
758
      *error= 1;
 
759
      return 0;
 
760
    }
 
761
    if (*endchar == 'k' || *endchar == 'K')
 
762
      num*= 1024L;
 
763
    else if (*endchar == 'm' || *endchar == 'M')
 
764
      num*= 1024L * 1024L;
 
765
    else if (*endchar == 'g' || *endchar == 'G')
 
766
      num*= 1024L * 1024L * 1024L;
 
767
    else if (*endchar)
 
768
    {
 
769
      fprintf(stderr,
 
770
          _("Unknown suffix '%c' used for variable '%s' (value '%s')\n"),
 
771
          *endchar, option_name, argument);
 
772
      *error= 1;
 
773
      return 0;
 
774
    }
 
775
    return num;
 
776
  }
 
777
 
 
778
  /*
 
779
function: getopt_ll
 
780
 
 
781
Evaluates and returns the value that user gave as an argument
 
782
to a variable. Recognizes (case insensitive) K as KILO, M as MEGA
 
783
and G as GIGA bytes. Some values must be in certain blocks, as
 
784
defined in the given option struct, this function will check
 
785
that those values are honored.
 
786
In case of an error, set error value in *err.
 
787
   */
 
788
 
 
789
  static int64_t getopt_ll(char *arg, const struct option *optp, int *err)
 
790
  {
 
791
    int64_t num=eval_num_suffix(arg, err, (char*) optp->name);
 
792
    return getopt_ll_limit_value(num, optp, NULL);
 
793
  }
 
794
 
 
795
  /*
96
796
function: getopt_ll_limit_value
97
797
 
98
798
Applies min/max/block_size to a numeric value of an option.
159
859
values.
160
860
   */
161
861
 
 
862
  static uint64_t getopt_ull(char *arg, const struct option *optp, int *err)
 
863
  {
 
864
    uint64_t num= eval_num_suffix(arg, err, (char*) optp->name);
 
865
    return getopt_ull_limit_value(num, optp, NULL);
 
866
  }
 
867
 
 
868
 
 
869
  static size_t getopt_size(char *arg, const struct option *optp, int *err)
 
870
  {
 
871
    return (size_t)getopt_ull(arg, optp, err);
 
872
  }
 
873
 
 
874
 
 
875
 
162
876
  uint64_t getopt_ull_limit_value(uint64_t num, const struct option *optp,
163
877
      bool *fix)
164
878
  {
224
938
    return num;
225
939
  }
226
940
 
227
 
  
 
941
 
 
942
  /*
 
943
     Get double value withing ranges
 
944
 
 
945
     Evaluates and returns the value that user gave as an argument to a variable.
 
946
 
 
947
     RETURN
 
948
     decimal value of arg
 
949
 
 
950
     In case of an error, prints an error message and sets *err to
 
951
     EXIT_ARGUMENT_INVALID.  Otherwise err is not touched
 
952
   */
 
953
 
 
954
  static double getopt_double(char *arg, const struct option *optp, int *err)
 
955
  {
 
956
    double num;
 
957
    int error;
 
958
    char *end= arg + 1000;                     /* Big enough as *arg is \0 terminated */
 
959
    num= internal::my_strtod(arg, &end, &error);
 
960
    if (end[0] != 0 || error)
 
961
    {
 
962
      fprintf(stderr,
 
963
          _("%s: ERROR: Invalid decimal value for option '%s'\n"),
 
964
          internal::my_progname, optp->name);
 
965
      *err= EXIT_ARGUMENT_INVALID;
 
966
      return 0.0;
 
967
    }
 
968
    if (optp->max_value && num > (double) optp->max_value)
 
969
      num= (double) optp->max_value;
 
970
    return max(num, (double) optp->min_value);
 
971
  }
 
972
 
 
973
  /*
 
974
     Init one value to it's default values
 
975
 
 
976
     SYNOPSIS
 
977
     init_one_value()
 
978
     option             Option to initialize
 
979
     value              Pointer to variable
 
980
   */
 
981
 
 
982
  static void init_one_value(const struct option *option, char** variable,
 
983
      int64_t value)
 
984
  {
 
985
    switch ((option->var_type & GET_TYPE_MASK)) {
 
986
      case GET_BOOL:
 
987
        *((bool*) variable)= (bool) value;
 
988
        break;
 
989
      case GET_INT:
 
990
        *((int*) variable)= (int) value;
 
991
        break;
 
992
      case GET_UINT:
 
993
      case GET_ENUM:
 
994
        *((uint*) variable)= (uint32_t) value;
 
995
        break;
 
996
      case GET_LONG:
 
997
        *((long*) variable)= (long) value;
 
998
        break;
 
999
      case GET_UINT32:
 
1000
        *((uint32_t*) variable)= (uint32_t) value;
 
1001
        break;
 
1002
      case GET_ULONG_IS_FAIL:
 
1003
        *((ulong*) variable)= (ulong) value;
 
1004
        break;
 
1005
      case GET_LL:
 
1006
        *((int64_t*) variable)= (int64_t) value;
 
1007
        break;
 
1008
      case GET_SIZE:
 
1009
        *((size_t*) variable)= (size_t) value;
 
1010
        break;
 
1011
      case GET_ULL:
 
1012
      case GET_SET:
 
1013
      case GET_UINT64:
 
1014
        *((uint64_t*) variable)=  (uint64_t) value;
 
1015
        break;
 
1016
      case GET_DOUBLE:
 
1017
        *((double*) variable)=  (double) value;
 
1018
        break;
 
1019
      case GET_STR:
 
1020
        /*
 
1021
           Do not clear variable value if it has no default value.
 
1022
           The default value may already be set.
 
1023
NOTE: To avoid compiler warnings, we first cast int64_t to intptr_t,
 
1024
so that the value has the same size as a pointer.
 
1025
         */
 
1026
        if ((char*) (intptr_t) value)
 
1027
          *((char**) variable)= (char*) (intptr_t) value;
 
1028
        break;
 
1029
      case GET_STR_ALLOC:
 
1030
        /*
 
1031
           Do not clear variable value if it has no default value.
 
1032
           The default value may already be set.
 
1033
NOTE: To avoid compiler warnings, we first cast int64_t to intptr_t,
 
1034
so that the value has the same size as a pointer.
 
1035
         */
 
1036
        if ((char*) (intptr_t) value)
 
1037
        {
 
1038
          free((*(char**) variable));
 
1039
          char *tmpptr= strdup((char *) (intptr_t) value);
 
1040
          if (tmpptr != NULL)
 
1041
            *((char**) variable)= tmpptr;
 
1042
        }
 
1043
        break;
 
1044
      default: /* dummy default to avoid compiler warnings */
 
1045
        break;
 
1046
    }
 
1047
    return;
 
1048
  }
 
1049
 
 
1050
 
 
1051
  /*
 
1052
     Init one value to it's default values
 
1053
 
 
1054
     SYNOPSIS
 
1055
     init_one_value()
 
1056
     option             Option to initialize
 
1057
     value              Pointer to variable
 
1058
   */
 
1059
 
 
1060
  static void fini_one_value(const struct option *option, char **variable,
 
1061
      int64_t)
 
1062
  {
 
1063
    switch ((option->var_type & GET_TYPE_MASK)) {
 
1064
      case GET_STR_ALLOC:
 
1065
        free((*(char**) variable));
 
1066
        *((char**) variable)= NULL;
 
1067
        break;
 
1068
      default: /* dummy default to avoid compiler warnings */
 
1069
        break;
 
1070
    }
 
1071
    return;
 
1072
  }
 
1073
 
 
1074
 
 
1075
  void my_cleanup_options(const struct option *options)
 
1076
  {
 
1077
    init_variables(options, fini_one_value);
 
1078
  }
 
1079
 
 
1080
 
 
1081
  /*
 
1082
     initialize all variables to their default values
 
1083
 
 
1084
     SYNOPSIS
 
1085
     init_variables()
 
1086
     options            Array of options
 
1087
 
 
1088
     NOTES
 
1089
     We will initialize the value that is pointed to by options->value.
 
1090
     If the value is of type GET_ASK_ADDR, we will also ask for the address
 
1091
     for a value and initialize.
 
1092
   */
 
1093
 
 
1094
  static void init_variables(const struct option *options,
 
1095
      init_func_p init_one_value)
 
1096
  {
 
1097
    for (; options->name; options++)
 
1098
    {
 
1099
      char* *variable;
 
1100
      /*
 
1101
         We must set u_max_value first as for some variables
 
1102
         options->u_max_value == options->value and in this case we want to
 
1103
         set the value to default value.
 
1104
       */
 
1105
      if (options->u_max_value)
 
1106
        init_one_value(options, options->u_max_value, options->max_value);
 
1107
      if (options->value)
 
1108
        init_one_value(options, options->value, options->def_value);
 
1109
      if (options->var_type & GET_ASK_ADDR &&
 
1110
          (variable= (*getopt_get_addr)("", 0, options)))
 
1111
        init_one_value(options, variable, options->def_value);
 
1112
    }
 
1113
    return;
 
1114
  }
 
1115
 
 
1116
 
228
1117
  /*
229
1118
function: my_print_options
230
1119
 
310
1199
  }
311
1200
 
312
1201
 
 
1202
  /*
 
1203
function: my_print_options
 
1204
 
 
1205
Print variables.
 
1206
   */
 
1207
 
 
1208
  void my_print_variables(const struct option *options)
 
1209
  {
 
1210
    uint32_t name_space= 34, length, nr;
 
1211
    uint64_t bit, llvalue;
 
1212
    char buff[255];
 
1213
    const struct option *optp;
 
1214
 
 
1215
    printf(_("\nVariables (--variable-name=value)\n"
 
1216
          "and boolean options {false|true}  Value (after reading options)\n"
 
1217
          "--------------------------------- -----------------------------\n"));
 
1218
    for (optp= options; optp->id; optp++)
 
1219
    {
 
1220
      char* *value= (optp->var_type & GET_ASK_ADDR ?
 
1221
          (*getopt_get_addr)("", 0, optp) : optp->value);
 
1222
      if (value)
 
1223
      {
 
1224
        printf("%s ", optp->name);
 
1225
        length= (uint32_t) strlen(optp->name)+1;
 
1226
        for (; length < name_space; length++)
 
1227
          putchar(' ');
 
1228
        switch ((optp->var_type & GET_TYPE_MASK)) {
 
1229
          case GET_SET:
 
1230
            if (!(llvalue= *(uint64_t*) value))
 
1231
              printf("%s\n", _("(No default value)"));
 
1232
            else
 
1233
              for (nr= 0, bit= 1; llvalue && nr < optp->typelib->count; nr++, bit<<=1)
 
1234
              {
 
1235
                if (!(bit & llvalue))
 
1236
                  continue;
 
1237
                llvalue&= ~bit;
 
1238
                printf( llvalue ? "%s," : "%s\n", optp->typelib->get_type(nr));
 
1239
              }
 
1240
            break;
 
1241
          case GET_ENUM:
 
1242
            printf("%s\n", optp->typelib->get_type(*(uint*) value));
 
1243
            break;
 
1244
          case GET_STR:
 
1245
          case GET_STR_ALLOC:                    /* fall through */
 
1246
            printf("%s\n", *((char**) value) ? *((char**) value) :
 
1247
                _("(No default value)"));
 
1248
            break;
 
1249
          case GET_BOOL:
 
1250
            printf("%s\n", *((bool*) value) ? _("true") : _("false"));
 
1251
            break;
 
1252
          case GET_INT:
 
1253
            printf("%d\n", *((int*) value));
 
1254
            break;
 
1255
          case GET_UINT:
 
1256
            printf("%d\n", *((uint*) value));
 
1257
            break;
 
1258
          case GET_LONG:
 
1259
            printf("%ld\n", *((long*) value));
 
1260
            break;
 
1261
          case GET_UINT32:
 
1262
            printf("%u\n", *((uint32_t*) value));
 
1263
            break;
 
1264
          case GET_ULONG_IS_FAIL:
 
1265
            printf("%lu\n", *((ulong*) value));
 
1266
            break;
 
1267
          case GET_SIZE:
 
1268
            internal::int64_t2str((uint64_t)(*(size_t*)value), buff, 10);
 
1269
            printf("%s\n", buff);
 
1270
            break;
 
1271
          case GET_LL:
 
1272
            printf("%s\n", internal::llstr(*((int64_t*) value), buff));
 
1273
            break;
 
1274
          case GET_ULL:
 
1275
          case GET_UINT64:
 
1276
            internal::int64_t2str(*((uint64_t*) value), buff, 10);
 
1277
            printf("%s\n", buff);
 
1278
            break;
 
1279
          case GET_DOUBLE:
 
1280
            printf("%g\n", *(double*) value);
 
1281
            break;
 
1282
          default:
 
1283
            printf(_("(Disabled)\n"));
 
1284
            break;
 
1285
        }
 
1286
      }
 
1287
    }
 
1288
  }
 
1289
 
313
1290
} /* namespace drizzled */