Commit 673e1557 authored by unknown's avatar unknown

Merge paul@bk-internal.mysql.com:/home/bk/mysql-4.1

into teton.kitebird.com:/home/paul/mysql-4.1

parents 608bda36 15fcc884
...@@ -1113,7 +1113,7 @@ AC_DEFUN([MYSQL_CHECK_BDB_VERSION], [ ...@@ -1113,7 +1113,7 @@ AC_DEFUN([MYSQL_CHECK_BDB_VERSION], [
# mysql_bdb=a # mysql_bdb=a
# fi # fi
dbl RAM: dnl RAM:
want_bdb_version="4.1.24" want_bdb_version="4.1.24"
bdb_version_ok=yes bdb_version_ok=yes
......
...@@ -17,7 +17,12 @@ ...@@ -17,7 +17,12 @@
C_MODE_START C_MODE_START
enum get_opt_var_type { GET_NO_ARG, GET_BOOL, GET_INT, GET_UINT, GET_LONG, enum get_opt_var_type { GET_NO_ARG, GET_BOOL, GET_INT, GET_UINT, GET_LONG,
GET_ULONG, GET_LL, GET_ULL, GET_STR, GET_STR_ALLOC }; GET_ULONG, GET_LL, GET_ULL, GET_STR, GET_STR_ALLOC
};
#define GET_ASK_ADDR 128
#define GET_TYPE_MASK 127
enum get_opt_arg_type { NO_ARG, OPT_ARG, REQUIRED_ARG }; enum get_opt_arg_type { NO_ARG, OPT_ARG, REQUIRED_ARG };
struct my_option struct my_option
...@@ -48,6 +53,8 @@ extern int handle_options (int *argc, char ***argv, ...@@ -48,6 +53,8 @@ extern int handle_options (int *argc, char ***argv,
char *)); char *));
extern void my_print_help(const struct my_option *options); extern void my_print_help(const struct my_option *options);
extern void my_print_variables(const struct my_option *options); extern void my_print_variables(const struct my_option *options);
extern void my_getopt_register_get_addr(gptr* (*func_addr)(char *, uint,
const struct my_option *));
ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp); ulonglong getopt_ull_limit_value(ulonglong num, const struct my_option *optp);
my_bool getopt_compare_strings(const char *s, const char *t, uint length); my_bool getopt_compare_strings(const char *s, const char *t, uint length);
......
...@@ -215,21 +215,21 @@ drop table t1; ...@@ -215,21 +215,21 @@ drop table t1;
create table t1 (word varchar(255) not null, word2 varchar(255) not null, index(word)); create table t1 (word varchar(255) not null, word2 varchar(255) not null, index(word));
insert into t1 (word) values ('ss'),(0xDF),(0xE4),('ae'); insert into t1 (word) values ('ss'),(0xDF),(0xE4),('ae');
update t1 set word2=word; update t1 set word2=word;
select word, word=0xdf as t from t1 having t > 0; select word, word=binary 0xdf as t from t1 having t > 0;
word t word t
1 1
select word, word=cast(0xdf AS CHAR) as t from t1 having t > 0; select word, word=cast(0xdf AS CHAR) as t from t1 having t > 0;
word t word t
ss 1 ss 1
1 1
select * from t1 where word=0xDF; select * from t1 where word=binary 0xDF;
word word2 word word2
select * from t1 where word=CAST(0xDF as CHAR); select * from t1 where word=CAST(0xDF as CHAR);
word word2 word word2
ss ss ss ss
select * from t1 where word2=0xDF; select * from t1 where word2=binary 0xDF;
word word2 word word2
select * from t1 where word2=CAST(0xDF as CHAR); select * from t1 where word2=CAST(0xDF as CHAR);
...@@ -244,7 +244,7 @@ select * from t1 where word= 0xe4 or word=CAST(0xe4 as CHAR); ...@@ -244,7 +244,7 @@ select * from t1 where word= 0xe4 or word=CAST(0xe4 as CHAR);
word word2 word word2
ae ae ae ae
select * from t1 where word between 0xDF and 0xDF; select * from t1 where word between binary 0xDF and binary 0xDF;
word word2 word word2
select * from t1 where word between CAST(0xDF AS CHAR) and CAST(0xDF AS CHAR); select * from t1 where word between CAST(0xDF AS CHAR) and CAST(0xDF AS CHAR);
...@@ -257,7 +257,7 @@ ae ae ...@@ -257,7 +257,7 @@ ae ae
select * from t1 where word like 'AE'; select * from t1 where word like 'AE';
word word2 word word2
ae ae ae ae
select * from t1 where word like 0xDF; select * from t1 where word like binary 0xDF;
word word2 word word2
select * from t1 where word like CAST(0xDF as CHAR); select * from t1 where word like CAST(0xDF as CHAR);
......
...@@ -276,6 +276,48 @@ select SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin2'd',2); ...@@ -276,6 +276,48 @@ select SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin2'd',2);
ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'substr_index' ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE) and (latin2_general_ci,COERCIBLE) for operation 'substr_index'
select SUBSTRING_INDEX(_latin1'abcdabcdabcd' COLLATE latin1_general_ci,_latin1'd' COLLATE latin1_bin,2); select SUBSTRING_INDEX(_latin1'abcdabcdabcd' COLLATE latin1_general_ci,_latin1'd' COLLATE latin1_bin,2);
ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation 'substr_index' ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT) and (latin1_bin,EXPLICIT) for operation 'substr_index'
select _latin1'B' between _latin1'a' and _latin1'c';
_latin1'B' between _latin1'a' and _latin1'c'
1
select _latin1'B' collate latin1_bin between _latin1'a' and _latin1'c';
_latin1'B' collate latin1_bin between _latin1'a' and _latin1'c'
0
select _latin1'B' between _latin1'a' collate latin1_bin and _latin1'c';
_latin1'B' between _latin1'a' collate latin1_bin and _latin1'c'
0
select _latin1'B' between _latin1'a' and _latin1'c' collate latin1_bin;
_latin1'B' between _latin1'a' and _latin1'c' collate latin1_bin
0
select _latin2'B' between _latin1'a' and _latin1'b';
ERROR HY000: Illegal mix of collations (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'between'
select _latin1'B' between _latin2'a' and _latin1'b';
ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE) for operation 'between'
select _latin1'B' between _latin1'a' and _latin2'b';
ERROR HY000: Illegal mix of collations (latin1_swedish_ci,COERCIBLE), (latin1_swedish_ci,COERCIBLE), (latin2_general_ci,COERCIBLE) for operation 'between'
select _latin1'B' collate latin1_general_ci between _latin1'a' collate latin1_bin and _latin1'b';
ERROR HY000: Illegal mix of collations (latin1_general_ci,EXPLICIT), (latin1_bin,EXPLICIT), (latin1_swedish_ci,COERCIBLE) for operation 'between'
select _latin1'B' in (_latin1'a',_latin1'b');
_latin1'B' in (_latin1'a',_latin1'b')
1
select _latin1'B' collate latin1_bin in (_latin1'a',_latin1'b');
_latin1'B' collate latin1_bin in (_latin1'a',_latin1'b')
0
select _latin1'B' in (_latin1'a' collate latin1_bin,_latin1'b');
_latin1'B' in (_latin1'a' collate latin1_bin,_latin1'b')
0
select _latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin);
_latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin)
0
select _latin2'B' in (_latin1'a',_latin1'b');
ERROR HY000: Illegal mix of collations for operation ' IN '
select _latin1'B' in (_latin2'a',_latin1'b');
ERROR HY000: Illegal mix of collations for operation ' IN '
select _latin1'B' in (_latin1'a',_latin2'b');
ERROR HY000: Illegal mix of collations for operation ' IN '
select _latin1'B' COLLATE latin1_general_ci in (_latin1'a' COLLATE latin1_bin,_latin1'b');
ERROR HY000: Illegal mix of collations for operation ' IN '
select _latin1'B' COLLATE latin1_general_ci in (_latin1'a',_latin1'b' COLLATE latin1_bin);
ERROR HY000: Illegal mix of collations for operation ' IN '
select collation(bin(130)), coercibility(bin(130)); select collation(bin(130)), coercibility(bin(130));
collation(bin(130)) coercibility(bin(130)) collation(bin(130)) coercibility(bin(130))
latin1_swedish_ci 3 latin1_swedish_ci 3
......
...@@ -52,21 +52,24 @@ drop table t1; ...@@ -52,21 +52,24 @@ drop table t1;
# Test bug report #152 (problem with index on latin1_de) # Test bug report #152 (problem with index on latin1_de)
# #
#
# The below checks both binary and character comparisons.
#
create table t1 (word varchar(255) not null, word2 varchar(255) not null, index(word)); create table t1 (word varchar(255) not null, word2 varchar(255) not null, index(word));
insert into t1 (word) values ('ss'),(0xDF),(0xE4),('ae'); insert into t1 (word) values ('ss'),(0xDF),(0xE4),('ae');
update t1 set word2=word; update t1 set word2=word;
select word, word=0xdf as t from t1 having t > 0; select word, word=binary 0xdf as t from t1 having t > 0;
select word, word=cast(0xdf AS CHAR) as t from t1 having t > 0; select word, word=cast(0xdf AS CHAR) as t from t1 having t > 0;
select * from t1 where word=0xDF; select * from t1 where word=binary 0xDF;
select * from t1 where word=CAST(0xDF as CHAR); select * from t1 where word=CAST(0xDF as CHAR);
select * from t1 where word2=0xDF; select * from t1 where word2=binary 0xDF;
select * from t1 where word2=CAST(0xDF as CHAR); select * from t1 where word2=CAST(0xDF as CHAR);
select * from t1 where word='ae'; select * from t1 where word='ae';
select * from t1 where word= 0xe4 or word=CAST(0xe4 as CHAR); select * from t1 where word= 0xe4 or word=CAST(0xe4 as CHAR);
select * from t1 where word between 0xDF and 0xDF; select * from t1 where word between binary 0xDF and binary 0xDF;
select * from t1 where word between CAST(0xDF AS CHAR) and CAST(0xDF AS CHAR); select * from t1 where word between CAST(0xDF AS CHAR) and CAST(0xDF AS CHAR);
select * from t1 where word like 'ae'; select * from t1 where word like 'ae';
select * from t1 where word like 'AE'; select * from t1 where word like 'AE';
select * from t1 where word like 0xDF; select * from t1 where word like binary 0xDF;
select * from t1 where word like CAST(0xDF as CHAR); select * from t1 where word like CAST(0xDF as CHAR);
drop table t1; drop table t1;
...@@ -162,6 +162,33 @@ select SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin2'd',2); ...@@ -162,6 +162,33 @@ select SUBSTRING_INDEX(_latin1'abcdabcdabcd',_latin2'd',2);
--error 1265 --error 1265
select SUBSTRING_INDEX(_latin1'abcdabcdabcd' COLLATE latin1_general_ci,_latin1'd' COLLATE latin1_bin,2); select SUBSTRING_INDEX(_latin1'abcdabcdabcd' COLLATE latin1_general_ci,_latin1'd' COLLATE latin1_bin,2);
select _latin1'B' between _latin1'a' and _latin1'c';
select _latin1'B' collate latin1_bin between _latin1'a' and _latin1'c';
select _latin1'B' between _latin1'a' collate latin1_bin and _latin1'c';
select _latin1'B' between _latin1'a' and _latin1'c' collate latin1_bin;
--error 1268
select _latin2'B' between _latin1'a' and _latin1'b';
--error 1268
select _latin1'B' between _latin2'a' and _latin1'b';
--error 1268
select _latin1'B' between _latin1'a' and _latin2'b';
--error 1268
select _latin1'B' collate latin1_general_ci between _latin1'a' collate latin1_bin and _latin1'b';
select _latin1'B' in (_latin1'a',_latin1'b');
select _latin1'B' collate latin1_bin in (_latin1'a',_latin1'b');
select _latin1'B' in (_latin1'a' collate latin1_bin,_latin1'b');
select _latin1'B' in (_latin1'a',_latin1'b' collate latin1_bin);
--error 1269
select _latin2'B' in (_latin1'a',_latin1'b');
--error 1269
select _latin1'B' in (_latin2'a',_latin1'b');
--error 1269
select _latin1'B' in (_latin1'a',_latin2'b');
--error 1269
select _latin1'B' COLLATE latin1_general_ci in (_latin1'a' COLLATE latin1_bin,_latin1'b');
--error 1269
select _latin1'B' COLLATE latin1_general_ci in (_latin1'a',_latin1'b' COLLATE latin1_bin);
select collation(bin(130)), coercibility(bin(130)); select collation(bin(130)), coercibility(bin(130));
select collation(oct(130)), coercibility(oct(130)); select collation(oct(130)), coercibility(oct(130));
......
...@@ -34,6 +34,7 @@ static ulonglong getopt_ull(char *arg, const struct my_option *optp, ...@@ -34,6 +34,7 @@ static ulonglong getopt_ull(char *arg, const struct my_option *optp,
static void init_variables(const struct my_option *options); static void init_variables(const struct my_option *options);
static int setval(const struct my_option *opts, char *argument, static int setval(const struct my_option *opts, char *argument,
my_bool set_maximum_value); my_bool set_maximum_value);
static char *check_struct_option(char *cur_arg, char *key_name);
/* /*
The following three variables belong to same group and the number and The following three variables belong to same group and the number and
...@@ -67,6 +68,14 @@ my_bool my_getopt_print_errors= 1; ...@@ -67,6 +68,14 @@ my_bool my_getopt_print_errors= 1;
one. Call function 'get_one_option()' once for each option. one. Call function 'get_one_option()' once for each option.
*/ */
static gptr* (*getopt_get_addr)(char *, uint, const struct my_option *);
void my_getopt_register_get_addr(gptr* (*func_addr)(char *, uint,
const struct my_option *))
{
getopt_get_addr= func_addr;
}
int handle_options(int *argc, char ***argv, int handle_options(int *argc, char ***argv,
const struct my_option *longopts, const struct my_option *longopts,
my_bool (*get_one_option)(int, my_bool (*get_one_option)(int,
...@@ -76,8 +85,10 @@ int handle_options(int *argc, char ***argv, ...@@ -76,8 +85,10 @@ int handle_options(int *argc, char ***argv,
uint opt_found, argvpos= 0, length, i; uint opt_found, argvpos= 0, length, i;
my_bool end_of_options= 0, must_be_var, set_maximum_value, special_used, my_bool end_of_options= 0, must_be_var, set_maximum_value, special_used,
option_is_loose; option_is_loose;
char *progname= *(*argv), **pos, **pos_end, *optend, *prev_found; char **pos, **pos_end, *optend, *prev_found,
*opt_str, key_name[FN_REFLEN];
const struct my_option *optp; const struct my_option *optp;
gptr *value;
int error; int error;
LINT_INIT(opt_found); LINT_INIT(opt_found);
...@@ -110,7 +121,7 @@ int handle_options(int *argc, char ***argv, ...@@ -110,7 +121,7 @@ int handle_options(int *argc, char ***argv,
{ {
if (my_getopt_print_errors) if (my_getopt_print_errors)
fprintf(stderr, "%s: Option '-O' requires an argument\n", fprintf(stderr, "%s: Option '-O' requires an argument\n",
progname); my_progname);
return EXIT_ARGUMENT_REQUIRED; return EXIT_ARGUMENT_REQUIRED;
} }
cur_arg= *pos; cur_arg= *pos;
...@@ -128,7 +139,7 @@ int handle_options(int *argc, char ***argv, ...@@ -128,7 +139,7 @@ int handle_options(int *argc, char ***argv,
if (my_getopt_print_errors) if (my_getopt_print_errors)
fprintf(stderr, fprintf(stderr,
"%s: Option '--set-variable' requires an argument\n", "%s: Option '--set-variable' requires an argument\n",
progname); my_progname);
return EXIT_ARGUMENT_REQUIRED; return EXIT_ARGUMENT_REQUIRED;
} }
} }
...@@ -142,7 +153,7 @@ int handle_options(int *argc, char ***argv, ...@@ -142,7 +153,7 @@ int handle_options(int *argc, char ***argv,
if (my_getopt_print_errors) if (my_getopt_print_errors)
fprintf(stderr, fprintf(stderr,
"%s: Option '--set-variable' requires an argument\n", "%s: Option '--set-variable' requires an argument\n",
progname); my_progname);
return EXIT_ARGUMENT_REQUIRED; return EXIT_ARGUMENT_REQUIRED;
} }
cur_arg= *pos; cur_arg= *pos;
...@@ -159,19 +170,20 @@ int handle_options(int *argc, char ***argv, ...@@ -159,19 +170,20 @@ int handle_options(int *argc, char ***argv,
continue; continue;
} }
} }
optend= strcend(cur_arg, '='); opt_str= check_struct_option(cur_arg, key_name);
length= optend - cur_arg; optend= strcend(opt_str, '=');
length= optend - opt_str;
if (*optend == '=') if (*optend == '=')
optend++; optend++;
else else
optend=0; optend= 0;
/* /*
Find first the right option. Return error in case of an ambiguous, Find first the right option. Return error in case of an ambiguous,
or unknown option or unknown option
*/ */
optp= longopts; optp= longopts;
if (!(opt_found= findopt(cur_arg, length, &optp, &prev_found))) if (!(opt_found= findopt(opt_str, length, &optp, &prev_found)))
{ {
/* /*
Didn't find any matching option. Let's see if someone called Didn't find any matching option. Let's see if someone called
...@@ -183,18 +195,18 @@ int handle_options(int *argc, char ***argv, ...@@ -183,18 +195,18 @@ int handle_options(int *argc, char ***argv,
must_be_var= 1; /* option is followed by an argument */ must_be_var= 1; /* option is followed by an argument */
for (i= 0; special_opt_prefix[i]; i++) for (i= 0; special_opt_prefix[i]; i++)
{ {
if (!getopt_compare_strings(special_opt_prefix[i], cur_arg, if (!getopt_compare_strings(special_opt_prefix[i], opt_str,
special_opt_prefix_lengths[i]) && special_opt_prefix_lengths[i]) &&
cur_arg[special_opt_prefix_lengths[i]] == '-') opt_str[special_opt_prefix_lengths[i]] == '-')
{ {
/* /*
We were called with a special prefix, we can reuse opt_found We were called with a special prefix, we can reuse opt_found
*/ */
special_used= 1; special_used= 1;
cur_arg+= (special_opt_prefix_lengths[i] + 1); opt_str+= (special_opt_prefix_lengths[i] + 1);
if (i == OPT_LOOSE) if (i == OPT_LOOSE)
option_is_loose= 1; option_is_loose= 1;
if ((opt_found= findopt(cur_arg, length - if ((opt_found= findopt(opt_str, length -
(special_opt_prefix_lengths[i] + 1), (special_opt_prefix_lengths[i] + 1),
&optp, &prev_found))) &optp, &prev_found)))
{ {
...@@ -203,7 +215,7 @@ int handle_options(int *argc, char ***argv, ...@@ -203,7 +215,7 @@ int handle_options(int *argc, char ***argv,
if (my_getopt_print_errors) if (my_getopt_print_errors)
fprintf(stderr, fprintf(stderr,
"%s: ambiguous option '--%s-%s' (--%s-%s)\n", "%s: ambiguous option '--%s-%s' (--%s-%s)\n",
progname, special_opt_prefix[i], cur_arg, my_progname, special_opt_prefix[i], opt_str,
special_opt_prefix[i], prev_found); special_opt_prefix[i], prev_found);
return EXIT_AMBIGUOUS_OPTION; return EXIT_AMBIGUOUS_OPTION;
} }
...@@ -237,8 +249,8 @@ int handle_options(int *argc, char ***argv, ...@@ -237,8 +249,8 @@ int handle_options(int *argc, char ***argv,
{ {
if (my_getopt_print_errors) if (my_getopt_print_errors)
fprintf(stderr, fprintf(stderr,
"%s: %s: unknown variable '%s'\n", progname, "%s: %s: unknown variable '%s'\n", my_progname,
option_is_loose ? "WARNING" : "ERROR", cur_arg); option_is_loose ? "WARNING" : "ERROR", opt_str);
if (!option_is_loose) if (!option_is_loose)
return EXIT_UNKNOWN_VARIABLE; return EXIT_UNKNOWN_VARIABLE;
} }
...@@ -246,8 +258,8 @@ int handle_options(int *argc, char ***argv, ...@@ -246,8 +258,8 @@ int handle_options(int *argc, char ***argv,
{ {
if (my_getopt_print_errors) if (my_getopt_print_errors)
fprintf(stderr, fprintf(stderr,
"%s: %s: unknown option '--%s'\n", progname, "%s: %s: unknown option '--%s'\n", my_progname,
option_is_loose ? "WARNING" : "ERROR", cur_arg); option_is_loose ? "WARNING" : "ERROR", opt_str);
if (!option_is_loose) if (!option_is_loose)
return EXIT_UNKNOWN_OPTION; return EXIT_UNKNOWN_OPTION;
} }
...@@ -264,57 +276,61 @@ int handle_options(int *argc, char ***argv, ...@@ -264,57 +276,61 @@ int handle_options(int *argc, char ***argv,
{ {
if (my_getopt_print_errors) if (my_getopt_print_errors)
fprintf(stderr, "%s: variable prefix '%s' is not unique\n", fprintf(stderr, "%s: variable prefix '%s' is not unique\n",
progname, cur_arg); my_progname, opt_str);
return EXIT_VAR_PREFIX_NOT_UNIQUE; return EXIT_VAR_PREFIX_NOT_UNIQUE;
} }
else else
{ {
if (my_getopt_print_errors) if (my_getopt_print_errors)
fprintf(stderr, "%s: ambiguous option '--%s' (%s, %s)\n", fprintf(stderr, "%s: ambiguous option '--%s' (%s, %s)\n",
progname, cur_arg, prev_found, optp->name); my_progname, opt_str, prev_found, optp->name);
return EXIT_AMBIGUOUS_OPTION; return EXIT_AMBIGUOUS_OPTION;
} }
} }
if (must_be_var && optp->var_type == GET_NO_ARG) if (must_be_var && (optp->var_type & GET_TYPE_MASK) == GET_NO_ARG)
{ {
if (my_getopt_print_errors) if (my_getopt_print_errors)
fprintf(stderr, "%s: option '%s' cannot take an argument\n", fprintf(stderr, "%s: option '%s' cannot take an argument\n",
progname, optp->name); my_progname, optp->name);
return EXIT_NO_ARGUMENT_ALLOWED; return EXIT_NO_ARGUMENT_ALLOWED;
} }
value= optp->var_type & GET_ASK_ADDR ?
(*getopt_get_addr)(key_name, strlen(key_name), optp) : optp->value;
if (optp->arg_type == NO_ARG) if (optp->arg_type == NO_ARG)
{ {
if (optend && optp->var_type != GET_BOOL) if (optend && (optp->var_type & GET_TYPE_MASK) != GET_BOOL)
{ {
if (my_getopt_print_errors) if (my_getopt_print_errors)
fprintf(stderr, "%s: option '--%s' cannot take an argument\n", fprintf(stderr, "%s: option '--%s' cannot take an argument\n",
progname, optp->name); my_progname, optp->name);
return EXIT_NO_ARGUMENT_ALLOWED; return EXIT_NO_ARGUMENT_ALLOWED;
} }
if (optp->var_type == GET_BOOL) if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL)
{ {
/* /*
Set bool to 1 if no argument or if the user has used Set bool to 1 if no argument or if the user has used
--enable-'option-name'. --enable-'option-name'.
*optend was set to '0' if one used --disable-option *optend was set to '0' if one used --disable-option
*/ */
*((my_bool*) optp->value)= (my_bool) (!optend || *optend == '1'); *((my_bool*) value)= (my_bool) (!optend || *optend == '1');
(*argc)--; (*argc)--;
get_one_option(optp->id, optp, argument); get_one_option(optp->id, optp, argument);
continue; continue;
} }
argument= optend; argument= optend;
} }
else if (optp->arg_type == OPT_ARG && optp->var_type == GET_BOOL) else if (optp->arg_type == OPT_ARG &&
(optp->var_type & GET_TYPE_MASK) == GET_BOOL)
{ {
if (optend == disabled_my_option) if (optend == disabled_my_option)
*((my_bool*) optp->value)= (my_bool) 0; *((my_bool*) value)= (my_bool) 0;
else else
{ {
if (!optend) /* No argument -> enable option */ if (!optend) /* No argument -> enable option */
*((my_bool*) optp->value)= (my_bool) 1; *((my_bool*) value)= (my_bool) 1;
else /* If argument differs from 0, enable option, else disable */ else /* If argument differs from 0, enable option, else disable */
*((my_bool*) optp->value)= (my_bool) atoi(optend) != 0; *((my_bool*) value)= (my_bool) atoi(optend) != 0;
} }
(*argc)--; (*argc)--;
continue; continue;
...@@ -326,7 +342,7 @@ int handle_options(int *argc, char ***argv, ...@@ -326,7 +342,7 @@ int handle_options(int *argc, char ***argv,
{ {
if (my_getopt_print_errors) if (my_getopt_print_errors)
fprintf(stderr, "%s: option '--%s' requires an argument\n", fprintf(stderr, "%s: option '--%s' requires an argument\n",
progname, optp->name); my_progname, optp->name);
return EXIT_ARGUMENT_REQUIRED; return EXIT_ARGUMENT_REQUIRED;
} }
argument= *pos; argument= *pos;
...@@ -346,7 +362,8 @@ int handle_options(int *argc, char ***argv, ...@@ -346,7 +362,8 @@ int handle_options(int *argc, char ***argv,
{ {
/* Option recognized. Find next what to do with it */ /* Option recognized. Find next what to do with it */
opt_found= 1; opt_found= 1;
if (optp->var_type == GET_BOOL && optp->arg_type == NO_ARG) if ((optp->var_type & GET_TYPE_MASK) == GET_BOOL &&
optp->arg_type == NO_ARG)
{ {
*((my_bool*) optp->value)= (my_bool) 1; *((my_bool*) optp->value)= (my_bool) 1;
get_one_option(optp->id, optp, argument); get_one_option(optp->id, optp, argument);
...@@ -370,7 +387,7 @@ int handle_options(int *argc, char ***argv, ...@@ -370,7 +387,7 @@ int handle_options(int *argc, char ***argv,
if (my_getopt_print_errors) if (my_getopt_print_errors)
fprintf(stderr, fprintf(stderr,
"%s: option '-%c' requires an argument\n", "%s: option '-%c' requires an argument\n",
progname, optp->id); my_progname, optp->id);
return EXIT_ARGUMENT_REQUIRED; return EXIT_ARGUMENT_REQUIRED;
} }
argument= *pos; argument= *pos;
...@@ -382,7 +399,7 @@ int handle_options(int *argc, char ***argv, ...@@ -382,7 +399,7 @@ int handle_options(int *argc, char ***argv,
{ {
fprintf(stderr, fprintf(stderr,
"%s: Error while setting value '%s' to '%s'\n", "%s: Error while setting value '%s' to '%s'\n",
progname, argument, optp->name); my_progname, argument, optp->name);
return error; return error;
} }
get_one_option(optp->id, optp, argument); get_one_option(optp->id, optp, argument);
...@@ -393,7 +410,7 @@ int handle_options(int *argc, char ***argv, ...@@ -393,7 +410,7 @@ int handle_options(int *argc, char ***argv,
{ {
if (my_getopt_print_errors) if (my_getopt_print_errors)
fprintf(stderr, fprintf(stderr,
"%s: unknown option '-%c'\n", progname, *optend); "%s: unknown option '-%c'\n", my_progname, *optend);
return EXIT_UNKNOWN_OPTION; return EXIT_UNKNOWN_OPTION;
} }
} }
...@@ -404,7 +421,7 @@ int handle_options(int *argc, char ***argv, ...@@ -404,7 +421,7 @@ int handle_options(int *argc, char ***argv,
{ {
fprintf(stderr, fprintf(stderr,
"%s: Error while setting value '%s' to '%s'\n", "%s: Error while setting value '%s' to '%s'\n",
progname, argument, optp->name); my_progname, argument, optp->name);
return error; return error;
} }
get_one_option(optp->id, optp, argument); get_one_option(optp->id, optp, argument);
...@@ -424,6 +441,47 @@ int handle_options(int *argc, char ***argv, ...@@ -424,6 +441,47 @@ int handle_options(int *argc, char ***argv,
return 0; return 0;
} }
/*
function: check_struct_option
Arguments: Current argument under processing from argv and a variable
where to store the possible key name.
Return value: In case option is a struct option, returns a pointer to
the current argument at the position where the struct option (key_name)
ends, the next character after the dot. In case argument is not a struct
option, returns a pointer to the argument.
key_name will hold the name of the key, or 0 if not found.
*/
static char *check_struct_option(char *cur_arg, char *key_name)
{
char *ptr, *ptr2;
ptr= strcend(cur_arg, '.');
ptr2= strcend(cur_arg, '=');
/*
Minimum length for a struct option is 3 (--a.b)
If the (first) dot is after an equal sign, then it is part
of a variable value and the option is not a struct option.
*/
if (strlen(ptr) >= 3 && ptr2 - ptr > 0)
{
uint len= ptr - cur_arg;
strnmov(key_name, cur_arg, len);
key_name[len]= '\0';
return ++ptr;
}
else
{
key_name= 0;
return cur_arg;
}
}
/* /*
function: setval function: setval
...@@ -444,7 +502,7 @@ static int setval(const struct my_option *opts, char *argument, ...@@ -444,7 +502,7 @@ static int setval(const struct my_option *opts, char *argument,
if (!result_pos) if (!result_pos)
return EXIT_NO_PTR_TO_VARIABLE; return EXIT_NO_PTR_TO_VARIABLE;
switch (opts->var_type) { switch ((opts->var_type & GET_TYPE_MASK)) {
case GET_INT: case GET_INT:
case GET_UINT: /* fall through */ case GET_UINT: /* fall through */
*((int*) result_pos)= (int) getopt_ll(argument, opts, &err); *((int*) result_pos)= (int) getopt_ll(argument, opts, &err);
...@@ -634,7 +692,7 @@ static void init_variables(const struct my_option *options) ...@@ -634,7 +692,7 @@ static void init_variables(const struct my_option *options)
{ {
if (options->value) if (options->value)
{ {
switch (options->var_type) { switch ((options->var_type & GET_TYPE_MASK)) {
case GET_BOOL: case GET_BOOL:
if (options->u_max_value) if (options->u_max_value)
*((my_bool*) options->u_max_value)= (my_bool) options->max_value; *((my_bool*) options->u_max_value)= (my_bool) options->max_value;
...@@ -706,13 +764,15 @@ void my_print_help(const struct my_option *options) ...@@ -706,13 +764,15 @@ void my_print_help(const struct my_option *options)
{ {
printf("--%s", optp->name); printf("--%s", optp->name);
col+= 2 + strlen(optp->name); col+= 2 + strlen(optp->name);
if (optp->var_type == GET_STR || optp->var_type == GET_STR_ALLOC) if ((optp->var_type & GET_TYPE_MASK) == GET_STR ||
(optp->var_type & GET_TYPE_MASK) == GET_STR_ALLOC)
{ {
printf("%s=name%s ", optp->arg_type == OPT_ARG ? "[" : "", printf("%s=name%s ", optp->arg_type == OPT_ARG ? "[" : "",
optp->arg_type == OPT_ARG ? "]" : ""); optp->arg_type == OPT_ARG ? "]" : "");
col+= (optp->arg_type == OPT_ARG) ? 8 : 6; col+= (optp->arg_type == OPT_ARG) ? 8 : 6;
} }
else if (optp->var_type == GET_NO_ARG || optp->var_type == GET_BOOL) else if ((optp->var_type & GET_TYPE_MASK) == GET_NO_ARG ||
(optp->var_type & GET_TYPE_MASK) == GET_BOOL)
{ {
putchar(' '); putchar(' ');
col++; col++;
...@@ -775,7 +835,7 @@ void my_print_variables(const struct my_option *options) ...@@ -775,7 +835,7 @@ void my_print_variables(const struct my_option *options)
length= strlen(optp->name); length= strlen(optp->name);
for (; length < name_space; length++) for (; length < name_space; length++)
putchar(' '); putchar(' ');
switch (optp->var_type) { switch ((optp->var_type & GET_TYPE_MASK)) {
case GET_STR: case GET_STR:
case GET_STR_ALLOC: /* fall through */ case GET_STR_ALLOC: /* fall through */
printf("%s\n", *((char**) optp->value) ? *((char**) optp->value) : printf("%s\n", *((char**) optp->value) ? *((char**) optp->value) :
......
...@@ -39,7 +39,7 @@ Item::Item(): ...@@ -39,7 +39,7 @@ Item::Item():
{ {
marker= 0; marker= 0;
maybe_null=null_value=with_sum_func=unsigned_flag=0; maybe_null=null_value=with_sum_func=unsigned_flag=0;
set_charset(&my_charset_bin, DERIVATION_COERCIBLE); set_charset(default_charset(), DERIVATION_COERCIBLE);
name= 0; name= 0;
decimals= 0; max_length= 0; decimals= 0; max_length= 0;
THD *thd= current_thd; THD *thd= current_thd;
...@@ -185,27 +185,27 @@ CHARSET_INFO * Item::default_charset() const ...@@ -185,27 +185,27 @@ CHARSET_INFO * Item::default_charset() const
bool DTCollation::aggregate(DTCollation &dt) bool DTCollation::aggregate(DTCollation &dt)
{ {
if (collation == &my_charset_bin || dt.collation == &my_charset_bin)
{
collation= &my_charset_bin;
derivation= derivation > dt.derivation ? derivation : dt.derivation;
return 0;
}
if (!my_charset_same(collation, dt.collation)) if (!my_charset_same(collation, dt.collation))
{ {
/* /*
We do allow to use binary strings (like BLOBS) We do allow to use binary strings (like BLOBS)
together with character strings. together with character strings.
Binaries have more precedance Binaries have more precedance than a character
string of the same derivation.
*/ */
if ((derivation <= dt.derivation) && (collation == &my_charset_bin)) if (collation == &my_charset_bin)
{ {
// Do nothing if (derivation <= dt.derivation)
; // Do nothing
else
set(dt);
} }
else if ((dt.derivation <= derivation) && (dt.collation==&my_charset_bin)) else if (dt.collation == &my_charset_bin)
{ {
if (dt.derivation <= derivation)
set(dt); set(dt);
else
; // Do nothing
} }
else else
{ {
......
...@@ -32,6 +32,18 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fnam ...@@ -32,6 +32,18 @@ static void my_coll_agg_error(DTCollation &c1, DTCollation &c2, const char *fnam
fname); fname);
} }
static void my_coll_agg3_error(DTCollation &c1,
DTCollation &c2,
DTCollation &c3,
const char *fname)
{
my_error(ER_CANT_AGGREGATE_3COLLATIONS,MYF(0),
c1.collation->name,c1.derivation_name(),
c2.collation->name,c2.derivation_name(),
c3.collation->name,c3.derivation_name(),
fname);
}
Item_bool_func2* Item_bool_func2::eq_creator(Item *a, Item *b) Item_bool_func2* Item_bool_func2::eq_creator(Item *a, Item *b)
{ {
return new Item_func_eq(a, b); return new Item_func_eq(a, b);
...@@ -575,11 +587,19 @@ void Item_func_between::fix_length_and_dec() ...@@ -575,11 +587,19 @@ void Item_func_between::fix_length_and_dec()
cmp_type=item_cmp_type(args[0]->result_type(), cmp_type=item_cmp_type(args[0]->result_type(),
item_cmp_type(args[1]->result_type(), item_cmp_type(args[1]->result_type(),
args[2]->result_type())); args[2]->result_type()));
/* QQ: COERCIBILITY */
if (args[0]->binary() | args[1]->binary() | args[2]->binary()) if (cmp_type == STRING_RESULT)
cmp_charset= &my_charset_bin; {
else cmp_collation.set(args[0]->collation);
cmp_charset= args[0]->charset(); if (!cmp_collation.aggregate(args[1]->collation))
cmp_collation.aggregate(args[2]->collation);
if (cmp_collation.derivation == DERIVATION_NONE)
{
my_coll_agg3_error(args[0]->collation, args[1]->collation,
args[2]->collation, func_name());
return;
}
}
/* /*
Make a special case of compare with date/time and longlong fields. Make a special case of compare with date/time and longlong fields.
...@@ -611,17 +631,17 @@ longlong Item_func_between::val_int() ...@@ -611,17 +631,17 @@ longlong Item_func_between::val_int()
a=args[1]->val_str(&value1); a=args[1]->val_str(&value1);
b=args[2]->val_str(&value2); b=args[2]->val_str(&value2);
if (!args[1]->null_value && !args[2]->null_value) if (!args[1]->null_value && !args[2]->null_value)
return (sortcmp(value,a,cmp_charset) >= 0 && return (sortcmp(value,a,cmp_collation.collation) >= 0 &&
sortcmp(value,b,cmp_charset) <= 0) ? 1 : 0; sortcmp(value,b,cmp_collation.collation) <= 0) ? 1 : 0;
if (args[1]->null_value && args[2]->null_value) if (args[1]->null_value && args[2]->null_value)
null_value=1; null_value=1;
else if (args[1]->null_value) else if (args[1]->null_value)
{ {
null_value= sortcmp(value,b,cmp_charset) <= 0; // not null if false range. null_value= sortcmp(value,b,cmp_collation.collation) <= 0; // not null if false range.
} }
else else
{ {
null_value= sortcmp(value,a,cmp_charset) >= 0; // not null if false range. null_value= sortcmp(value,a,cmp_collation.collation) >= 0; // not null if false range.
} }
} }
else if (cmp_type == INT_RESULT) else if (cmp_type == INT_RESULT)
...@@ -1176,17 +1196,17 @@ void Item_func_coalesce::fix_length_and_dec() ...@@ -1176,17 +1196,17 @@ void Item_func_coalesce::fix_length_and_dec()
Classes and function for the IN operator Classes and function for the IN operator
****************************************************************************/ ****************************************************************************/
static int cmp_longlong(longlong *a,longlong *b) static int cmp_longlong(void *cmp_arg, longlong *a,longlong *b)
{ {
return *a < *b ? -1 : *a == *b ? 0 : 1; return *a < *b ? -1 : *a == *b ? 0 : 1;
} }
static int cmp_double(double *a,double *b) static int cmp_double(void *cmp_arg, double *a,double *b)
{ {
return *a < *b ? -1 : *a == *b ? 0 : 1; return *a < *b ? -1 : *a == *b ? 0 : 1;
} }
static int cmp_row(cmp_item_row* a, cmp_item_row* b) static int cmp_row(void *cmp_arg, cmp_item_row* a, cmp_item_row* b)
{ {
return a->compare(b); return a->compare(b);
} }
...@@ -1203,18 +1223,18 @@ int in_vector::find(Item *item) ...@@ -1203,18 +1223,18 @@ int in_vector::find(Item *item)
{ {
uint mid=(start+end+1)/2; uint mid=(start+end+1)/2;
int res; int res;
if ((res=(*compare)(base+mid*size,result)) == 0) if ((res=(*compare)(collation, base+mid*size, result)) == 0)
return 1; return 1;
if (res < 0) if (res < 0)
start=mid; start=mid;
else else
end=mid-1; end=mid-1;
} }
return (int) ((*compare)(base+start*size,result) == 0); return (int) ((*compare)(collation, base+start*size, result) == 0);
} }
in_string::in_string(uint elements,qsort_cmp cmp_func) in_string::in_string(uint elements,qsort2_cmp cmp_func, CHARSET_INFO *cs)
:in_vector(elements, sizeof(String), cmp_func), :in_vector(elements, sizeof(String), cmp_func, cs),
tmp(buff, sizeof(buff), &my_charset_bin) tmp(buff, sizeof(buff), &my_charset_bin)
{} {}
...@@ -1253,7 +1273,7 @@ in_row::in_row(uint elements, Item * item) ...@@ -1253,7 +1273,7 @@ in_row::in_row(uint elements, Item * item)
{ {
base= (char*) new cmp_item_row[count= elements]; base= (char*) new cmp_item_row[count= elements];
size= sizeof(cmp_item_row); size= sizeof(cmp_item_row);
compare= (qsort_cmp) cmp_row; compare= (qsort2_cmp) cmp_row;
tmp.store_value(item); tmp.store_value(item);
} }
...@@ -1278,7 +1298,7 @@ void in_row::set(uint pos, Item *item) ...@@ -1278,7 +1298,7 @@ void in_row::set(uint pos, Item *item)
} }
in_longlong::in_longlong(uint elements) in_longlong::in_longlong(uint elements)
:in_vector(elements,sizeof(longlong),(qsort_cmp) cmp_longlong) :in_vector(elements,sizeof(longlong),(qsort2_cmp) cmp_longlong, 0)
{} {}
void in_longlong::set(uint pos,Item *item) void in_longlong::set(uint pos,Item *item)
...@@ -1295,7 +1315,7 @@ byte *in_longlong::get_value(Item *item) ...@@ -1295,7 +1315,7 @@ byte *in_longlong::get_value(Item *item)
} }
in_double::in_double(uint elements) in_double::in_double(uint elements)
:in_vector(elements,sizeof(double),(qsort_cmp) cmp_double) :in_vector(elements,sizeof(double),(qsort2_cmp) cmp_double, 0)
{} {}
void in_double::set(uint pos,Item *item) void in_double::set(uint pos,Item *item)
...@@ -1442,17 +1462,8 @@ bool Item_func_in::nulls_in_row() ...@@ -1442,17 +1462,8 @@ bool Item_func_in::nulls_in_row()
return 0; return 0;
} }
static int srtcmp_in(const String *x,const String *y) static int srtcmp_in(CHARSET_INFO *cs, const String *x,const String *y)
{
CHARSET_INFO *cs= x->charset();
return cs->coll->strnncollsp(cs,
(unsigned char *) x->ptr(),x->length(),
(unsigned char *) y->ptr(),y->length());
}
static int bincmp_in(const String *x,const String *y)
{ {
CHARSET_INFO *cs= &my_charset_bin;
return cs->coll->strnncollsp(cs, return cs->coll->strnncollsp(cs,
(unsigned char *) x->ptr(),x->length(), (unsigned char *) x->ptr(),x->length(),
(unsigned char *) y->ptr(),y->length()); (unsigned char *) y->ptr(),y->length());
...@@ -1468,10 +1479,18 @@ void Item_func_in::fix_length_and_dec() ...@@ -1468,10 +1479,18 @@ void Item_func_in::fix_length_and_dec()
{ {
switch (item->result_type()) { switch (item->result_type()) {
case STRING_RESULT: case STRING_RESULT:
if (item->binary()) uint i;
array=new in_string(arg_count,(qsort_cmp) srtcmp_in); cmp_collation.set(item->collation);
else for (i=0 ; i<arg_count; i++)
array=new in_string(arg_count,(qsort_cmp) bincmp_in); if (cmp_collation.aggregate(args[i]->collation))
break;
if (cmp_collation.derivation == DERIVATION_NONE)
{
my_error(ER_CANT_AGGREGATE_NCOLLATIONS,MYF(0),func_name());
return;
}
array=new in_string(arg_count,(qsort2_cmp) srtcmp_in,
cmp_collation.collation);
break; break;
case INT_RESULT: case INT_RESULT:
array= new in_longlong(arg_count); array= new in_longlong(arg_count);
......
...@@ -245,7 +245,7 @@ class Item_func_ne :public Item_bool_rowready_func2 ...@@ -245,7 +245,7 @@ class Item_func_ne :public Item_bool_rowready_func2
class Item_func_between :public Item_int_func class Item_func_between :public Item_int_func
{ {
CHARSET_INFO *cmp_charset; DTCollation cmp_collation;
public: public:
Item_result cmp_type; Item_result cmp_type;
String value0,value1,value2; String value0,value1,value2;
...@@ -382,21 +382,23 @@ class in_vector :public Sql_alloc ...@@ -382,21 +382,23 @@ class in_vector :public Sql_alloc
protected: protected:
char *base; char *base;
uint size; uint size;
qsort_cmp compare; qsort2_cmp compare;
CHARSET_INFO *collation;
uint count; uint count;
public: public:
uint used_count; uint used_count;
in_vector() {} in_vector() {}
in_vector(uint elements,uint element_length,qsort_cmp cmp_func) in_vector(uint elements,uint element_length,qsort2_cmp cmp_func,
CHARSET_INFO *cmp_coll)
:base((char*) sql_calloc(elements*element_length)), :base((char*) sql_calloc(elements*element_length)),
size(element_length), compare(cmp_func), count(elements), size(element_length), compare(cmp_func), collation(cmp_coll),
used_count(elements) {} count(elements), used_count(elements) {}
virtual ~in_vector() {} virtual ~in_vector() {}
virtual void set(uint pos,Item *item)=0; virtual void set(uint pos,Item *item)=0;
virtual byte *get_value(Item *item)=0; virtual byte *get_value(Item *item)=0;
void sort() void sort()
{ {
qsort(base,used_count,size,compare); qsort2(base,used_count,size,compare,collation);
} }
int find(Item *item); int find(Item *item);
}; };
...@@ -406,7 +408,7 @@ class in_string :public in_vector ...@@ -406,7 +408,7 @@ class in_string :public in_vector
char buff[80]; char buff[80];
String tmp; String tmp;
public: public:
in_string(uint elements,qsort_cmp cmp_func); in_string(uint elements,qsort2_cmp cmp_func, CHARSET_INFO *cs);
~in_string(); ~in_string();
void set(uint pos,Item *item); void set(uint pos,Item *item);
byte *get_value(Item *item); byte *get_value(Item *item);
...@@ -605,6 +607,7 @@ class Item_func_in :public Item_int_func ...@@ -605,6 +607,7 @@ class Item_func_in :public Item_int_func
in_vector *array; in_vector *array;
cmp_item *in_item; cmp_item *in_item;
bool have_null; bool have_null;
DTCollation cmp_collation;
public: public:
Item_func_in(Item *a,List<Item> &list) Item_func_in(Item *a,List<Item> &list)
:Item_int_func(list), item(a), array(0), in_item(0), have_null(0) :Item_int_func(list), item(a), array(0), in_item(0), have_null(0)
......
...@@ -4092,7 +4092,8 @@ replicating a LOAD DATA INFILE command.", ...@@ -4092,7 +4092,8 @@ replicating a LOAD DATA INFILE command.",
IO_SIZE, 0}, IO_SIZE, 0},
{"key_buffer_size", OPT_KEY_BUFFER_SIZE, {"key_buffer_size", OPT_KEY_BUFFER_SIZE,
"The size of the buffer used for index blocks. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.", "The size of the buffer used for index blocks. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.",
(gptr*) &keybuff_size, (gptr*) &keybuff_size, 0, GET_ULL, (gptr*) &keybuff_size, (gptr*) &keybuff_size, 0,
(enum get_opt_var_type) (GET_ULL | GET_ASK_ADDR),
REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD, REQUIRED_ARG, KEY_CACHE_SIZE, MALLOC_OVERHEAD, (long) ~0, MALLOC_OVERHEAD,
IO_SIZE, 0}, IO_SIZE, 0},
{"long_query_time", OPT_LONG_QUERY_TIME, {"long_query_time", OPT_LONG_QUERY_TIME,
...@@ -5298,10 +5299,19 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)), ...@@ -5298,10 +5299,19 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
} }
/* Initiates DEBUG - but no debugging here ! */ /* Initiates DEBUG - but no debugging here ! */
extern "C" gptr *
mysql_getopt_value(char *keyname, uint key_length,
const struct my_option *option)
{
return option->value;
}
static void get_options(int argc,char **argv) static void get_options(int argc,char **argv)
{ {
int ho_error; int ho_error;
my_getopt_register_get_addr(mysql_getopt_value);
if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option))) if ((ho_error=handle_options(&argc, &argv, my_long_options, get_one_option)))
exit(ho_error); exit(ho_error);
if (argc > 0) if (argc > 0)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment