~drizzle-trunk/drizzle/development

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