diff --git a/libiberty/argv.c b/libiberty/argv.c index d9d32e59e72..675336273f3 100644 --- a/libiberty/argv.c +++ b/libiberty/argv.c @@ -212,71 +212,74 @@ char **buildargv (const char *input) argv[argc] = NULL; } /* Begin scanning arg */ - arg = copybuf; - while (*input != EOS) + if (*input != EOS) { - if (ISSPACE (*input) && !squote && !dquote && !bsquote) + arg = copybuf; + while (*input != EOS) { - break; - } - else - { - if (bsquote) + if (ISSPACE (*input) && !squote && !dquote && !bsquote) { - bsquote = 0; - if (*input != '\n') - *arg++ = *input; - } - else if (*input == '\\' - && !squote - && (!dquote - || strchr ("$`\"\\\n", *(input + 1)) != NULL)) - { - bsquote = 1; - } - else if (squote) - { - if (*input == '\'') - { - squote = 0; - } - else - { - *arg++ = *input; - } - } - else if (dquote) - { - if (*input == '"') - { - dquote = 0; - } - else - { - *arg++ = *input; - } + break; } else { - if (*input == '\'') + if (bsquote) { - squote = 1; + bsquote = 0; + if (*input != '\n') + *arg++ = *input; } - else if (*input == '"') + else if (*input == '\\' + && !squote + && (!dquote + || strchr ("$`\"\\\n", *(input + 1)) != NULL)) { - dquote = 1; + bsquote = 1; + } + else if (squote) + { + if (*input == '\'') + { + squote = 0; + } + else + { + *arg++ = *input; + } + } + else if (dquote) + { + if (*input == '"') + { + dquote = 0; + } + else + { + *arg++ = *input; + } } else { - *arg++ = *input; + if (*input == '\'') + { + squote = 1; + } + else if (*input == '"') + { + dquote = 1; + } + else + { + *arg++ = *input; + } } + input++; } - input++; } + *arg = EOS; + argv[argc] = xstrdup (copybuf); + argc++; } - *arg = EOS; - argv[argc] = xstrdup (copybuf); - argc++; argv[argc] = NULL; consume_whitespace (&input); @@ -439,17 +442,8 @@ expandargv (int *argcp, char ***argvp) } /* Add a NUL terminator. */ buffer[len] = '\0'; - /* If the file is empty or contains only whitespace, buildargv would - return a single empty argument. In this context we want no arguments, - instead. */ - if (only_whitespace (buffer)) - { - file_argv = (char **) xmalloc (sizeof (char *)); - file_argv[0] = NULL; - } - else - /* Parse the string. */ - file_argv = buildargv (buffer); + /* Parse the string. */ + file_argv = buildargv (buffer); /* If *ARGVP is not already dynamically allocated, copy it. */ if (*argvp == original_argv) *argvp = dupargv (*argvp); diff --git a/libiberty/testsuite/test-expandargv.c b/libiberty/testsuite/test-expandargv.c index ea1aeb0eda2..ca7031eaf68 100644 --- a/libiberty/testsuite/test-expandargv.c +++ b/libiberty/testsuite/test-expandargv.c @@ -176,6 +176,30 @@ const char *test_data[] = { "\\t", 0, + /* Test 10 - Mixed white space characters. */ + "\t \n \t ", /* Test 10 data */ + ARGV0, + "@test-expandargv-10.lst", + 0, + ARGV0, + 0, + + /* Test 11 - Single ' ' character. */ + " ", /* Test 11 data */ + ARGV0, + "@test-expandargv-11.lst", + 0, + ARGV0, + 0, + + /* Test 12 - Multiple ' ' characters. */ + " ", /* Test 12 data */ + ARGV0, + "@test-expandargv-12.lst", + 0, + ARGV0, + 0, + 0 /* Test done marker, don't remove. */ }; @@ -265,6 +289,78 @@ erase_test (int test) fatal_error (__LINE__, "Failed to erase test file.", errno); } +/* compare_argv: + TEST is the current test number, and NAME is a short string to identify + which libibery function is being tested. ARGC_A and ARGV_A describe an + argument array, and this is compared to ARGC_B and ARGV_B, return 0 if + the two arrays match, otherwise return 1. */ + +static int +compare_argv (int test, const char *name, int argc_a, char *argv_a[], + int argc_b, char *argv_b[]) +{ + int failed = 0, k; + + if (argc_a != argc_b) + { + printf ("FAIL: test-%s-%d. Argument count didn't match\n", name, test); + failed = 1; + } + /* Compare each of the argv's ... */ + else + for (k = 0; k < argc_a; k++) + if (strcmp (argv_a[k], argv_b[k]) != 0) + { + printf ("FAIL: test-%s-%d. Arguments don't match.\n", name, test); + failed = 1; + break; + } + + if (!failed) + printf ("PASS: test-%s-%d.\n", name, test); + + return failed; +} + +/* test_buildargv + Test the buildargv function from libiberty. TEST is the current test + number and TEST_INPUT is the string to pass to buildargv (after calling + run_replaces on it). ARGC_AFTER and ARGV_AFTER are the expected + results. Return 0 if the test passes, otherwise return 1. */ + +static int +test_buildargv (int test, const char * test_input, int argc_after, + char *argv_after[]) +{ + char * input, ** argv; + size_t len; + int argc, failed; + + /* Generate RW copy of data for replaces */ + len = strlen (test_input); + input = malloc (sizeof (char) * (len + 1)); + if (input == NULL) + fatal_error (__LINE__, "Failed to malloc buildargv input buffer.", errno); + + memcpy (input, test_input, sizeof (char) * (len + 1)); + /* Run all possible replaces */ + run_replaces (input); + + /* Split INPUT into separate arguments. */ + argv = buildargv (input); + + /* Count the arguments we got back. */ + argc = 0; + while (argv[argc]) + ++argc; + + failed = compare_argv (test, "buildargv", argc_after, argv_after, argc, argv); + + free (input); + freeargv (argv); + + return failed; +} /* run_tests: Run expandargv @@ -276,12 +372,16 @@ run_tests (const char **test_data) { int argc_after, argc_before; char ** argv_before, ** argv_after; - int i, j, k, fails, failed; + int i, j, k, fails; + const char * input_str; i = j = fails = 0; /* Loop over all the tests */ while (test_data[j]) { + /* Save original input in case we run a buildargv test. */ + input_str = test_data[j]; + /* Write test data */ writeout_test (i, test_data[j++]); /* Copy argv before */ @@ -305,29 +405,23 @@ run_tests (const char **test_data) for (k = 0; k < argc_after; k++) run_replaces (argv_after[k]); + /* If the test input is just a file to expand then we can also test + calling buildargv directly as the expected output is equivalent to + calling buildargv on the contents of the file. + + The results of calling buildargv will not include the ARGV0 constant, + which is why we pass 'argc_after - 1' and 'argv_after + 1', this skips + over the ARGV0 in the expected results. */ + if (argc_before == 2) + fails += test_buildargv (i, input_str, argc_after - 1, argv_after + 1); + else + printf ("SKIP: test-buildargv-%d. This test isn't for buildargv\n", i); + /* Run test: Expand arguments */ expandargv (&argc_before, &argv_before); - failed = 0; - /* Compare size first */ - if (argc_before != argc_after) - { - printf ("FAIL: test-expandargv-%d. Number of arguments don't match.\n", i); - failed++; - } - /* Compare each of the argv's ... */ - else - for (k = 0; k < argc_after; k++) - if (strcmp (argv_before[k], argv_after[k]) != 0) - { - printf ("FAIL: test-expandargv-%d. Arguments don't match.\n", i); - failed++; - } - - if (!failed) - printf ("PASS: test-expandargv-%d.\n", i); - else - fails++; + fails += compare_argv (i, "expandargv", argc_before, argv_before, + argc_after, argv_after); freeargv (argv_before); freeargv (argv_after);