Bug fixes and new functionality added in my_getopt and myisamchk

parent 21255c19
...@@ -42,7 +42,6 @@ struct my_option ...@@ -42,7 +42,6 @@ struct my_option
longlong sub_size; /* Subtract this from given value */ longlong sub_size; /* Subtract this from given value */
long block_size; /* Value should be a mult. of this */ long block_size; /* Value should be a mult. of this */
int app_type; /* To be used by an application */ int app_type; /* To be used by an application */
my_bool opt_is_var; /* If true, the option is a variable */
}; };
extern int handle_options (int *argc, char ***argv, extern int handle_options (int *argc, char ***argv,
...@@ -50,3 +49,5 @@ extern int handle_options (int *argc, char ***argv, ...@@ -50,3 +49,5 @@ extern int handle_options (int *argc, char ***argv,
my_bool (*get_one_option)(int, my_bool (*get_one_option)(int,
const struct my_option *, const struct my_option *,
char *)); char *));
extern void my_print_help(const struct my_option *options);
extern void my_print_variables(const struct my_option *options);
...@@ -152,71 +152,145 @@ enum options { ...@@ -152,71 +152,145 @@ enum options {
static struct my_option my_long_options[] = static struct my_option my_long_options[] =
{ {
{"analyze", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'a', 0, 0, 0, 0, 0, 0, 0}, {"analyze",
{"block-search", "", 0, 0, 0, GET_LONG, REQUIRED_ARG, 'b', 0, 0, 0, 0, 0, 0, 0}, "Analyze distribution of keys. Will make some joins in MySQL faster. You can check the calculated distribution.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'a', 0, 0,
{"backup", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'B', 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0, 0},
{"character-sets-dir", "", (gptr*) &set_charset_name, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0, 0, 1}, {"block-search", "No help available.", 0, 0, 0, GET_LONG, REQUIRED_ARG, 'b',
0, 0, 0, 0, 0, 0},
{"check", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'c', 0, 0, 0, 0, 0, 0, 0}, {"backup", "Make a backup of the .MYD file as 'filename-time.BAK'", 0, 0, 0,
{"check-only-changed", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'C', 0, 0, 0, 0, 0, 0, 0}, GET_NO_ARG, NO_ARG, 'B', 0, 0, 0, 0, 0, 0},
{"character-sets-dir", "Directory where character sets are.",
{"correct-checksum", "", 0, 0, 0, GET_NO_ARG, NO_ARG, OPT_CORRECT_CHECKSUM, 0, 0, 0, 0, 0, 0, 0}, (gptr*) &set_charset_name, 0, 0, GET_STR, REQUIRED_ARG, OPT_CHARSETS_DIR, 0,
0, 0, 0, 0, 0},
{"check", "Check table for errors.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'c', 0, 0,
0, 0, 0, 0},
{"check-only-changed",
"Check only tables that has changed since last check.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 'C', 0, 0, 0, 0, 0, 0},
{"correct-checksum", "Correct checksum information for table.", 0, 0, 0,
GET_NO_ARG, NO_ARG, OPT_CORRECT_CHECKSUM, 0, 0, 0, 0, 0, 0},
#ifndef DBUG_OFF #ifndef DBUG_OFF
{"debug", "", 0, 0, 0, GET_STR, OPT_ARG, '#', 0, 0, 0, 0, 0, 0, 0}, {"debug", "Output debug log. Often this is 'd:t:o,filename'.", 0, 0, 0,
GET_STR, OPT_ARG, '#', 0, 0, 0, 0, 0, 0},
#endif #endif
{"description", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'd', 0, 0, 0, 0, 0, 0, 0}, {"description", "Prints some information about table.", 0, 0, 0, GET_NO_ARG,
{"data-file-length", "", 0, 0, 0, GET_LONG, REQUIRED_ARG, 'D', 0, 0, 0, 0, 0, 0, 0}, NO_ARG, 'd', 0, 0, 0, 0, 0, 0},
{"extend-check", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'e', 0, 0, 0, 0, 0, 0, 0}, {"data-file-length",
{"fast", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'F', 0, 0, 0, 0, 0, 0, 0}, "Max length of data file (when recreating data-file when it's full).",
{"force", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'f', 0, 0, 0, 0, 0, 0, 0}, (gptr*) &check_param.max_data_file_length,
{"help", "", 0, 0, 0, GET_NO_ARG, NO_ARG, '?', 0, 0, 0, 0, 0, 0, 0}, (gptr*) &check_param.max_data_file_length, 0, GET_LONG, REQUIRED_ARG, 'D',
{"information", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'i', 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0, 0, 0, 0},
{"keys-used", "", 0, 0, 0, GET_LONG, REQUIRED_ARG, 'k', 0, 0, 0, 0, 0, 0, 0}, {"extend-check",
{"medium-check", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'm', 0, 0, 0, 0, 0, 0, 0}, "Try to recover every possible row from the data file. Normally this will also find a lot of garbage rows; Don't use this option if you are not totally desperate.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'e', 0, 0, 0, 0, 0, 0},
{"quick", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'q', 0, 0, 0, 0, 0, 0, 0}, {"fast", "Check only tables that hasn't been closed properly.", 0, 0, 0,
{"read-only", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'T', 0, 0, 0, 0, 0, 0, 0}, GET_NO_ARG, NO_ARG, 'F', 0, 0, 0, 0, 0, 0},
{"recover", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'r', 0, 0, 0, 0, 0, 0, 0}, {"force",
{"safe-recover", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'o', 0, 0, 0, 0, 0, 0, 0}, "Restart with -r if there are any errors in the table. States will be updated as with --update-state.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'f', 0, 0, 0, 0, 0,
{"start-check-pos", "", 0, 0, 0, GET_LONG, REQUIRED_ARG, OPT_START_CHECK_POS, 0, 0, 0, 0, 0, 0, 0}, 0},
{"set-auto-increment", "", 0, 0, 0, GET_LONG, OPT_ARG, 'A', 0, 0, 0, 0, 0, 0, 0}, {"help", "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, '?', 0,
{"set-character-set", "", 0, 0, 0, GET_STR, REQUIRED_ARG, OPT_SET_CHARSET, 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0, 0, 0},
{"set-variable", "", 0, 0, 0, GET_STR, REQUIRED_ARG, 'O', 0, 0, 0, 0, 0, 0, 0}, {"information", "Print statistics information about table that is checked.",
{"silent", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 's', 0, 0, 0, 0, 0, 0, 0}, 0, 0, 0, GET_NO_ARG, NO_ARG, 'i', 0, 0, 0, 0, 0, 0},
{"sort-index", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'S', 0, 0, 0, 0, 0, 0, 0}, {"keys-used", "Tell MyISAM to update only some specific keys. # is a bit mask of which keys to use. This can be used to get faster inserts!",
{"sort-records", "", 0, 0, 0, GET_LONG, REQUIRED_ARG, 'R', 0, 0, 0, 0, 0, 0, 0}, (gptr*) &check_param.keys_in_use, (gptr*) &check_param.keys_in_use, 0,
{"sort-recover", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'n', 0, 0, 0, 0, 0, 0, 0}, GET_LONG, REQUIRED_ARG, 'k', 0, 0, 0, 0, 0, 0},
{"tmpdir", "", 0, 0, 0, GET_STR, REQUIRED_ARG, 't', 0, 0, 0, 0, 0, 0, 0}, {"medium-check",
{"update-state", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'U', 0, 0, 0, 0, 0, 0, 0}, "Faster than extended-check, but only finds 99.99% of all errors. Should be good enough for most cases.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'm', 0, 0, 0, 0, 0,
{"unpack", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'u', 0, 0, 0, 0, 0, 0, 0}, 0},
{"verbose", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'v', 0, 0, 0, 0, 0, 0, 0}, {"quick", "Faster repair by not modifying the data file.", 0, 0, 0,
{"version", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'V', 0, 0, 0, 0, 0, 0, 0}, GET_NO_ARG, NO_ARG, 'q', 0, 0, 0, 0, 0, 0},
{"wait", "", 0, 0, 0, GET_NO_ARG, NO_ARG, 'w', 0, 0, 0, 0, 0, 0, 0}, {"read-only", "Don't mark table as checked.", 0, 0, 0, GET_NO_ARG, NO_ARG,
'T', 0, 0, 0, 0, 0, 0},
/* variables begin here */ {"recover",
{ "key_buffer_size", "", (gptr*) &check_param.use_buffers, (gptr*) &check_param.use_buffers, 0, GET_LONG, REQUIRED_ARG, OPT_KEY_BUFFER_SIZE, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD, (long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0, 1}, "Can fix almost anything except unique keys that aren't unique.", 0, 0, 0,
{ "myisam_block_size", "", (gptr*) &opt_myisam_block_size, (gptr*) &opt_myisam_block_size, 0, GET_LONG, REQUIRED_ARG, OPT_MYISAM_BLOCK_SIZE, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH, MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0, 1}, GET_NO_ARG, NO_ARG, 'r', 0, 0, 0, 0, 0, 0},
{ "read_buffer_size", "", (gptr*) &check_param.read_buffer_length, (gptr*) &check_param.read_buffer_length, 0, GET_LONG, REQUIRED_ARG, OPT_READ_BUFFER_SIZE, (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD, (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0, 1}, {"safe-recover",
{ "write_buffer_size", "", (gptr*) &check_param.write_buffer_length, (gptr*) &check_param.write_buffer_length, 0, GET_LONG, REQUIRED_ARG, OPT_WRITE_BUFFER_SIZE, (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD, (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0, 1}, "Uses old recovery method; Slower than '-r' but can handle a couple of cases where '-r' reports that it can't fix the data file.", 0, 0, 0, GET_NO_ARG,
{ "sort_buffer_size", "", (gptr*) &check_param.sort_buffer_length, (gptr*) &check_param.sort_buffer_length, 0, GET_LONG, REQUIRED_ARG, OPT_SORT_BUFFER_SIZE, (long) SORT_BUFFER_INIT, (long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD), (long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0, 1}, NO_ARG, 'o', 0, 0, 0, 0, 0, 0},
{ "sort_key_blocks", "", (gptr*) &check_param.sort_key_blocks, (gptr*) &check_param.sort_key_blocks, 0, GET_LONG, REQUIRED_ARG, OPT_SORT_KEY_BLOCKS, BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0, 1}, {"start-check-pos", "No help available.", 0, 0, 0, GET_LONG, REQUIRED_ARG,
{ "decode_bits", "", (gptr*) &decode_bits, (gptr*) &decode_bits, 0, GET_LONG, REQUIRED_ARG, OPT_DECODE_BITS, 9L, 4L, 17L, 0L, 1L, 0, 1}, OPT_START_CHECK_POS, 0, 0, 0, 0, 0, 0},
{ "ft_min_word_len", "", (gptr*) &ft_min_word_len, (gptr*) &ft_min_word_len, 0, GET_LONG, REQUIRED_ARG, OPT_FT_MIN_WORD_LEN, 4, 1, HA_FT_MAXLEN, 0, 1, 0, 1}, {"set-auto-increment",
{ "ft_max_word_len", "", (gptr*) &ft_max_word_len, (gptr*) &ft_max_word_len, 0, GET_LONG, REQUIRED_ARG, OPT_FT_MAX_WORD_LEN, HA_FT_MAXLEN, 10, HA_FT_MAXLEN, 0, 1, 0, 1}, "Force auto_increment to start at this or higher value. If no value is given, then sets the next auto_increment value to the highest used value for the auto key + 1.", (gptr*) &check_param.auto_increment_value,
{ "ft_max_word_len_for_sort", "", (gptr*) &ft_max_word_len_for_sort, (gptr*) &ft_max_word_len_for_sort, 0, GET_LONG, REQUIRED_ARG, OPT_FT_MAX_WORD_LEN_FOR_SORT, 20, 4, HA_FT_MAXLEN, 0, 1, 0, 1}, (gptr*) &check_param.auto_increment_value, 0, GET_LONG, OPT_ARG, 'A', 0, 0,
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 0, 0, 0, 0},
{"set-character-set", "Change the character set used by the index", 0, 0, 0,
GET_STR, REQUIRED_ARG, OPT_SET_CHARSET, 0, 0, 0, 0, 0, 0},
{"set-variable", "Change the value of a variable. Please note that this option is depricated; you can set variables directly with --variable-name=value.",
0, 0, 0, GET_STR, REQUIRED_ARG, 'O', 0, 0, 0, 0, 0, 0},
{"silent",
"Only print errors. One can use two -s to make myisamchk very silent.", 0,
0, 0, GET_NO_ARG, NO_ARG, 's', 0, 0, 0, 0, 0, 0},
{"sort-index",
"Sort index blocks. This speeds up 'read-next' in applications.", 0, 0, 0,
GET_NO_ARG, NO_ARG, 'S', 0, 0, 0, 0, 0, 0},
{"sort-records",
"Sort records according to an index. This makes your data much more localized and may speed up things. (It may be VERY slow to do a sort the first time!)",
(gptr*) &check_param.opt_sort_key, (gptr*) &check_param.opt_sort_key, 0,
GET_LONG, REQUIRED_ARG, 'R', 0, 0, 0, 0, 0, 0},
{"sort-recover",
"Force recovering with sorting even if the temporary file was very big.",
0, 0, 0, GET_NO_ARG, NO_ARG, 'n', 0, 0, 0, 0, 0, 0},
{"tmpdir", "Path for temporary files.", (gptr*) &check_param.tmpdir, 0, 0,
GET_STR, REQUIRED_ARG, 't', 0, 0, 0, 0, 0, 0},
{"update-state", "Mark tables as crashed if any errors were found.", 0, 0,
0, GET_NO_ARG, NO_ARG, 'U', 0, 0, 0, 0, 0, 0},
{"unpack", "Unpack file packed with myisampack.", 0, 0, 0, GET_NO_ARG,
NO_ARG, 'u', 0, 0, 0, 0, 0, 0},
{"verbose",
"Print more information. This can be used with --describe and --check. Use many -v for more verbosity!", 0, 0, 0, GET_NO_ARG, NO_ARG, 'v', 0, 0, 0, 0, 0,
0},
{"version", "Print version and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'V', 0,
0, 0, 0, 0, 0},
{"wait", "Wait if table is locked.", 0, 0, 0, GET_NO_ARG, NO_ARG, 'w', 0, 0,
0, 0, 0, 0},
{ "key_buffer_size", "", (gptr*) &check_param.use_buffers,
(gptr*) &check_param.use_buffers, 0, GET_LONG, REQUIRED_ARG,
OPT_KEY_BUFFER_SIZE, (long) USE_BUFFER_INIT, (long) MALLOC_OVERHEAD,
(long) ~0L, (long) MALLOC_OVERHEAD, (long) IO_SIZE, 0},
{ "myisam_block_size", "", (gptr*) &opt_myisam_block_size,
(gptr*) &opt_myisam_block_size, 0, GET_LONG, REQUIRED_ARG,
OPT_MYISAM_BLOCK_SIZE, MI_KEY_BLOCK_LENGTH, MI_MIN_KEY_BLOCK_LENGTH,
MI_MAX_KEY_BLOCK_LENGTH, 0, MI_MIN_KEY_BLOCK_LENGTH, 0},
{ "read_buffer_size", "", (gptr*) &check_param.read_buffer_length,
(gptr*) &check_param.read_buffer_length, 0, GET_LONG, REQUIRED_ARG,
OPT_READ_BUFFER_SIZE, (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
(long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
{ "write_buffer_size", "", (gptr*) &check_param.write_buffer_length,
(gptr*) &check_param.write_buffer_length, 0, GET_LONG, REQUIRED_ARG,
OPT_WRITE_BUFFER_SIZE, (long) READ_BUFFER_INIT, (long) MALLOC_OVERHEAD,
(long) ~0L, (long) MALLOC_OVERHEAD, (long) 1L, 0},
{ "sort_buffer_size", "", (gptr*) &check_param.sort_buffer_length,
(gptr*) &check_param.sort_buffer_length, 0, GET_LONG, REQUIRED_ARG,
OPT_SORT_BUFFER_SIZE, (long) SORT_BUFFER_INIT,
(long) (MIN_SORT_BUFFER + MALLOC_OVERHEAD), (long) ~0L,
(long) MALLOC_OVERHEAD, (long) 1L, 0},
{ "sort_key_blocks", "", (gptr*) &check_param.sort_key_blocks,
(gptr*) &check_param.sort_key_blocks, 0, GET_LONG, REQUIRED_ARG,
OPT_SORT_KEY_BLOCKS, BUFFERS_WHEN_SORTING, 4L, 100L, 0L, 1L, 0},
{ "decode_bits", "", (gptr*) &decode_bits, (gptr*) &decode_bits, 0,
GET_LONG, REQUIRED_ARG, OPT_DECODE_BITS, 9L, 4L, 17L, 0L, 1L, 0},
{ "ft_min_word_len", "", (gptr*) &ft_min_word_len, (gptr*) &ft_min_word_len,
0, GET_LONG, REQUIRED_ARG, OPT_FT_MIN_WORD_LEN, 4, 1, HA_FT_MAXLEN, 0, 1,
0},
{ "ft_max_word_len", "", (gptr*) &ft_max_word_len, (gptr*) &ft_max_word_len,
0, GET_LONG, REQUIRED_ARG, OPT_FT_MAX_WORD_LEN, HA_FT_MAXLEN, 10,
HA_FT_MAXLEN, 0, 1, 0},
{ "ft_max_word_len_for_sort", "", (gptr*) &ft_max_word_len_for_sort,
(gptr*) &ft_max_word_len_for_sort, 0, GET_LONG, REQUIRED_ARG,
OPT_FT_MAX_WORD_LEN_FOR_SORT, 20, 4, HA_FT_MAXLEN, 0, 1, 0},
{ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
}; };
static void print_version(void) static void print_version(void)
{ {
printf("%s Ver 2.2 for %s at %s\n", my_progname, SYSTEM_TYPE, printf("%s Ver 2.3 for %s at %s\n", my_progname, SYSTEM_TYPE,
MACHINE_TYPE); MACHINE_TYPE);
} }
static void usage(void) static void usage(void)
{ {
uint i;
print_version(); print_version();
puts("By Monty, for your professional use"); puts("By Monty, for your professional use");
puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n"); puts("This software comes with NO WARRANTY: see the PUBLIC for details.\n");
...@@ -297,17 +371,9 @@ static void usage(void) ...@@ -297,17 +371,9 @@ static void usage(void)
data much more localized and may speed up things\n\ data much more localized and may speed up things\n\
(It may be VERY slow to do a sort the first time!)"); (It may be VERY slow to do a sort the first time!)");
print_defaults("my",load_default_groups); print_defaults("my", load_default_groups);
printf("\nThe variables you can set are:\n"); putchar('\n');
for (i=0; my_long_options[i].name ; i++) my_print_variables(my_long_options);
{
if (!my_long_options[i].opt_is_var)
continue;
#ifdef TO_BE_FIXED
printf("%-20s current value: %lu\n", my_long_options[i].name,
*my_long_options[i].value);
#endif
}
} }
...@@ -322,46 +388,82 @@ get_one_option(int optid, ...@@ -322,46 +388,82 @@ get_one_option(int optid,
switch (optid) { switch (optid) {
case 'a': case 'a':
if (argument && *argument == '0')
check_param.testflag&= ~T_STATISTICS;
else
check_param.testflag|= T_STATISTICS; check_param.testflag|= T_STATISTICS;
break; break;
case 'A': case 'A':
if (argument) if (argument)
check_param.auto_increment_value=strtoull(argument, NULL, 0); check_param.auto_increment_value= strtoull(argument, NULL, 0);
else else
check_param.auto_increment_value=0; /* Set to max used value */ check_param.auto_increment_value= 0; /* Set to max used value */
check_param.testflag|= T_AUTO_INC; check_param.testflag|= T_AUTO_INC;
break; break;
case 'b': case 'b':
check_param.search_after_block=strtoul(argument, NULL, 10); check_param.search_after_block= strtoul(argument, NULL, 10);
break; break;
case 'B': case 'B':
if (argument && *argument == '0')
check_param.testflag&= ~T_BACKUP_DATA;
else
check_param.testflag|= T_BACKUP_DATA; check_param.testflag|= T_BACKUP_DATA;
break; break;
case 'c': case 'c':
if (argument && *argument == '0')
check_param.testflag&= ~T_CHECK;
else
check_param.testflag|= T_CHECK; check_param.testflag|= T_CHECK;
break; break;
case 'C': case 'C':
if (argument && *argument == '0')
{
check_param.testflag&= ~T_CHECK;
check_param.testflag&= ~T_CHECK_ONLY_CHANGED;
}
else
check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED; check_param.testflag|= T_CHECK | T_CHECK_ONLY_CHANGED;
break; break;
case 'D': case 'D':
check_param.max_data_file_length=strtoll(argument, NULL, 10); check_param.max_data_file_length=strtoll(argument, NULL, 10);
break; break;
case 's': /* silent */ case 's': /* silent */
if (argument && *argument == '0')
{
if (check_param.testflag & T_VERY_SILENT)
check_param.testflag&= ~T_VERY_SILENT;
check_param.testflag&= ~T_SILENT;
}
else
{
if (check_param.testflag & T_SILENT) if (check_param.testflag & T_SILENT)
check_param.testflag|=T_VERY_SILENT; check_param.testflag|= T_VERY_SILENT;
check_param.testflag|= T_SILENT; check_param.testflag|= T_SILENT;
check_param.testflag&= ~T_WRITE_LOOP; check_param.testflag&= ~T_WRITE_LOOP;
}
break; break;
case 'w': case 'w':
if (argument && *argument == '0')
check_param.testflag&= ~T_WAIT_FOREVER;
else
check_param.testflag|= T_WAIT_FOREVER; check_param.testflag|= T_WAIT_FOREVER;
break; break;
case 'd': /* description if isam-file */ case 'd': /* description if isam-file */
if (argument && *argument == '0')
check_param.testflag&= ~T_DESCRIPT;
else
check_param.testflag|= T_DESCRIPT; check_param.testflag|= T_DESCRIPT;
break; break;
case 'e': /* extend check */ case 'e': /* extend check */
if (argument && *argument == '0')
check_param.testflag&= ~T_EXTEND;
else
check_param.testflag|= T_EXTEND; check_param.testflag|= T_EXTEND;
break; break;
case 'i': case 'i':
if (argument && *argument == '0')
check_param.testflag&= ~T_INFO;
else
check_param.testflag|= T_INFO; check_param.testflag|= T_INFO;
break; break;
case 'f': case 'f':
...@@ -369,12 +471,18 @@ get_one_option(int optid, ...@@ -369,12 +471,18 @@ get_one_option(int optid,
check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE; check_param.testflag|= T_FORCE_CREATE | T_UPDATE_STATE;
break; break;
case 'F': case 'F':
check_param.testflag|=T_FAST; if (argument && *argument == '0')
check_param.testflag&= ~T_FAST;
else
check_param.testflag|= T_FAST;
break; break;
case 'k': case 'k':
check_param.keys_in_use= (ulonglong) strtoll(argument, NULL, 10); check_param.keys_in_use= (ulonglong) strtoll(argument, NULL, 10);
break; break;
case 'm': case 'm':
if (argument && *argument == '0')
check_param.testflag&= ~T_MEDIUM;
else
check_param.testflag|= T_MEDIUM; /* Medium check */ check_param.testflag|= T_MEDIUM; /* Medium check */
break; break;
case 'r': /* Repair table */ case 'r': /* Repair table */
...@@ -387,22 +495,34 @@ get_one_option(int optid, ...@@ -387,22 +495,34 @@ get_one_option(int optid,
break; break;
case 'n': case 'n':
check_param.testflag= (check_param.testflag & ~T_REP) | T_REP_BY_SORT; check_param.testflag= (check_param.testflag & ~T_REP) | T_REP_BY_SORT;
check_param.force_sort=1; check_param.force_sort= 1;
break; break;
case 'q': case 'q':
if (argument && *argument == '0')
check_param.opt_rep_quick--;
else
check_param.opt_rep_quick++; check_param.opt_rep_quick++;
break; break;
case 'u': case 'u':
if (argument && *argument == '0')
{
check_param.testflag&= ~T_UNPACK;
check_param.testflag&= ~T_REP_BY_SORT;
}
else
check_param.testflag|= T_UNPACK | T_REP_BY_SORT; check_param.testflag|= T_UNPACK | T_REP_BY_SORT;
break; break;
case 'v': /* Verbose */ case 'v': /* Verbose */
if (argument && *argument == '0')
check_param.testflag&= ~T_VERBOSE;
else
check_param.testflag|= T_VERBOSE; check_param.testflag|= T_VERBOSE;
check_param.verbose++; check_param.verbose++;
break; break;
case 'R': /* Sort records */ case 'R': /* Sort records */
old_testflag=check_param.testflag; old_testflag= check_param.testflag;
check_param.testflag|= T_SORT_RECORDS; check_param.testflag|= T_SORT_RECORDS;
check_param.opt_sort_key=(uint) atoi(argument) - 1; check_param.opt_sort_key= (uint) atoi(argument) - 1;
if (check_param.opt_sort_key >= MI_MAX_KEY) if (check_param.opt_sort_key >= MI_MAX_KEY)
{ {
fprintf(stderr, fprintf(stderr,
...@@ -412,16 +532,25 @@ get_one_option(int optid, ...@@ -412,16 +532,25 @@ get_one_option(int optid,
} }
break; break;
case 'S': /* Sort index */ case 'S': /* Sort index */
old_testflag=check_param.testflag; old_testflag= check_param.testflag;
if (argument && *argument == '0')
check_param.testflag&= ~T_SORT_INDEX;
else
check_param.testflag|= T_SORT_INDEX; check_param.testflag|= T_SORT_INDEX;
break; break;
case 't': case 't':
check_param.tmpdir=argument; check_param.tmpdir= argument;
break; break;
case 'T': case 'T':
if (argument && *argument == '0')
check_param.testflag&= ~T_READONLY;
else
check_param.testflag|= T_READONLY; check_param.testflag|= T_READONLY;
break; break;
case 'U': case 'U':
if (argument && *argument == '0')
check_param.testflag&= ~T_UPDATE_STATE;
else
check_param.testflag|= T_UPDATE_STATE; check_param.testflag|= T_UPDATE_STATE;
break; break;
case '#': case '#':
...@@ -431,14 +560,14 @@ get_one_option(int optid, ...@@ -431,14 +560,14 @@ get_one_option(int optid,
print_version(); print_version();
exit(0); exit(0);
case OPT_CORRECT_CHECKSUM: case OPT_CORRECT_CHECKSUM:
if (*argument && *argument == '0') if (argument && *argument == '0')
check_param.testflag&= ~T_CALC_CHECKSUM; check_param.testflag&= ~T_CALC_CHECKSUM;
else else
check_param.testflag|=T_CALC_CHECKSUM; check_param.testflag|= T_CALC_CHECKSUM;
break; break;
#ifdef DEBUG /* Only useful if debugging */ #ifdef DEBUG /* Only useful if debugging */
case OPT_START_CHECK_POS: case OPT_START_CHECK_POS:
check_param.start_check_pos=strtoull(argument, NULL, 0); check_param.start_check_pos= strtoull(argument, NULL, 0);
break; break;
#endif #endif
case '?': case '?':
......
...@@ -29,8 +29,15 @@ static my_bool compare_strings (register const char *s, register const char *t, ...@@ -29,8 +29,15 @@ static my_bool compare_strings (register const char *s, register const char *t,
static longlong getopt_ll (char *arg, const struct my_option *optp, int *err); static longlong getopt_ll (char *arg, const struct my_option *optp, int *err);
static void init_variables(const struct my_option *options); static void init_variables(const struct my_option *options);
#define DISABLE_OPTION_COUNT 2 #define DISABLE_OPTION_COUNT 2
static const char *special_opt_prefix[]=
{"skip", "disable", "enable", "maximum", 0};
/* Return error values from handle_options */
#define ERR_UNKNOWN_OPTION 1 #define ERR_UNKNOWN_OPTION 1
#define ERR_AMBIGUOUS_OPTION 2 #define ERR_AMBIGUOUS_OPTION 2
#define ERR_NO_ARGUMENT_ALLOWED 3 #define ERR_NO_ARGUMENT_ALLOWED 3
...@@ -41,9 +48,6 @@ static void init_variables(const struct my_option *options); ...@@ -41,9 +48,6 @@ static void init_variables(const struct my_option *options);
#define ERR_UNKNOWN_SUFFIX 8 #define ERR_UNKNOWN_SUFFIX 8
#define ERR_NO_PTR_TO_VARIABLE 9 #define ERR_NO_PTR_TO_VARIABLE 9
static const char *special_opt_prefix[]=
{"skip", "disable", "enable", "maximum", 0};
/* /*
function: handle_options function: handle_options
...@@ -63,54 +67,51 @@ int handle_options(int *argc, char ***argv, ...@@ -63,54 +67,51 @@ int handle_options(int *argc, char ***argv,
{ {
uint opt_found, argvpos= 0, length, spec_len, i; uint opt_found, argvpos= 0, length, spec_len, i;
int err; int err;
my_bool end_of_options= 0, must_be_var, set_maximum_value; my_bool end_of_options= 0, must_be_var, set_maximum_value, special_used;
char *progname= *(*argv), **pos, *optend, *prev_found; char *progname= *(*argv), **pos, *optend, *prev_found;
const struct my_option *optp; const struct my_option *optp;
LINT_INIT(opt_found);
(*argc)--; /* Skip the program name */ (*argc)--; /* Skip the program name */
(*argv)++; /* --- || ---- */ (*argv)++; /* --- || ---- */
init_variables(longopts); init_variables(longopts);
for (pos= *argv; *pos; pos++) for (pos= *argv; *pos; pos++)
{ {
char *cur_arg= *pos; char *cur_arg= *pos;
if (*cur_arg == '-' && *(cur_arg + 1) && !end_of_options) /* must be opt */ if (cur_arg[0] == '-' && cur_arg[1] && !end_of_options) /* must be opt */
{ {
char *argument= 0; char *argument= 0;
must_be_var= 0; must_be_var= 0;
set_maximum_value= 0; set_maximum_value= 0;
special_used= 0;
/* check for long option, or --set-variable (-O) */ cur_arg++; /* skip '-' */
if (*(cur_arg + 1) == '-' || *(cur_arg + 1) == 'O') if (*cur_arg == 'O')
{
if (*(cur_arg + 1) == 'O' ||
!compare_strings(cur_arg, "--set-variable", 14))
{ {
must_be_var= 1; must_be_var= 1;
if (*(cur_arg + 1) == 'O') if (!(*++cur_arg)) /* If not -Ovar=# */
{
cur_arg+= 2;
if (!(*cur_arg))
{ {
/* the argument must be in next argv */ /* the argument must be in next argv */
if (!(*(pos + 1))) if (!*++pos)
{ {
fprintf(stderr, "%s: Option '-O' requires an argument\n", fprintf(stderr, "%s: Option '-O' requires an argument\n",
progname); progname);
return ERR_ARGUMENT_REQUIRED; return ERR_ARGUMENT_REQUIRED;
} }
pos++;
cur_arg= *pos; cur_arg= *pos;
(*argc)--; (*argc)--;
} }
} }
else /* Option argument begins with string '--set-variable' */ else if (*cur_arg == '-') /* check for long option, or --set-variable */
{ {
cur_arg+= 14; if (!compare_strings(cur_arg, "-set-variable", 13))
if (*cur_arg == '=')
{ {
cur_arg++; must_be_var= 1;
if (!(*cur_arg)) if (cur_arg[13] == '=')
{
cur_arg+= 14;
if (!*cur_arg)
{ {
fprintf(stderr, fprintf(stderr,
"%s: Option '--set-variable' requires an argument\n", "%s: Option '--set-variable' requires an argument\n",
...@@ -118,40 +119,39 @@ int handle_options(int *argc, char ***argv, ...@@ -118,40 +119,39 @@ int handle_options(int *argc, char ***argv,
return ERR_ARGUMENT_REQUIRED; return ERR_ARGUMENT_REQUIRED;
} }
} }
else if (*cur_arg) /* garbage, or another option. break out */ else if (cur_arg[14]) /* garbage, or another option. break out */
{
cur_arg-= 14;
must_be_var= 0; must_be_var= 0;
}
else else
{ {
/* the argument must be in next argv */ /* the argument must be in next argv */
if (!(*(pos + 1))) if (!*++pos)
{ {
fprintf(stderr, fprintf(stderr,
"%s: Option '--set-variable' requires an argument\n", "%s: Option '--set-variable' requires an argument\n",
progname); progname);
return ERR_ARGUMENT_REQUIRED; return ERR_ARGUMENT_REQUIRED;
} }
pos++;
cur_arg= *pos; cur_arg= *pos;
(*argc)--; (*argc)--;
} }
} }
}
else if (!must_be_var) else if (!must_be_var)
{ {
/* '--' means end of options, look no further */ if (!*++cur_arg) /* skip the double dash */
if (!*(cur_arg + 2))
{ {
/* '--' means end of options, look no further */
end_of_options= 1; end_of_options= 1;
(*argc)--; (*argc)--;
continue; continue;
} }
cur_arg+= 2; /* skip the double dash */
} }
for (optend= cur_arg; *optend && *optend != '='; optend++) ; optend= strcend(cur_arg, '=');
length= optend - cur_arg; length= optend - cur_arg;
if (*optend == '=')
optend++;
else
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
...@@ -165,7 +165,7 @@ int handle_options(int *argc, char ***argv, ...@@ -165,7 +165,7 @@ int handle_options(int *argc, char ***argv,
*/ */
if (!must_be_var) if (!must_be_var)
{ {
if (*optend == '=') if (optend)
must_be_var= 1; must_be_var= 1;
for (i= 0; special_opt_prefix[i]; i++) for (i= 0; special_opt_prefix[i]; i++)
{ {
...@@ -176,6 +176,7 @@ int handle_options(int *argc, char ***argv, ...@@ -176,6 +176,7 @@ int handle_options(int *argc, char ***argv,
/* /*
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;
cur_arg += (spec_len + 1); cur_arg += (spec_len + 1);
if ((opt_found= findopt(cur_arg, length - (spec_len + 1), if ((opt_found= findopt(cur_arg, length - (spec_len + 1),
&optp, &prev_found))) &optp, &prev_found)))
...@@ -189,9 +190,9 @@ int handle_options(int *argc, char ***argv, ...@@ -189,9 +190,9 @@ int handle_options(int *argc, char ***argv,
return ERR_AMBIGUOUS_OPTION; return ERR_AMBIGUOUS_OPTION;
} }
if (i < DISABLE_OPTION_COUNT) if (i < DISABLE_OPTION_COUNT)
optend= (char*) "=0"; optend= (char*) "0";
else if (!compare_strings(special_opt_prefix[i],"enable",6)) else if (!compare_strings(special_opt_prefix[i],"enable",6))
optend= (char*) "=1"; optend= (char*) "1";
else if (!compare_strings(special_opt_prefix[i],"maximum",7)) else if (!compare_strings(special_opt_prefix[i],"maximum",7))
{ {
set_maximum_value= 1; set_maximum_value= 1;
...@@ -233,81 +234,81 @@ int handle_options(int *argc, char ***argv, ...@@ -233,81 +234,81 @@ int handle_options(int *argc, char ***argv,
return ERR_AMBIGUOUS_OPTION; return ERR_AMBIGUOUS_OPTION;
} }
} }
if (must_be_var && !optp->opt_is_var) if (must_be_var && !optp->value)
{ {
fprintf(stderr, "%s: the argument '%s' is not an variable\n", fprintf(stderr, "%s: the argument '%s' is not an variable\n",
progname, *pos); progname, *pos);
return ERR_MUST_BE_VARIABLE; return ERR_MUST_BE_VARIABLE;
} }
if (optp->arg_type == NO_ARG && *optend == '=') if (optp->arg_type == NO_ARG && optend && !special_used)
{ {
fprintf(stderr, "%s: option '--%s' cannot take an argument\n", fprintf(stderr, "%s: option '--%s' cannot take an argument\n",
progname, optp->name); progname, optp->name);
return ERR_NO_ARGUMENT_ALLOWED; return ERR_NO_ARGUMENT_ALLOWED;
} }
else if (optp->arg_type == REQUIRED_ARG && !*optend) else if (optp->arg_type == REQUIRED_ARG && !optend)
{ {
/* Check if there are more arguments after this one */ /* Check if there are more arguments after this one */
if (!(*(pos + 1))) if (!*++pos)
{ {
fprintf(stderr, "%s: option '--%s' requires an argument\n", fprintf(stderr, "%s: option '--%s' requires an argument\n",
progname, optp->name); progname, optp->name);
return ERR_ARGUMENT_REQUIRED; return ERR_ARGUMENT_REQUIRED;
} }
pos++;
argument= *pos; argument= *pos;
(*argc)--; (*argc)--;
} }
else if (*optend == '=') else
argument= *(optend + 1) ? optend + 1 : (char*) ""; argument= optend;
} }
else /* must be short option */ else /* must be short option */
{ {
my_bool skip; for (optend= cur_arg; *optend; optend++, opt_found= 0)
for (skip= 0, optend= (cur_arg + 1); *optend && !skip; optend++)
{ {
for (optp= longopts; optp->id ; optp++) for (optp= longopts; optp->id; optp++)
{ {
if (optp->id == (int) (uchar) *optend) if (optp->id == (int) (uchar) *optend)
{ {
/* Option recognized. Find next what to do with it */ /* Option recognized. Find next what to do with it */
opt_found= 1;
if (optp->arg_type == REQUIRED_ARG || optp->arg_type == OPT_ARG) if (optp->arg_type == REQUIRED_ARG || optp->arg_type == OPT_ARG)
{ {
if (*(optend + 1)) if (*(optend + 1))
{ {
argument= (optend + 1); // The rest of the option is option argument
/* argument= optend + 1;
The rest of the option is option argument // This is in effect a jump out of the outer loop
This is in effect a jump out of this loop optend= (char*) " ";
*/
skip= 1;
} }
else if (optp->arg_type == REQUIRED_ARG) else if (optp->arg_type == REQUIRED_ARG)
{ {
/* Check if there are more arguments after this one */ /* Check if there are more arguments after this one */
if (!(*(pos + 1))) if (!*++pos)
{ {
fprintf(stderr, "%s: option '-%c' requires an argument\n", fprintf(stderr, "%s: option '-%c' requires an argument\n",
progname, optp->id); progname, optp->id);
return ERR_ARGUMENT_REQUIRED; return ERR_ARGUMENT_REQUIRED;
} }
pos++;
argument= *pos; argument= *pos;
(*argc)--; (*argc)--;
/* the other loop will break, because *optend + 1 == 0 */
} }
} }
else get_one_option(optp->id, optp, argument);
{
/* we are hitting many options in 1 argv */
if (*(optend + 1))
get_one_option(optp->id, optp, 0);
}
break; break;
} }
} }
if (!opt_found)
{
fprintf(stderr,
"%s: unknown option '-%c'\n", progname, *cur_arg);
return ERR_UNKNOWN_OPTION;
}
} }
(*argc)--; /* option handled (short), decrease argument count */
continue;
} }
if (optp->opt_is_var) if (optp->value)
{ {
gptr *result_pos= (set_maximum_value) ? gptr *result_pos= (set_maximum_value) ?
optp->u_max_value : optp->value; optp->u_max_value : optp->value;
...@@ -349,6 +350,7 @@ int handle_options(int *argc, char ***argv, ...@@ -349,6 +350,7 @@ int handle_options(int *argc, char ***argv,
list the option found, if any. In case of ambiguous option, store list the option found, if any. In case of ambiguous option, store
the name in ffname argument the name in ffname argument
*/ */
static int findopt (char *optpat, uint length, static int findopt (char *optpat, uint length,
const struct my_option **opt_res, const struct my_option **opt_res,
char **ffname) char **ffname)
...@@ -378,6 +380,7 @@ static int findopt (char *optpat, uint length, ...@@ -378,6 +380,7 @@ static int findopt (char *optpat, uint length,
Works like strncmp, other than 1.) considers '-' and '_' the same. Works like strncmp, other than 1.) considers '-' and '_' the same.
2.) Returns -1 if strings differ, 0 if they are equal 2.) Returns -1 if strings differ, 0 if they are equal
*/ */
static my_bool compare_strings(register const char *s, register const char *t, static my_bool compare_strings(register const char *s, register const char *t,
uint length) uint length)
{ {
...@@ -401,6 +404,7 @@ static my_bool compare_strings(register const char *s, register const char *t, ...@@ -401,6 +404,7 @@ static my_bool compare_strings(register const char *s, register const char *t,
that those values are honored. that those values are honored.
In case of an error, set error value in *err. In case of an error, set error value in *err.
*/ */
static longlong getopt_ll (char *arg, const struct my_option *optp, int *err) static longlong getopt_ll (char *arg, const struct my_option *optp, int *err)
{ {
char *endchar; char *endchar;
...@@ -423,11 +427,14 @@ static longlong getopt_ll (char *arg, const struct my_option *optp, int *err) ...@@ -423,11 +427,14 @@ static longlong getopt_ll (char *arg, const struct my_option *optp, int *err)
} }
if (num < (longlong) optp->min_value) if (num < (longlong) optp->min_value)
num= (longlong) optp->min_value; num= (longlong) optp->min_value;
else if (num > 0 && (ulonglong) num > (ulonglong) (ulong) optp->max_value) else if (num > 0 && (ulonglong) num > (ulonglong) (ulong) optp->max_value
&& optp->max_value) // if max value is not set -> no upper limit
num= (longlong) (ulong) optp->max_value; num= (longlong) (ulong) optp->max_value;
num= ((num - (longlong) optp->sub_size) / (ulonglong) optp->block_size); num= ((num - (longlong) optp->sub_size) / (optp->block_size ?
(ulonglong) optp->block_size :
return (longlong) (num * (ulonglong) optp->block_size); 1L));
return (longlong) (num * (optp->block_size ? (ulonglong) optp->block_size :
1L));
} }
...@@ -436,11 +443,12 @@ static longlong getopt_ll (char *arg, const struct my_option *optp, int *err) ...@@ -436,11 +443,12 @@ static longlong getopt_ll (char *arg, const struct my_option *optp, int *err)
initialize all variables to their default values initialize all variables to their default values
*/ */
static void init_variables(const struct my_option *options) static void init_variables(const struct my_option *options)
{ {
for ( ; options->name ; options++) for (; options->name; options++)
{ {
if (options->opt_is_var) if (options->value)
{ {
if (options->var_type == GET_LONG) if (options->var_type == GET_LONG)
*((long*) options->u_max_value)= *((long*) options->value)= *((long*) options->u_max_value)= *((long*) options->value)=
...@@ -451,3 +459,120 @@ static void init_variables(const struct my_option *options) ...@@ -451,3 +459,120 @@ static void init_variables(const struct my_option *options)
} }
} }
} }
/*
function: my_print_options
Print help for all options and variables.
*/
void my_print_help(const struct my_option *options)
{
uint col, name_space= 22, comment_space= 57;
const char *line_end;
const struct my_option *optp;
for (optp= options; optp->id; optp++)
{
if (optp->id < 256)
{
printf(" -%c, ", optp->id);
col= 6;
}
else
{
printf(" ");
col= 2;
}
printf("--%s", optp->name);
col+= 2 + strlen(optp->name);
if (optp->var_type == GET_STR)
{
printf("=name ");
col+= 6;
}
else if (optp->var_type == GET_NO_ARG)
{
putchar(' ');
col++;
}
else
{
printf("=# ");
col+= 3;
}
if (col > name_space)
{
putchar('\n');
col= 0;
}
for (; col < name_space; col++)
putchar(' ');
if (optp->comment && *optp->comment)
{
const char *comment= optp->comment, *end= strend(comment);
while ((uint) (end - comment) > comment_space)
{
for (line_end= comment + comment_space; *line_end != ' '; line_end--);
for (; comment != line_end; comment++)
putchar(*comment);
comment++; // skip the space, as a newline will take it's place now
putchar('\n');
for (col= 0; col < name_space; col++)
putchar(' ');
}
printf("%s", comment);
}
putchar('\n');
}
}
/*
function: my_print_options
Print variables.
*/
void my_print_variables(const struct my_option *options)
{
uint name_space= 34, length;
char buff[255];
const struct my_option *optp;
printf("Variables (--variable-name=value) Default value\n");
printf("--------------------------------- -------------\n");
for (optp= options; optp->id; optp++)
{
if (optp->value)
{
printf("%s", optp->name);
length= strlen(optp->name);
for (; length < name_space; length++)
putchar(' ');
if (optp->var_type == GET_STR)
{
if (!optp->def_value && !*((char**) optp->value))
printf("(No default value)\n");
else
printf("%s\n", *((char**) optp->value));
}
else if (optp->var_type == GET_LONG)
{
if (!optp->def_value && !*((long*) optp->value))
printf("(No default value)\n");
else
printf("%lu\n", *((long*) optp->value));
}
else
{
if (!optp->def_value && !*((longlong*) optp->value))
printf("(No default value)\n");
else
printf("%s\n", llstr(*((longlong*) optp->value), buff));
}
}
}
}
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