1
1

Fix for bug 989: parse command line properly. Good code to tweak

around with while waiting for other things to compile.  :-)

Since there were some unit tests for the argv interface, took the
liberty of updating it for two new functions that were necessary:
ompi_argv_delete() and ompi_argv_insert().

This commit was SVN r2907.
Этот коммит содержится в:
Jeff Squyres 2004-10-01 18:38:16 +00:00
родитель 3f8c5372c6
Коммит 7f2b73a4e5
5 изменённых файлов: 534 добавлений и 175 удалений

Просмотреть файл

@ -252,3 +252,100 @@ char **ompi_argv_copy(char **argv)
return dupv;
}
int ompi_argv_delete(char **argv, int start, int num_to_delete)
{
int i;
int count;
int suffix_count;
/* Check for the bozo cases */
count = ompi_argv_count(argv);
if (NULL == argv || start > count || 0 == num_to_delete) {
return OMPI_SUCCESS;
} else if (start < 0 || num_to_delete < 0) {
return OMPI_ERR_BAD_PARAM;
}
/* Ok, we have some tokens to delete. Calculate the new length of
the argv array. */
suffix_count = count - (start + num_to_delete);
if (suffix_count < 0) {
suffix_count = 0;
}
/* Free all items that are being deleted */
for (i = start; i < count && i < start + num_to_delete; ++i) {
free(argv[i]);
}
/* Copy the suffix over the deleted items */
for (i = start; i < start + suffix_count; ++i) {
argv[i] = argv[i + num_to_delete];
}
/* Add the trailing NULL */
argv[i] = NULL;
return OMPI_SUCCESS;
}
int ompi_argv_insert(char ***target, int start, char **source)
{
int i, source_count, target_count;
int suffix_count;
/* Check for the bozo cases */
if (NULL == target || NULL == *target || start < 0) {
return OMPI_ERR_BAD_PARAM;
} else if (NULL == source) {
return OMPI_SUCCESS;
}
/* Easy case: appending to the end */
target_count = ompi_argv_count(*target);
source_count = ompi_argv_count(source);
if (start > target_count) {
for (i = 0; i < source_count; ++i) {
ompi_argv_append(&target_count, target, source[i]);
}
}
/* Harder: insertting into the middle */
else {
/* Alloc out new space */
*target = realloc(*target,
sizeof(char *) * (target_count + source_count + 1));
/* Move suffix items down to the end */
suffix_count = target_count - start;
for (i = suffix_count - 1; i >= 0; --i) {
(*target)[start + source_count + i] =
(*target)[start + i];
}
(*target)[start + suffix_count + source_count] = NULL;
/* Strdup in the source argv */
for (i = start; i < start + source_count; ++i) {
(*target)[i] = strdup(source[i - start]);
}
}
/* All done */
return OMPI_SUCCESS;
}

Просмотреть файл

@ -133,6 +133,55 @@ extern "C" {
* as the input argv, and strcmp(argv_in[i], argv_out[i]) will be 0.
*/
char **ompi_argv_copy(char **argv);
/**
* Delete one or more tokens from the middle of an argv.
*
* @param argv The argv to delete from
* @param start The index of the first token to delete
* @param num_to_delete How many tokens to delete
*
* @retval OMPI_SUCCESS Always
*
* Delete some tokens from within an existing argv. The start
* parameter specifies the first token to delete, and will delete
* (num_to_delete-1) tokens following it.
*
* If start is beyond the end of the argv array, this function is
* a no-op.
*
* If num_to_delete runs beyond the end of the argv array, this
* function will delete all tokens starting with start to the end
* of the array.
*
* All deleted items in the argv array will have their contents
* free()ed (it is assumed that the argv "owns" the memory that
* the pointer points to).
*/
int ompi_argv_delete(char **argv, int start, int num_to_delete);
/**
* Insert one argv array into the middle of another
*
* @param target The argv to insert tokens into
* @param start Index where the first token will be placed in target
* @param source The argv to copy tokens from
*
* @retval OMPI_SUCCESS upon success
* @retval OMPI_BAD_PARAM if any parameters are non-sensical
*
* This function takes one arg and inserts it in the middle of
* another. The first token in source will be insertted at index
* start in the target argv; all other tokens will follow it.
* Similar to ompi_argv_append(), the target may be realloc()'ed
* to accomodate the new storage requirements.
*
* The source array is left unaffected -- its contents are copied
* by value over to the target array (i.e., the strings that
* source points to are strdup'ed into the new locations in
* target).
*/
int ompi_argv_insert(char ***target, int start, char **source);
#ifdef __cplusplus
}
#endif

Просмотреть файл

@ -88,12 +88,12 @@ static char special_empty_token[] = {
* Private functions
*/
static void free_parse_results(ompi_cmd_line_t *cmd);
static int split_shorts(ompi_cmd_line_t *cmd, bool ignore_unknown);
static int split_shorts(ompi_cmd_line_t *cmd,
char *token, char **args,
int *output_argc, char ***output_argv,
int *num_args_used, bool ignore_unknown);
static cmd_line_option_t *find_option(ompi_cmd_line_t *cmd,
const char *option_name);
static void suck_params(ompi_cmd_line_t *cmd, cmd_line_option_t *option,
int *argc, char ***argv,
char *token, int *i);
/*
@ -170,6 +170,9 @@ int ompi_cmd_line_parse(ompi_cmd_line_t *cmd, bool ignore_unknown,
cmd_line_param_t *param;
bool is_unknown;
bool is_option;
char **shortsv;
int shortsc;
int num_args_used;
/* Bozo check */
@ -190,13 +193,6 @@ int ompi_cmd_line_parse(ompi_cmd_line_t *cmd, bool ignore_unknown,
cmd->lcl_argc = argc;
cmd->lcl_argv = ompi_argv_copy(argv);
/* Split groups of multiple short names into individual tokens */
if (OMPI_SUCCESS != (ret = split_shorts(cmd, ignore_unknown))) {
ompi_mutex_unlock(&cmd->lcl_mutex);
return ret;
}
/* Now traverse the easy-to-parse sequence of tokens. Note that
incrementing i must happen elsehwere; it can't be the third
clause in the "if" statement. */
@ -236,13 +232,45 @@ int ompi_cmd_line_parse(ompi_cmd_line_t *cmd, bool ignore_unknown,
option = find_option(cmd, cmd->lcl_argv[i] + 2);
}
/* Nope, this must be a short name (and, as a result of
split_shorts(), above, we know that there's only one short
name in this token) */
/* It could be a short name. Is it? */
else {
is_option = true;
option = find_option(cmd, cmd->lcl_argv[i] + 1);
/* If we didn't find it, try to split it into shorts. If
we find the short option, replace lcl_argv[i] and
insert the rest into lcl_argv starting after position
i. If we don't find the short option, don't do
anything to lcl_argv so that it can fall through to the
error condition, below. */
if (NULL == option) {
shortsv = NULL;
shortsc = 0;
ret = split_shorts(cmd, cmd->lcl_argv[i] + 1,
&(cmd->lcl_argv[i + 1]),
&shortsc, &shortsv,
&num_args_used, ignore_unknown);
if (OMPI_SUCCESS == ret) {
option = find_option(cmd, shortsv[0] + 1);
if (NULL != option) {
ompi_argv_delete(cmd->lcl_argv, i,
1 + num_args_used);
ompi_argv_insert(&cmd->lcl_argv, i, shortsv);
cmd->lcl_argc = ompi_argv_count(cmd->lcl_argv);
} else {
is_unknown = true;
}
ompi_argv_free(shortsv);
} else {
is_unknown = true;
}
}
if (NULL != option) {
is_option = true;
}
}
/* If we figured out above that this is an option, handle it */
@ -716,160 +744,62 @@ static void free_parse_results(ompi_cmd_line_t *cmd)
/*
* Look for collections of short names and split them into individual
* short options. Ensure to differentiate them from "single dash"
* names.
* Traverse a token and split it into individual letter options (the
* token has already been certified to not be a long name and not be a
* short name). Ensure to differentiate the resulting options from
* "single dash" names.
*/
static int split_shorts(ompi_cmd_line_t *cmd, bool ignore_unknown)
static int split_shorts(ompi_cmd_line_t *cmd, char *token, char **args,
int *output_argc, char ***output_argv,
int *num_args_used, bool ignore_unknown)
{
int i, j, k, len;
int argc;
char **argv;
char *token;
bool changed;
char new_token[3];
int i, j, len;
cmd_line_option_t *option;
char fake_token[3];
int num_args;
/* Traverse all the tokens looking for "-multiple_letters". Note
that incrementing i must happen elsehwere; it can't be the
third clause in the "if" statement. */
/* Setup that we didn't use any of the args */
argc = 0;
argv = NULL;
changed = false;
if (cmd->lcl_argc > 0) {
ompi_argv_append(&argc, &argv, cmd->lcl_argv[0]);
}
for (i = 1; i < cmd->lcl_argc; ) {
token = cmd->lcl_argv[i];
len = strlen(token);
num_args = ompi_argv_count(args);
*num_args_used = 0;
/* If we hit the special "--" token, copy the rest into the
new argv */
/* Traverse the token */
if (0 == strcmp(token, "--")) {
while (i < cmd->lcl_argc) {
ompi_argv_append(&argc, &argv, cmd->lcl_argv[i]);
++i;
}
}
len = strlen(token);
fake_token[0] = '-';
fake_token[2] = '\0';
for (i = 0; i < len; ++i) {
fake_token[1] = token[i];
option = find_option(cmd, fake_token + 1);
/* If it's a long name, find its option and copy that many
parmeters into the new argv */
/* If we don't find the option, either return an error or pass
it through unmodified to the new argv */
else if (0 == strncmp(token, "--", 2)) {
option = find_option(cmd, token + 2);
/* If we don't find the option, either return an error or
pass it through unmodified to the new argv */
if (NULL == option) {
++i;
if (!ignore_unknown) {
ompi_output(0, "Unrecognized option: '%s'", token);
return OMPI_ERR_BAD_PARAM;
} else {
ompi_argv_append(&argc, &argv, new_token);
}
}
/* If we do find the option, copy it and all of its
parameters to the output args. If we run out of
paramters (i.e., no more tokens in the original argv),
that error will be handled at a higher level) */
else {
suck_params(cmd, option, &argc, &argv, token, &i);
}
}
/* If it's a bunch of short names, handle them */
else if ('-' == token[0] && len >= 2 && '-' != token[1]) {
changed = true;
/* See if this is a "single-dash" name. If we find it,
treat it just like finding a --long name above: copy it
and all of its parameters to the output args. If we
run out of paramters (i.e., no more tokens in the
original argv), that error will be handled at a higher
level) */
option = find_option(cmd, token + 1);
if (NULL != option) {
suck_params(cmd, option, &argc, &argv, token, &i);
}
/* Nope, it must be one or more short names */
else {
++i;
for (j = 1; j < len; ++j) {
new_token[0] = '-';
new_token[1] = token[j];
new_token[2] = '\0';
option = find_option(cmd, new_token + 1);
/* If we don't find the option, either return an
error or pass it through unmodified to the new
argv */
if (NULL == option) {
if (!ignore_unknown) {
ompi_output(0, "Unrecognized option: '-%c'",
token[j]);
return OMPI_ERR_BAD_PARAM;
} else {
ompi_argv_append(&argc, &argv, new_token);
}
}
/* If we do find the option, copy it and all of
its parameters to the output args. If we run
out of paramters (i.e., no more tokens in the
original argv), that error will be handled at a
higher level) */
else {
ompi_argv_append(&argc, &argv, new_token);
for (k = 0; k < option->clo_num_params; ++k) {
if (i < cmd->lcl_argc) {
ompi_argv_append(&argc, &argv,
cmd->lcl_argv[i]);
++i;
} else {
ompi_argv_append(&argc, &argv,
special_empty_token);
}
}
}
}
}
}
/* It's unrecognized */
else {
if (NULL == option) {
if (!ignore_unknown) {
ompi_output(0, "Unrecognized option: '%s'", token);
return OMPI_ERR_BAD_PARAM;
} else {
ompi_argv_append(&argc, &argv, token);
++i;
ompi_argv_append(output_argc, output_argv, fake_token);
}
}
}
}
/* If we changed anything, then replace the argc/argv on cmd */
/* If we do find the option, copy it and all of its parameters
to the output args. If we run out of paramters (i.e., no
more tokens in the original argv), that error will be
handled at a higher level) */
if (changed) {
ompi_argv_free(cmd->lcl_argv);
cmd->lcl_argc = argc;
cmd->lcl_argv = argv;
} else {
if (NULL != argv) {
ompi_argv_free(argv);
else {
ompi_argv_append(output_argc, output_argv, fake_token);
for (j = 0; j < option->clo_num_params; ++j) {
if (*num_args_used < num_args) {
ompi_argv_append(output_argc, output_argv,
args[*num_args_used]);
++(*num_args_used);
} else {
ompi_argv_append(output_argc, output_argv,
special_empty_token);
}
}
}
}
@ -907,22 +837,3 @@ static cmd_line_option_t *find_option(ompi_cmd_line_t *cmd,
return NULL;
}
static void suck_params(ompi_cmd_line_t *cmd, cmd_line_option_t *option,
int *argc, char ***argv,
char *token, int *i)
{
int k;
ompi_argv_append(argc, argv, token);
++(*i);
for (k = 0; k < option->clo_num_params; ++k, ++(*i)) {
if ((*i) < cmd->lcl_argc) {
ompi_argv_append(argc, argv, cmd->lcl_argv[*i]);
} else {
ompi_argv_append(argc, argv, special_empty_token);
}
}
}

Просмотреть файл

@ -1,10 +1,9 @@
# -*- makefile -*-
#
# $HEADER$
#
include $(top_srcdir)/config/Makefile.options
AM_CPPFLAGS = -I$(top_srcdir)/test/support -DOMPI_ENABLE_DEBUG_OVERRIDE=1
AM_CPPFLAGS = -I$(top_srcdir)/test/support -DOMPI_ENABLE_DEBUG_OVERRIDE=1 -g
noinst_PROGRAMS = \
ompi_numtostr \

Просмотреть файл

@ -19,6 +19,8 @@ static bool test5(void);
static bool test6(void);
static bool test7(void);
static bool test8(void);
static bool test9(void);
static bool test10(void);
int main(int argc, char* argv[])
@ -50,6 +52,17 @@ int main(int argc, char* argv[])
if( test8() ) test_success();
else test_failure("test8 argv test failed");
if (test9()) {
test_success();
} else {
test_failure("test9 argv test failed");
}
if (test10()) {
test_success();
} else {
test_failure("test10 argv test failed");
}
/* All done */
test_finalize();
@ -92,6 +105,7 @@ static bool test1(void)
return false;
}
}
ompi_argv_free(argv);
return true;
}
@ -135,6 +149,11 @@ static bool test2(void)
}
}
ompi_argv_free(argv);
for (i = 0; b[i] != NULL; ++i) {
free(b[i]);
}
return true;
}
@ -166,9 +185,12 @@ static bool test3(void)
/* Do the same thing but guarantee that the copied array was from
the heap and was freed before we call ompi_argv_free(). */
argc = 0;
argv = NULL;
for (i = 0; a[i] != NULL; ++i) {
b[i] = strdup(a[i]);
}
b[i] = NULL;
for (i = 0; b[i] != NULL; ++i) {
if (ompi_argv_append(&argc, &argv, b[i]) != OMPI_SUCCESS) {
return false;
@ -324,3 +346,284 @@ static bool test8(void)
ompi_argv_free(b);
return true;
}
static bool test9(void)
{
char **a = NULL;
int argc;
/* bozo cases */
if (OMPI_SUCCESS != ompi_argv_delete(NULL, 0, 0)) {
return false;
}
a = NULL;
argc = 0;
ompi_argv_append(&argc, &a, "foo");
if (OMPI_SUCCESS != ompi_argv_delete(a, 7, 1) ||
1 != ompi_argv_count(a)) {
return false;
}
ompi_argv_free(a);
a = NULL;
argc = 0;
ompi_argv_append(&argc, &a, "foo");
if (OMPI_SUCCESS != ompi_argv_delete(a, 0, 0) ||
1 != ompi_argv_count(a)) {
return false;
}
ompi_argv_free(a);
/* now some real tests */
/* delete 1 off the top */
a = NULL;
argc = 0;
ompi_argv_append(&argc, &a, "a");
ompi_argv_append(&argc, &a, "b");
ompi_argv_append(&argc, &a, "c");
ompi_argv_append(&argc, &a, "d");
ompi_argv_append(&argc, &a, "e");
ompi_argv_append(&argc, &a, "f");
if (OMPI_SUCCESS != ompi_argv_delete(a, 0, 1) ||
5 != ompi_argv_count(a) ||
0 != strcmp(a[0], "b") ||
0 != strcmp(a[1], "c") ||
0 != strcmp(a[2], "d") ||
0 != strcmp(a[3], "e") ||
0 != strcmp(a[4], "f")) {
return false;
}
ompi_argv_free(a);
/* delete 2 off the top */
a = NULL;
argc = 0;
ompi_argv_append(&argc, &a, "a");
ompi_argv_append(&argc, &a, "b");
ompi_argv_append(&argc, &a, "c");
ompi_argv_append(&argc, &a, "d");
ompi_argv_append(&argc, &a, "e");
ompi_argv_append(&argc, &a, "f");
if (OMPI_SUCCESS != ompi_argv_delete(a, 0, 2) ||
4 != ompi_argv_count(a) ||
0 != strcmp(a[0], "c") ||
0 != strcmp(a[1], "d") ||
0 != strcmp(a[2], "e") ||
0 != strcmp(a[3], "f")) {
return false;
}
ompi_argv_free(a);
/* delete 1 in the middle */
a = NULL;
argc = 0;
ompi_argv_append(&argc, &a, "a");
ompi_argv_append(&argc, &a, "b");
ompi_argv_append(&argc, &a, "c");
ompi_argv_append(&argc, &a, "d");
ompi_argv_append(&argc, &a, "e");
ompi_argv_append(&argc, &a, "f");
if (OMPI_SUCCESS != ompi_argv_delete(a, 1, 1) ||
5 != ompi_argv_count(a) ||
0 != strcmp(a[0], "a") ||
0 != strcmp(a[1], "c") ||
0 != strcmp(a[2], "d") ||
0 != strcmp(a[3], "e") ||
0 != strcmp(a[4], "f")) {
return false;
}
ompi_argv_free(a);
/* delete 2 in the middle */
a = NULL;
argc = 0;
ompi_argv_append(&argc, &a, "a");
ompi_argv_append(&argc, &a, "b");
ompi_argv_append(&argc, &a, "c");
ompi_argv_append(&argc, &a, "d");
ompi_argv_append(&argc, &a, "e");
ompi_argv_append(&argc, &a, "f");
if (OMPI_SUCCESS != ompi_argv_delete(a, 1, 2) ||
4 != ompi_argv_count(a) ||
0 != strcmp(a[0], "a") ||
0 != strcmp(a[1], "d") ||
0 != strcmp(a[2], "e") ||
0 != strcmp(a[3], "f")) {
return false;
}
ompi_argv_free(a);
/* delete everything from the top */
a = NULL;
argc = 0;
ompi_argv_append(&argc, &a, "a");
ompi_argv_append(&argc, &a, "b");
if (OMPI_SUCCESS != ompi_argv_delete(a, 0, 99) ||
0 != ompi_argv_count(a)) {
return false;
}
ompi_argv_free(a);
/* delete everything from the middle */
a = NULL;
argc = 0;
ompi_argv_append(&argc, &a, "a");
ompi_argv_append(&argc, &a, "b");
if (OMPI_SUCCESS != ompi_argv_delete(a, 1, 99) ||
1 != ompi_argv_count(a) ||
0 != strcmp(a[0], "a")) {
return false;
}
ompi_argv_free(a);
/* All done */
return true;
}
static bool test10(void)
{
char **orig;
char **insert;
int o, i;
/* bozo cases */
orig = NULL;
o = 0;
insert = NULL;
i = 0;
ompi_argv_append(&i, &insert, "insert a");
if (OMPI_SUCCESS == ompi_argv_insert(NULL, 0, insert)) {
return false;
}
ompi_argv_append(&o, &orig, "orig a");
if (OMPI_SUCCESS != ompi_argv_insert(&orig, 0, NULL)) {
return false;
}
if (OMPI_SUCCESS == ompi_argv_insert(&orig, -1, insert)) {
return false;
}
ompi_argv_free(orig);
ompi_argv_free(insert);
/* append to the end */
orig = NULL;
o = 0;
insert = NULL;
i = 0;
ompi_argv_append(&i, &insert, "insert a");
ompi_argv_append(&i, &insert, "insert b");
ompi_argv_append(&i, &insert, "insert c");
ompi_argv_append(&o, &orig, "orig a");
ompi_argv_append(&o, &orig, "orig b");
ompi_argv_append(&o, &orig, "orig c");
if (OMPI_SUCCESS != ompi_argv_insert(&orig, 99, insert) ||
6 != ompi_argv_count(orig) ||
0 != strcmp(orig[0], "orig a") ||
0 != strcmp(orig[1], "orig b") ||
0 != strcmp(orig[2], "orig c") ||
0 != strcmp(orig[3], "insert a") ||
0 != strcmp(orig[4], "insert b") ||
0 != strcmp(orig[5], "insert c")) {
return false;
}
ompi_argv_free(orig);
ompi_argv_free(insert);
/* insert at the beginning */
orig = NULL;
o = 0;
insert = NULL;
i = 0;
ompi_argv_append(&i, &insert, "insert a");
ompi_argv_append(&i, &insert, "insert b");
ompi_argv_append(&i, &insert, "insert c");
ompi_argv_append(&o, &orig, "orig a");
ompi_argv_append(&o, &orig, "orig b");
ompi_argv_append(&o, &orig, "orig c");
if (OMPI_SUCCESS != ompi_argv_insert(&orig, 0, insert) ||
6 != ompi_argv_count(orig) ||
0 != strcmp(orig[3], "orig a") ||
0 != strcmp(orig[4], "orig b") ||
0 != strcmp(orig[5], "orig c") ||
0 != strcmp(orig[0], "insert a") ||
0 != strcmp(orig[1], "insert b") ||
0 != strcmp(orig[2], "insert c")) {
return false;
}
ompi_argv_free(orig);
ompi_argv_free(insert);
/* insert in the middle */
orig = NULL;
o = 0;
insert = NULL;
i = 0;
ompi_argv_append(&i, &insert, "insert a");
ompi_argv_append(&i, &insert, "insert b");
ompi_argv_append(&i, &insert, "insert c");
ompi_argv_append(&o, &orig, "orig a");
ompi_argv_append(&o, &orig, "orig b");
ompi_argv_append(&o, &orig, "orig c");
if (OMPI_SUCCESS != ompi_argv_insert(&orig, 1, insert) ||
6 != ompi_argv_count(orig) ||
0 != strcmp(orig[0], "orig a") ||
0 != strcmp(orig[4], "orig b") ||
0 != strcmp(orig[5], "orig c") ||
0 != strcmp(orig[1], "insert a") ||
0 != strcmp(orig[2], "insert b") ||
0 != strcmp(orig[3], "insert c")) {
return false;
}
ompi_argv_free(orig);
ompi_argv_free(insert);
/* insert in the middle */
orig = NULL;
o = 0;
insert = NULL;
i = 0;
ompi_argv_append(&i, &insert, "insert a");
ompi_argv_append(&i, &insert, "insert b");
ompi_argv_append(&i, &insert, "insert c");
ompi_argv_append(&o, &orig, "orig a");
ompi_argv_append(&o, &orig, "orig b");
ompi_argv_append(&o, &orig, "orig c");
ompi_argv_append(&o, &orig, "orig d");
ompi_argv_append(&o, &orig, "orig e");
ompi_argv_append(&o, &orig, "orig f");
if (OMPI_SUCCESS != ompi_argv_insert(&orig, 1, insert) ||
9 != ompi_argv_count(orig) ||
0 != strcmp(orig[0], "orig a") ||
0 != strcmp(orig[4], "orig b") ||
0 != strcmp(orig[5], "orig c") ||
0 != strcmp(orig[6], "orig d") ||
0 != strcmp(orig[7], "orig e") ||
0 != strcmp(orig[8], "orig f") ||
0 != strcmp(orig[1], "insert a") ||
0 != strcmp(orig[2], "insert b") ||
0 != strcmp(orig[3], "insert c")) {
return false;
}
ompi_argv_free(orig);
ompi_argv_free(insert);
/* All done */
return true;
}