diff options
-rw-r--r-- | libiberty/ChangeLog | 7 | ||||
-rw-r--r-- | libiberty/argv.c | 17 | ||||
-rw-r--r-- | libiberty/testsuite/Makefile.in | 12 | ||||
-rw-r--r-- | libiberty/testsuite/test-expandargv.c | 296 |
4 files changed, 327 insertions, 5 deletions
diff --git a/libiberty/ChangeLog b/libiberty/ChangeLog index 4d5caf3..290293c 100644 --- a/libiberty/ChangeLog +++ b/libiberty/ChangeLog @@ -1,3 +1,10 @@ +2006-01-20 Carlos O'Donell <carlos@codesourcery.com> + + * testsuite/Makefile.in: Add test-expandargv test. + * testsuite/test-expandargv.c: New test. + * argv.c (expandargv): Check for errors with ferror, + rather than just by looking at return value from fread. + 2005-12-17 Gabriel Dos Reis <gdr@integrable-solutions.net> * floatformat.c (floatformat_i387_ext_is_valid): Use explicit cast diff --git a/libiberty/argv.c b/libiberty/argv.c index 79241b6..11ca549 100644 --- a/libiberty/argv.c +++ b/libiberty/argv.c @@ -328,8 +328,12 @@ expandargv (argcp, argvp) const char *filename; /* The response file. */ FILE *f; - /* The number of characters in the response file. */ + /* An upper bound on the number of characters in the response + file. */ long pos; + /* The number of characters in the response file, when actually + read. */ + size_t len; /* A dynamically allocated buffer used to hold options read from a response file. */ char *buffer; @@ -337,7 +341,7 @@ expandargv (argcp, argvp) response file. */ char **file_argv; /* The number of options read from the response file, if any. */ - size_t file_argc; + size_t file_argc; /* We are only interested in options of the form "@file". */ filename = (*argvp)[i]; if (filename[0] != '@') @@ -354,10 +358,15 @@ expandargv (argcp, argvp) if (fseek (f, 0L, SEEK_SET) == -1) goto error; buffer = (char *) xmalloc (pos * sizeof (char) + 1); - if (fread (buffer, sizeof (char), pos, f) != (size_t) pos) + len = fread (buffer, sizeof (char), pos, f); + if (len != (size_t) pos + /* On Windows, fread may return a value smaller than POS, + due to CR/LF->CR translation when reading text files. + That does not in-and-of itself indicate failure. */ + && ferror (f)) goto error; /* Add a NUL terminator. */ - buffer[pos] = '\0'; + buffer[len] = '\0'; /* Parse the string. */ file_argv = buildargv (buffer); /* If *ARGVP is not already dynamically allocated, copy it. */ diff --git a/libiberty/testsuite/Makefile.in b/libiberty/testsuite/Makefile.in index 2be6bb3..67e1d28 100644 --- a/libiberty/testsuite/Makefile.in +++ b/libiberty/testsuite/Makefile.in @@ -45,7 +45,7 @@ all: # CHECK is set to "really_check" or the empty string by configure. check: @CHECK@ -really-check: check-cplus-dem check-pexecute +really-check: check-cplus-dem check-pexecute check-expandargv # Run some tests of the demangler. check-cplus-dem: test-demangle $(srcdir)/demangle-expected @@ -55,6 +55,10 @@ check-cplus-dem: test-demangle $(srcdir)/demangle-expected check-pexecute: test-pexecute ./test-pexecute +# Check the expandargv functionality +check-expandargv: test-expandargv + ./test-expandargv + TEST_COMPILE = $(CC) @DEFS@ $(LIBCFLAGS) -I.. -I$(INCDIR) $(HDEFINES) test-demangle: $(srcdir)/test-demangle.c ../libiberty.a $(TEST_COMPILE) -o test-demangle \ @@ -63,6 +67,10 @@ test-demangle: $(srcdir)/test-demangle.c ../libiberty.a test-pexecute: $(srcdir)/test-pexecute.c ../libiberty.a $(TEST_COMPILE) -DHAVE_CONFIG_H -I.. -o test-pexecute \ $(srcdir)/test-pexecute.c ../libiberty.a + +test-expandargv: $(srcdir)/test-expandargv.c ../libiberty.a + $(TEST_COMPILE) -DHAVE_CONFIG_H -I.. -o test-expandargv \ + $(srcdir)/test-expandargv.c ../libiberty.a # Standard (either GNU or Cygnus) rules we don't use. info install-info clean-info dvi install etags tags installcheck: @@ -70,6 +78,8 @@ info install-info clean-info dvi install etags tags installcheck: # The standard clean rules. mostlyclean: rm -f test-demangle + rm -f test-pexecute + rm -f test-expandargv clean: mostlyclean distclean: clean rm -f Makefile diff --git a/libiberty/testsuite/test-expandargv.c b/libiberty/testsuite/test-expandargv.c new file mode 100644 index 0000000..9d1af01 --- /dev/null +++ b/libiberty/testsuite/test-expandargv.c @@ -0,0 +1,296 @@ +/* expandargv test program, + Copyright (C) 2006 Free Software Foundation, Inc. + Written by Carlos O'Donell <carlos@codesourcery.com> + + This file is part of the libiberty library, which is part of GCC. + + This file is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + In addition to the permissions in the GNU General Public License, the + Free Software Foundation gives you unlimited permission to link the + compiled version of this file into combinations with other programs, + and to distribute those combinations without any restriction coming + from the use of this file. (The General Public License restrictions + do apply in other respects; for example, they cover modification of + the file, and distribution when not linked into a combined + executable.) + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. +*/ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif +#include "libiberty.h" +#include <stdio.h> +#include <errno.h> +#ifdef HAVE_STDLIB_H +#include <stdlib.h> +#endif +#ifdef HAVE_STRING_H +#include <string.h> +#endif + +#ifndef EXIT_SUCCESS +#define EXIT_SUCCESS 0 +#endif + +#ifndef EXIT_FAILURE +#define EXIT_FAILURE 1 +#endif + +static void fatal_error (int, const char *, int) ATTRIBUTE_NORETURN; +void writeout_test (int, const char *); +void run_replaces (char *); +void hook_char_replace (char *, size_t, char, char); +int run_tests (const char **); +void erase_test (int); + +/* Test input data, argv before, and argv after: + + The \n is an important part of test_data since expandargv + may have to work in environments where \n is translated + as \r\n. Thus \n is included in the test data for the file. + + We use \b to indicate that the test data is the null character. + This is because we use \0 normally to represent the end of the + file data, so we need something else for this. */ + +#define FILENAME_PATTERN "test-expandargv-%d.lst" +#define ARGV0 "test-expandargv" + +const char *test_data[] = { + /* Test 0 - Check for expansion with \r\n */ + "a\r\nb", /* Test 0 data */ + ARGV0, + "@test-expandargv-0.lst", + 0, /* End of argv[] before expansion */ + ARGV0, + "a", + "b", + 0, /* End of argv[] after expansion */ + + /* Test 1 - Check for expansion with \n */ + "a\nb", /* Test 1 data */ + ARGV0, + "@test-expandargv-1.lst", + 0, + ARGV0, + "a", + "b", + 0, + + /* Test 2 - Check for expansion with \0 */ + "a\bb", /* Test 2 data */ + ARGV0, + "@test-expandargv-2.lst", + 0, + ARGV0, + "a", + 0, + + /* Test 3 - Check for expansion with only \0 */ + "\b", /* Test 3 data */ + ARGV0, + "@test-expandargv-3.lst", + 0, + ARGV0, + 0, + + 0 /* Test done marker, don't remove. */ +}; + +/* Print a fatal error and exit. LINE is the line number where we + detected the error, ERRMSG is the error message to print, and ERR + is 0 or an errno value to print. */ + +static void +fatal_error (int line, const char *errmsg, int err) +{ + fprintf (stderr, "test-expandargv:%d: %s", line, errmsg); + if (errno != 0) + fprintf (stderr, ": %s", xstrerror (err)); + fprintf (stderr, "\n"); + exit (EXIT_FAILURE); +} + +/* hook_char_replace: + Replace 'replacethis' with 'withthis' */ + +void +hook_char_replace (char *string, size_t len, char replacethis, char withthis) +{ + int i = 0; + for (i = 0; i < len; i++) + if (string[i] == replacethis) + string[i] = withthis; +} + +/* run_replaces: + Hook here all the character for character replaces. + Be warned that expanding the string or contracting the string + should be handled with care. */ + +void +run_replaces (char * string) +{ + /* Store original string size */ + size_t len = strlen (string); + hook_char_replace (string, len, '\b', '\0'); +} + +/* write_test: + Write test datafile */ + +void +writeout_test (int test, const char * test_data) +{ + char filename[256]; + FILE *fd; + size_t len; + char * parse; + + /* Unique filename per test */ + sprintf (filename, FILENAME_PATTERN, test); + fd = fopen (filename, "w"); + if (fd == NULL) + fatal_error (__LINE__, "Failed to create test file.", errno); + + /* Generate RW copy of data for replaces */ + len = strlen (test_data); + parse = malloc (sizeof (char) * (len + 1)); + if (parse == NULL) + fatal_error (__LINE__, "Failed to malloc parse.", errno); + + memcpy (parse, test_data, sizeof (char) * len); + /* Run all possible replaces */ + run_replaces (parse); + + fwrite (parse, len, sizeof (char), fd); + free (parse); + fclose (fd); +} + +/* erase_test: + Erase the test file */ + +void +erase_test (int test) +{ + char filename[256]; + sprintf (filename, FILENAME_PATTERN, test); + if (unlink (filename) != 0) + fatal_error (__LINE__, "Failed to erase test file.", errno); +} + + +/* run_tests: + Run expandargv + Compare argv before and after. + Return number of fails */ + +int +run_tests (const char **test_data) +{ + int argc_after, argc_before; + char ** argv_before, ** argv_after; + int i, j, k, fails, failed; + + i = j = fails = 0; + /* Loop over all the tests */ + while (test_data[j]) + { + /* Write test data */ + writeout_test (i, test_data[j++]); + /* Copy argv before */ + argv_before = dupargv ((char **) &test_data[j]); + + /* Count argc before/after */ + argc_before = 0; + argc_after = 0; + while (test_data[j + argc_before]) + argc_before++; + j += argc_before + 1; /* Skip null */ + while (test_data[j + argc_after]) + argc_after++; + + /* Copy argv after */ + argv_after = dupargv ((char **) &test_data[j]); + + /* Run all possible replaces */ + for (k = 0; k < argc_before; k++) + run_replaces (argv_before[k]); + for (k = 0; k < argc_after; k++) + run_replaces (argv_after[k]); + + /* 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 (strncmp (argv_before[k], argv_after[k], strlen(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++; + + freeargv (argv_before); + freeargv (argv_after); + /* Advance to next test */ + j += argc_after + 1; + /* Erase test file */ + erase_test (i); + i++; + } + return fails; +} + +/* main: + Run tests. + Check result and exit with appropriate code. */ + +int +main(int argc, char **argv) +{ + int fails; + /* Repeat for all the tests: + - Parse data array and write into file. + - Run replace hooks before writing to file. + - Parse data array and build argv before/after. + - Run replace hooks on argv before/after + - Run expandargv. + - Compare output of expandargv argv to after argv. + - If they compare the same then test passes + else the test fails. + - Erase test file. */ + + fails = run_tests (test_data); + if (!fails) + exit (EXIT_SUCCESS); + else + exit (EXIT_FAILURE); +} + |