~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
16
#include "config.h"
17
#include "drizzled/internal/my_sys.h"
18
#include <drizzled/gettext.h>
19
20
#include "drizzled/internal/m_string.h"
21
#include "drizzled/internal/my_sys.h"
22
#include "drizzled/error.h"
23
#include "drizzled/option.h"
2151.5.3 by Olaf van der Spek
Make class of TYPELIB
24
#include "drizzled/typelib.h"
1410.4.2 by Djellel E. Difallah
removing my
25
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <errno.h>
29
#include <iostream>
30
#include <algorithm>
31
32
using namespace std;
33
namespace drizzled
34
{
35
1410.3.4 by Djellel E. Difallah
update references to old my_'s
36
  typedef void (*init_func_p)(const struct option *option, char **variable,
1410.4.2 by Djellel E. Difallah
removing my
37
      int64_t value);
38
39
  void default_reporter(enum loglevel level, const char *format, ...);
40
  my_error_reporter my_getopt_error_reporter= &default_reporter;
41
42
  static int findopt(char *optpat, uint32_t length,
1410.3.4 by Djellel E. Difallah
update references to old my_'s
43
      const struct option **opt_res,
1410.4.2 by Djellel E. Difallah
removing my
44
      char **ffname);
1410.3.4 by Djellel E. Difallah
update references to old my_'s
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,
1410.4.2 by Djellel E. Difallah
removing my
47
      int *err);
1410.3.4 by Djellel E. Difallah
update references to old my_'s
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,
1410.4.2 by Djellel E. Difallah
removing my
51
      init_func_p init_one_value);
1410.3.4 by Djellel E. Difallah
update references to old my_'s
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,
1410.4.2 by Djellel E. Difallah
removing my
57
      bool set_maximum_value);
58
  static char *check_struct_option(char *cur_arg, char *key_name);
59
60
  /*
61
     The following three variables belong to same group and the number and
62
     order of their arguments must correspond to each other.
63
   */
64
  static const char *special_opt_prefix[]=
65
  {"skip", "disable", "enable", "maximum", "loose", 0};
66
  static const uint32_t special_opt_prefix_lengths[]=
67
  { 4,      7,         6,        7,         5,      0};
68
  enum enum_special_opt
69
  { OPT_SKIP, OPT_DISABLE, OPT_ENABLE, OPT_MAXIMUM, OPT_LOOSE};
70
71
  char *disabled_my_option= (char*) "0";
72
73
  /*
74
     This is a flag that can be set in client programs. 1 means that
75
     my_getopt will skip over options it does not know how to handle.
76
   */
77
78
  bool my_getopt_skip_unknown= 0;
79
80
  void default_reporter(enum loglevel level, const char *format, ...)
81
  {
82
    va_list args;
83
    va_start(args, format);
84
    if (level == WARNING_LEVEL)
85
      fprintf(stderr, "%s", _("Warning: "));
86
    else if (level == INFORMATION_LEVEL)
87
      fprintf(stderr, "%s", _("Info: "));
88
    vfprintf(stderr, format, args);
89
    va_end(args);
90
    fputc('\n', stderr);
91
    fflush(stderr);
92
  }
93
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
1410.3.4 by Djellel E. Difallah
update references to old my_'s
99
one of the options in struct 'option', return error in case of ambiguous
1410.4.2 by Djellel E. Difallah
removing my
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,
1410.3.4 by Djellel E. Difallah
update references to old my_'s
107
      const struct option *longopts,
1410.4.2 by Djellel E. Difallah
removing my
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];
1410.3.4 by Djellel E. Difallah
update references to old my_'s
115
    const struct option *optp;
1410.4.2 by Djellel E. Difallah
removing my
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);
1497.2.1 by Eric Day
Changed option parsing to search for first '=', not last, since some option values can contain '='.
199
          optend= strchr(opt_str, '=');
1410.4.2 by Djellel E. Difallah
removing my
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
1633.6.2 by Vijay Samuel
Reverted changes.
566
    ptr= NULL; //Options with '.' are now supported.
1410.4.2 by Djellel E. Difallah
removing my
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
1410.3.4 by Djellel E. Difallah
update references to old my_'s
594
  static int setval(const struct option *opts, char **value, char *argument,
1410.4.2 by Djellel E. Difallah
removing my
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:
2151.5.2 by Olaf van der Spek
Make class of TYPELIB
647
          if (((*(int*)result_pos)= opts->typelib->find_type(argument, 2) - 1) < 0)
1410.4.2 by Djellel E. Difallah
removing my
648
            return EXIT_ARGUMENT_INVALID;
649
          break;
650
        case GET_SET:
2151.5.3 by Olaf van der Spek
Make class of TYPELIB
651
          *((uint64_t*)result_pos)= opts->typelib->find_typeset(argument, &err);
1410.4.2 by Djellel E. Difallah
removing my
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
1410.3.4 by Djellel E. Difallah
update references to old my_'s
676
     Go through all options in the option struct. Return number
1410.4.2 by Djellel E. Difallah
removing my
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,
1410.3.4 by Djellel E. Difallah
update references to old my_'s
688
      const struct option **opt_res,
1410.4.2 by Djellel E. Difallah
removing my
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
  /*
721
function: compare_strings
722
723
Works like strncmp, other than 1.) considers '-' and '_' the same.
724
2.) Returns -1 if strings differ, 0 if they are equal
725
   */
726
727
  bool getopt_compare_strings(register const char *s, register const char *t,
728
      uint32_t length)
729
  {
730
    char const *end= s + length;
731
    for (;s != end ; s++, t++)
732
    {
733
      if ((*s != '-' ? *s : '_') != (*t != '-' ? *t : '_'))
734
        return 1;
735
    }
736
    return 0;
737
  }
738
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
  /*
796
function: getopt_ll_limit_value
797
798
Applies min/max/block_size to a numeric value of an option.
799
Returns "fixed" value.
800
   */
801
802
  int64_t getopt_ll_limit_value(int64_t num, const struct option *optp,
803
      bool *fix)
804
  {
805
    int64_t old= num;
806
    bool adjusted= false;
807
    char buf1[255], buf2[255];
808
    uint64_t block_size= (optp->block_size ? (uint64_t) optp->block_size : 1L);
809
810
    if (num > 0 && ((uint64_t) num > (uint64_t) optp->max_value) &&
811
        optp->max_value) /* if max value is not set -> no upper limit */
812
    {
813
      num= (uint64_t) optp->max_value;
814
      adjusted= true;
815
    }
816
817
    switch ((optp->var_type & GET_TYPE_MASK)) {
818
      case GET_INT:
819
        if (num > (int64_t) INT_MAX)
820
        {
821
          num= ((int64_t) INT_MAX);
822
          adjusted= true;
823
        }
824
        break;
825
      case GET_LONG:
826
        if (num > (int64_t) INT32_MAX)
827
        {
828
          num= ((int64_t) INT32_MAX);
829
          adjusted= true;
830
        }
831
        break;
832
      default:
833
        assert((optp->var_type & GET_TYPE_MASK) == GET_LL);
834
        break;
835
    }
836
837
    num= ((num - optp->sub_size) / block_size);
838
    num= (int64_t) (num * block_size);
839
840
    if (num < optp->min_value)
841
    {
842
      num= optp->min_value;
843
      adjusted= true;
844
    }
845
846
    if (fix)
847
      *fix= adjusted;
848
    else if (adjusted)
849
      my_getopt_error_reporter(WARNING_LEVEL,
850
          "option '%s': signed value %s adjusted to %s",
851
          optp->name, internal::llstr(old, buf1), internal::llstr(num, buf2));
852
    return num;
853
  }
854
855
  /*
856
function: getopt_ull
857
858
This is the same as getopt_ll, but is meant for uint64_t
859
values.
860
   */
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
876
  uint64_t getopt_ull_limit_value(uint64_t num, const struct option *optp,
877
      bool *fix)
878
  {
879
    bool adjusted= false;
880
    uint64_t old= num;
881
    char buf1[255], buf2[255];
882
883
    if ((uint64_t) num > (uint64_t) optp->max_value &&
884
        optp->max_value) /* if max value is not set -> no upper limit */
885
    {
886
      num= (uint64_t) optp->max_value;
887
      adjusted= true;
888
    }
889
890
    switch ((optp->var_type & GET_TYPE_MASK)) {
891
      case GET_UINT:
892
        if (num > (uint64_t) UINT_MAX)
893
        {
894
          num= ((uint64_t) UINT_MAX);
895
          adjusted= true;
896
        }
897
        break;
898
      case GET_UINT32:
899
      case GET_ULONG_IS_FAIL:
900
        if (num > (uint64_t) UINT32_MAX)
901
        {
902
          num= ((uint64_t) UINT32_MAX);
903
          adjusted= true;
904
        }
905
        break;
906
      case GET_SIZE:
907
        if (num > (uint64_t) SIZE_MAX)
908
        {
909
          num= ((uint64_t) SIZE_MAX);
910
          adjusted= true;
911
        }
912
        break;
913
      default:
914
        assert(((optp->var_type & GET_TYPE_MASK) == GET_ULL)
915
            || ((optp->var_type & GET_TYPE_MASK) == GET_UINT64));
916
        break;
917
    }
918
919
    if (optp->block_size > 1)
920
    {
921
      num/= (uint64_t) optp->block_size;
922
      num*= (uint64_t) optp->block_size;
923
    }
924
925
    if (num < (uint64_t) optp->min_value)
926
    {
927
      num= (uint64_t) optp->min_value;
928
      adjusted= true;
929
    }
930
931
    if (fix)
932
      *fix= adjusted;
933
    else if (adjusted)
934
      my_getopt_error_reporter(WARNING_LEVEL,
935
          "option '%s': unsigned value %s adjusted to %s",
936
          optp->name, internal::ullstr(old, buf1), internal::ullstr(num, buf2));
937
938
    return num;
939
  }
940
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
1117
  /*
1118
function: my_print_options
1119
1120
Print help for all options and variables.
1121
   */
1122
1123
  void my_print_help(const struct option *options)
1124
  {
1125
    uint32_t col, name_space= 22, comment_space= 57;
1126
    const char *line_end;
1127
    const struct option *optp;
1128
1129
    for (optp= options; optp->id; optp++)
1130
    {
1131
      if (optp->id < 256)
1132
      {
1133
        printf("  -%c%s", optp->id, strlen(optp->name) ? ", " : "  ");
1134
        col= 6;
1135
      }
1136
      else
1137
      {
1138
        printf("  ");
1139
        col= 2;
1140
      }
1141
      if (strlen(optp->name))
1142
      {
1143
        printf("--%s", optp->name);
1144
        col+= 2 + (uint32_t) strlen(optp->name);
1145
        if ((optp->var_type & GET_TYPE_MASK) == GET_STR ||
1146
            (optp->var_type & GET_TYPE_MASK) == GET_STR_ALLOC)
1147
        {
1148
          printf("%s=name%s ", optp->arg_type == OPT_ARG ? "[" : "",
1149
              optp->arg_type == OPT_ARG ? "]" : "");
1150
          col+= (optp->arg_type == OPT_ARG) ? 8 : 6;
1151
        }
1152
        else if ((optp->var_type & GET_TYPE_MASK) == GET_NO_ARG ||
1153
            (optp->var_type & GET_TYPE_MASK) == GET_BOOL)
1154
        {
1155
          putchar(' ');
1156
          col++;
1157
        }
1158
        else
1159
        {
1160
          printf("%s=#%s ", optp->arg_type == OPT_ARG ? "[" : "",
1161
              optp->arg_type == OPT_ARG ? "]" : "");
1162
          col+= (optp->arg_type == OPT_ARG) ? 5 : 3;
1163
        }
1164
        if (col > name_space && optp->comment && *optp->comment)
1165
        {
1166
          putchar('\n');
1167
          col= 0;
1168
        }
1169
      }
1170
      for (; col < name_space; col++)
1171
        putchar(' ');
1172
      if (optp->comment && *optp->comment)
1173
      {
1174
        const char *comment= _(optp->comment), *end= strchr(comment, '\0');
1175
1176
        while ((uint32_t) (end - comment) > comment_space)
1177
        {
1178
          for (line_end= comment + comment_space; *line_end != ' '; line_end--)
1179
          {}
1180
          for (; comment != line_end; comment++)
1181
            putchar(*comment);
1182
          comment++; /* skip the space, as a newline will take it's place now */
1183
          putchar('\n');
1184
          for (col= 0; col < name_space; col++)
1185
            putchar(' ');
1186
        }
1187
        printf("%s", comment);
1188
      }
1189
      putchar('\n');
1190
      if ((optp->var_type & GET_TYPE_MASK) == GET_NO_ARG ||
1191
          (optp->var_type & GET_TYPE_MASK) == GET_BOOL)
1192
      {
1193
        if (optp->def_value != 0)
1194
        {
1195
          printf(_("%*s(Defaults to on; use --skip-%s to disable.)\n"), name_space, "", optp->name);
1196
        }
1197
      }
1198
    }
1199
  }
1200
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;
2151.5.3 by Olaf van der Spek
Make class of TYPELIB
1238
                printf( llvalue ? "%s," : "%s\n", optp->typelib->get_type(nr));
1410.4.2 by Djellel E. Difallah
removing my
1239
              }
1240
            break;
1241
          case GET_ENUM:
2151.5.3 by Olaf van der Spek
Make class of TYPELIB
1242
            printf("%s\n", optp->typelib->get_type(*(uint*) value));
1410.4.2 by Djellel E. Difallah
removing my
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
1290
} /* namespace drizzled */