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