~drizzle-trunk/drizzle/development

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