From 845db7c20ba28e014c5a36a6c95afd8ed111f316 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 25 Jan 2002 23:34:37 +0200 Subject: Added my_getopt struct and modified myisamchk to the bk tree. include/Makefile.am: Added my_getopt.h myisam/myisamchk.c: myisamcheck is using my_getopt struct now. Old code left: changeable_var[], will be changed later. mysys/Makefile.am: added my_getopt.c mysys/getvar.c: Added my_set_changeable_var. This is not being used yet, and is mostly a copy of set_changeable_var still. BitKeeper/etc/logging_ok: Logging to logging@openlogging.org accepted --- mysys/Makefile.am | 2 +- mysys/getvar.c | 77 +++++++++++++- mysys/my_getopt.c | 313 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 390 insertions(+), 2 deletions(-) create mode 100644 mysys/my_getopt.c (limited to 'mysys') diff --git a/mysys/Makefile.am b/mysys/Makefile.am index 97f065bc7e2..287dc357b3d 100644 --- a/mysys/Makefile.am +++ b/mysys/Makefile.am @@ -44,7 +44,7 @@ libmysys_a_SOURCES = my_init.c my_getwd.c mf_getdate.c\ my_delete.c my_rename.c my_redel.c my_tempnam.c \ my_chsize.c my_lread.c my_lwrite.c my_clock.c \ my_quick.c my_lockmem.c my_static.c \ - getopt.c getopt1.c getvar.c my_mkdir.c \ + getopt.c getopt1.c my_getopt.c getvar.c my_mkdir.c \ default.c my_compress.c checksum.c raid.cc my_net.c \ my_vsnprintf.c charset.c my_bitmap.c my_bit.c md5.c EXTRA_DIST = thr_alarm.c thr_lock.c my_pthread.c my_thr_init.c \ diff --git a/mysys/getvar.c b/mysys/getvar.c index 49b321f592e..1a2adc10e62 100644 --- a/mysys/getvar.c +++ b/mysys/getvar.c @@ -19,7 +19,7 @@ #include "mysys_priv.h" #include #include - +#include /* set all changeable variables */ void set_all_changeable_vars(CHANGEABLE_VAR *vars) @@ -109,3 +109,78 @@ my_bool set_changeable_var(my_string str,CHANGEABLE_VAR *vars) } DBUG_RETURN(1); } + +my_bool my_set_changeable_var(my_string str, const struct my_option *vars) +{ + char endchar; + my_string end; + DBUG_ENTER("my_set_changeable_var"); + DBUG_PRINT("enter",("%s",str)); + + if (str) + { + if (!(end=strchr(str,'='))) + fprintf(stderr,"Can't find '=' in expression '%s' to option -O\n",str); + else + { + uint length,found_count=0; + const struct my_option *var, *found; + my_string var_end; + const char *name; + longlong num; + + /* Skip end space from variable */ + for (var_end=end ; end > str && isspace(var_end[-1]) ; var_end--) ; + length=(uint) (var_end-str); + /* Skip start space from argument */ + for (end++ ; isspace(*end) ; end++) ; + + for (var= vars, found= 0; (name= var->name); var++) + { + if (var->changeable_var) + { + if (!my_casecmp(name, str, length)) + { + found= var; found_count++; + if (!name[length]) + { + found_count=1; + break; + } + } + } + } + if (found_count == 0) + { + fprintf(stderr,"No variable match for: -O '%s'\n",str); + DBUG_RETURN(1); + } + if (found_count > 1) + { + fprintf(stderr,"Variable prefix '%*s' is not unique\n",length,str); + DBUG_RETURN(1); + } + + num=strtoll(end, (char **)NULL, 10); endchar=strend(end)[-1]; + if (endchar == 'k' || endchar == 'K') + num*=1024; + else if (endchar == 'm' || endchar == 'M') + num*=1024L*1024L; + else if (endchar == 'g' || endchar == 'G') + num*=1024L*1024L*1024L; + else if (!isdigit(endchar)) + { + fprintf(stderr,"Unknown prefix used for variable value '%s'\n",str); + DBUG_RETURN(1); + } + if (num < (longlong) found->min_value) + num=(longlong) found->min_value; + else if (num > 0 && (ulonglong) num > (ulonglong) (ulong) found->max_value) + num=(longlong) (ulong) found->max_value; + num=((num- (longlong) found->sub_size) / (ulonglong) found->block_size); + /* (*found->varptr)= (long) (num*(ulonglong) found->block_size);*/ + DBUG_RETURN(0); + } + } + DBUG_RETURN(1); +} diff --git a/mysys/my_getopt.c b/mysys/my_getopt.c new file mode 100644 index 00000000000..afe3da214bf --- /dev/null +++ b/mysys/my_getopt.c @@ -0,0 +1,313 @@ +/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ + +#include +#include +#include +#include +#include +#include + +static int sortopt (int *argc, char ***argv); +static int findopt (char *optpat, uint length, + const struct my_option **opt_res, + char **ffname); + +#define DISABLE_OPTION_COUNT 2 + +static char *special_opt_prefix[] = {"skip", "disable", "enable", 0}; + + +/* function: handle_options + Sort options; put options first, until special end of options (--), or + until end of argv. Parse options; check that the given option matches with + one of the options in struct 'my_option', return error in case of ambiguous + or unknown option. Check that option was given an argument if it requires + one. Call function 'get_one_option()' once for each option. +*/ +extern int handle_options (int *argc, char ***argv, + const struct my_option *longopts, + my_bool (*get_one_option)(int, + const struct my_option *, + char *)) +{ + uint opt_found, argvpos = 0, length, spec_len, i; + my_bool end_of_options = 0, must_be_var = 0; + char *progname = *(*argv), **pos, *optend, *prev_found; + const struct my_option *optp; + + (*argc)--; + (*argv)++; + for (pos = *argv; *pos; pos++) + { + char *cur_arg= *pos; + if (*cur_arg == '-' && *(cur_arg + 1) && !end_of_options) // must be opt. + { + char *argument = 0; + must_be_var= 0; + + // check for long option, or --set-variable (-O) + if (*(cur_arg + 1) == '-' || *(cur_arg + 1) == 'O') + { + if (*(cur_arg + 1) == 'O' || !strncmp(cur_arg, "--set-variable", 14)) + { + must_be_var= 1; + + if (*(cur_arg + 1) == 'O') + { + cur_arg+= 2; + if (!(*cur_arg)) + { + // the argument must be in next argv + if (!(*(pos + 1))) + { + fprintf(stderr, "%s: Option '-O' requires an argument\n", + progname); + return 4; + } + pos++; + cur_arg= *pos; + (*argc)--; + } + } + else // Option argument begins with string '--set-variable' + { + cur_arg+= 14; + if (*cur_arg == '=') + { + cur_arg++; + if (!(*cur_arg)) + { + fprintf(stderr, + "%s: Option '--set-variable' requires an argument\n", + progname); + return 4; + } + } + else if (*cur_arg) // garbage, or another option. break out + { + cur_arg-= 14; + must_be_var= 0; + } + else + { + // the argument must be in next argv + if (!(*(pos + 1))) + { + fprintf(stderr, + "%s: Option '--set-variable' requires an argument\n", + progname); + return 4; + } + pos++; + cur_arg= *pos; + (*argc)--; + } + } + } + else if (!must_be_var) + { + if (!*(cur_arg + 2)) // '--' means end of options, look no further + { + end_of_options = 1; + (*argc)--; + continue; + } + cur_arg+= 2; // skip the double dash + } + for (optend = cur_arg; *optend && *optend != '='; optend++) ; + length = optend - cur_arg; + /* + Find first the right option. Return error in case of an ambiguous, + or unknown option + */ + optp = longopts; + if (!(opt_found = findopt(cur_arg, length, &optp, &prev_found))) + { + /* + Didn't find any matching option. Let's see if someone called + option with a special option prefix + */ + if (*optend != '=' && !must_be_var) + { + for (i = 0; special_opt_prefix[i]; i++) + { + spec_len = strlen(special_opt_prefix[i]); + if (!strncmp(special_opt_prefix[i], cur_arg, spec_len) && + cur_arg[spec_len] == '-') + { + // We were called with a special prefix, we can reuse opt_found + cur_arg += (spec_len + 1); + if ((opt_found = findopt(cur_arg, length - (spec_len + 1), + &optp, &prev_found))) + { + if (opt_found > 1) + { + fprintf(stderr, + "%s: ambiguous option '--%s-%s' (--%s-%s)\n", + progname, special_opt_prefix[i], cur_arg, + special_opt_prefix[i], prev_found); + return 2; + } + if (i < DISABLE_OPTION_COUNT) + optend= "=0"; + else // enable + optend= "=1"; + break; // note break from the inner loop, main loop continues + } + } + } + } + if (!opt_found) + { + if (must_be_var) + { + fprintf(stderr, + "%s: unknown variable '%s'\n", progname, cur_arg); + return 7; + } + else + { + fprintf(stderr, + "%s: unknown option '--%s'\n", progname, cur_arg); + return 1; + } + } + } + if (opt_found > 1) + { + if (must_be_var) + { + fprintf(stderr, "%s: variable prefix '%s' is not unique\n", + progname, cur_arg); + return 6; + } + else + { + fprintf(stderr, "%s: ambiguous option '--%s' (%s, %s)\n", + progname, cur_arg, prev_found, optp->name); + return 2; + } + } + if (must_be_var && !optp->changeable_var) + { + fprintf(stderr, "%s: the argument to -O must be a variable\n", + progname); + return 8; + } + if (optp->arg_type == NO_ARG && *optend == '=') + { + fprintf(stderr, "%s: option '--%s' cannot take an argument\n", + progname, optp->name); + return 3; + } + else if (optp->arg_type == REQUIRED_ARG && !*optend) + { + /* Check if there are more arguments after this one */ + if (!(*(pos + 1))) + { + fprintf(stderr, "%s: option '--%s' requires an argument\n", + progname, optp->name); + return 4; + } + pos++; + argument = *pos; + (*argc)--; + } + else if (*optend == '=') + argument = *(optend + 1) ? optend + 1 : ""; + } + else // must be short option + { + my_bool skip; + for (skip = 0, optend = (cur_arg + 1); *optend && !skip; optend++) + { + for (optp = longopts; optp->id ; optp++) + { + if (optp->id == (int) (uchar) *optend) + { + /* Option recognized. Find next what to do with it */ + if (optp->arg_type == REQUIRED_ARG || optp->arg_type == OPT_ARG) + { + if (*(optend + 1)) + { + argument = (optend + 1); + /* + The rest of the option is option argument + This is in effect a jump out of this loop + */ + skip = 1; + } + else if (optp->arg_type == REQUIRED_ARG) + { + /* Check if there are more arguments after this one */ + if (!(*(pos + 1))) + { + fprintf(stderr, "%s: option '-%c' requires an argument\n", + progname, optp->id); + return 4; + } + pos++; + argument = *pos; + (*argc)--; + } + } + else if (*(optend + 1)) // we are hitting many options in 1 argv + get_one_option(optp->id, optp, 0); + break; + } + } + } + } + get_one_option(optp->id, optp, argument); + (*argc)--; // option handled (short or long), decrease argument count + } + else // non-option found + (*argv)[argvpos++] = cur_arg; + } + return 0; +} + +/* function: findopt + Arguments: opt_pattern, length of opt_pattern, opt_struct, first found + name (ffname) + + Go through all options in the my_option struct. Return number + of options found that match the pattern and in the argument + list the option found, if any. In case of ambiguous option, store + the name in ffname argument +*/ +static int findopt (char *optpat, uint length, + const struct my_option **opt_res, + char **ffname) +{ + int count; + struct my_option *opt= (struct my_option *) *opt_res; + + for (count = 0; opt->id; opt++) + { + if (!strncmp(opt->name, optpat, length)) // match found + { + (*opt_res) = opt; + if (!count) + *ffname = (char *) opt->name; // we only need to know one prev + if (length == strlen(opt->name)) // exact match + return 1; + count++; + } + } + return count; +} -- cgit v1.2.1