diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-08-13 14:10:55 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2011-08-13 14:15:05 +0200 |
commit | 2385c7f999c12802b11859a34b89ff7662b1f4af (patch) | |
tree | a6dc75e9438f5ea2413a627ce8dde5d28e2a195b /gl/tests | |
parent | 7f373a9e760c1aaad40aff7878dba1399831c9c3 (diff) | |
download | gnutls-2385c7f999c12802b11859a34b89ff7662b1f4af.tar.gz |
Added crywrap to the distributed programs.
Diffstat (limited to 'gl/tests')
68 files changed, 9868 insertions, 161 deletions
diff --git a/gl/tests/Makefile.am b/gl/tests/Makefile.am index 4070ef4de9..d385feb580 100644 --- a/gl/tests/Makefile.am +++ b/gl/tests/Makefile.am @@ -55,6 +55,15 @@ EXTRA_DIST += test-alloca-opt.c ## end gnulib module alloca-opt-tests +## begin gnulib module argp-tests + +TESTS += test-argp test-argp-2.sh +check_PROGRAMS += test-argp +test_argp_LDADD = $(LDADD) @LIBINTL@ +EXTRA_DIST += test-argp.c test-argp-2.sh + +## end gnulib module argp-tests + ## begin gnulib module binary-io libtests_a_SOURCES += binary-io.h @@ -103,6 +112,40 @@ EXTRA_DIST += test-md5.c ## end gnulib module crypto/md5-tests +## begin gnulib module dirent-tests + +TESTS += test-dirent +check_PROGRAMS += test-dirent +EXTRA_DIST += test-dirent.c + +## end gnulib module dirent-tests + +## begin gnulib module dup2 + + +EXTRA_DIST += dup2.c + +EXTRA_libtests_a_SOURCES += dup2.c + +## end gnulib module dup2 + +## begin gnulib module dup2-tests + +TESTS += test-dup2 +check_PROGRAMS += test-dup2 +EXTRA_DIST += test-dup2.c signature.h macros.h + +## end gnulib module dup2-tests + +## begin gnulib module environ-tests + +TESTS += test-environ +check_PROGRAMS += test-environ + +EXTRA_DIST += test-environ.c + +## end gnulib module environ-tests + ## begin gnulib module errno-tests TESTS += test-errno @@ -163,12 +206,23 @@ EXTRA_DIST += test-float.c macros.h ## end gnulib module float-tests -## begin gnulib module fpucw +## begin gnulib module frexp-nolibm-tests + +TESTS += test-frexp-nolibm +check_PROGRAMS += test-frexp-nolibm +test_frexp_nolibm_SOURCES = test-frexp.c +EXTRA_DIST += test-frexp.c minus-zero.h nan.h signature.h macros.h + +## end gnulib module frexp-nolibm-tests +## begin gnulib module frexpl-nolibm-tests -EXTRA_DIST += fpucw.h +TESTS += test-frexpl-nolibm +check_PROGRAMS += test-frexpl-nolibm +test_frexpl_nolibm_SOURCES = test-frexpl.c +EXTRA_DIST += test-frexpl.c minus-zero.h nan.h signature.h macros.h -## end gnulib module fpucw +## end gnulib module frexpl-nolibm-tests ## begin gnulib module fseek-tests @@ -180,12 +234,21 @@ EXTRA_DIST += test-fseek.c test-fseek.sh test-fseek2.sh signature.h macros.h ## begin gnulib module fseeko-tests -TESTS += test-fseeko.sh test-fseeko2.sh -check_PROGRAMS += test-fseeko -EXTRA_DIST += test-fseeko.c test-fseeko.sh test-fseeko2.sh signature.h macros.h +TESTS += test-fseeko.sh test-fseeko2.sh test-fseeko3.sh +check_PROGRAMS += test-fseeko test-fseeko3 +EXTRA_DIST += test-fseeko.c test-fseeko.sh test-fseeko2.sh test-fseeko3.c test-fseeko3.sh signature.h macros.h ## end gnulib module fseeko-tests +## begin gnulib module fseterr-tests + +TESTS += test-fseterr +check_PROGRAMS += test-fseterr + +EXTRA_DIST += test-fseterr.c + +## end gnulib module fseterr-tests + ## begin gnulib module ftell-tests TESTS += test-ftell.sh test-ftell2.sh test-ftell3 @@ -212,6 +275,23 @@ EXTRA_DIST += test-func.c macros.h ## end gnulib module func-tests +## begin gnulib module getcwd-lgpl + + +EXTRA_DIST += getcwd-lgpl.c + +EXTRA_libtests_a_SOURCES += getcwd-lgpl.c + +## end gnulib module getcwd-lgpl + +## begin gnulib module getcwd-lgpl-tests + +TESTS += test-getcwd-lgpl +check_PROGRAMS += test-getcwd-lgpl +EXTRA_DIST += test-getcwd-lgpl.c signature.h macros.h + +## end gnulib module getcwd-lgpl-tests + ## begin gnulib module getdelim-tests TESTS += test-getdelim @@ -230,6 +310,15 @@ EXTRA_DIST += test-getline.c signature.h macros.h ## end gnulib module getline-tests +## begin gnulib module getopt-posix-tests + +TESTS += test-getopt +check_PROGRAMS += test-getopt +test_getopt_LDADD = $(LDADD) $(LIBINTL) +EXTRA_DIST += macros.h signature.h test-getopt.c test-getopt.h test-getopt_long.h + +## end gnulib module getopt-posix-tests + ## begin gnulib module getpagesize @@ -248,6 +337,21 @@ EXTRA_DIST += signature.h test-gettimeofday.c ## end gnulib module gettimeofday-tests +## begin gnulib module ignore-value + + +EXTRA_DIST += ignore-value.h + +## end gnulib module ignore-value + +## begin gnulib module ignore-value-tests + +TESTS += test-ignore-value +check_PROGRAMS += test-ignore-value +EXTRA_DIST += test-ignore-value.c + +## end gnulib module ignore-value-tests + ## begin gnulib module intprops-tests TESTS += test-intprops @@ -306,6 +410,83 @@ EXTRA_DIST += test-inttypes.c ## end gnulib module inttypes-tests +## begin gnulib module isnand-nolibm-tests + +TESTS += test-isnand-nolibm +check_PROGRAMS += test-isnand-nolibm + +EXTRA_DIST += test-isnand-nolibm.c test-isnand.h minus-zero.h nan.h macros.h + +## end gnulib module isnand-nolibm-tests + +## begin gnulib module isnanf-nolibm-tests + +TESTS += test-isnanf-nolibm +check_PROGRAMS += test-isnanf-nolibm + +EXTRA_DIST += test-isnanf-nolibm.c test-isnanf.h minus-zero.h nan.h macros.h + +## end gnulib module isnanf-nolibm-tests + +## begin gnulib module isnanl-nolibm-tests + +TESTS += test-isnanl-nolibm +check_PROGRAMS += test-isnanl-nolibm + +EXTRA_DIST += test-isnanl-nolibm.c test-isnanl.h minus-zero.h nan.h macros.h + +## end gnulib module isnanl-nolibm-tests + +## begin gnulib module lstat + + +EXTRA_DIST += lstat.c + +EXTRA_libtests_a_SOURCES += lstat.c + +## end gnulib module lstat + +## begin gnulib module lstat-tests + +TESTS += test-lstat +check_PROGRAMS += test-lstat +EXTRA_DIST += test-lstat.h test-lstat.c signature.h macros.h + +## end gnulib module lstat-tests + +## begin gnulib module malloc-gnu-tests + +TESTS += test-malloc-gnu +check_PROGRAMS += test-malloc-gnu +EXTRA_DIST += test-malloc-gnu.c + +## end gnulib module malloc-gnu-tests + +## begin gnulib module malloca + +libtests_a_SOURCES += malloca.c + +EXTRA_DIST += malloca.h malloca.valgrind + +## end gnulib module malloca + +## begin gnulib module malloca-tests + +TESTS += test-malloca +check_PROGRAMS += test-malloca + +EXTRA_DIST += test-malloca.c + +## end gnulib module malloca-tests + +## begin gnulib module math-tests + +TESTS += test-math +check_PROGRAMS += test-math +EXTRA_DIST += test-math.c + +## end gnulib module math-tests + ## begin gnulib module memchr-tests TESTS += test-memchr @@ -330,6 +511,56 @@ EXTRA_DIST += test-netinet_in.c ## end gnulib module netinet_in-tests +## begin gnulib module open + + +EXTRA_DIST += open.c + +EXTRA_libtests_a_SOURCES += open.c + +## end gnulib module open + +## begin gnulib module open-tests + +TESTS += test-open +check_PROGRAMS += test-open +EXTRA_DIST += test-open.h test-open.c signature.h macros.h + +## end gnulib module open-tests + +## begin gnulib module printf-frexp-tests + +TESTS += test-printf-frexp +check_PROGRAMS += test-printf-frexp +EXTRA_DIST += test-printf-frexp.c macros.h + +## end gnulib module printf-frexp-tests + +## begin gnulib module printf-frexpl-tests + +TESTS += test-printf-frexpl +check_PROGRAMS += test-printf-frexpl +EXTRA_DIST += test-printf-frexpl.c macros.h + +## end gnulib module printf-frexpl-tests + +## begin gnulib module putenv + + +EXTRA_DIST += putenv.c + +EXTRA_libtests_a_SOURCES += putenv.c + +## end gnulib module putenv + +## begin gnulib module rawmemchr-tests + +TESTS += test-rawmemchr +check_PROGRAMS += test-rawmemchr +EXTRA_DIST += test-rawmemchr.c zerosize-ptr.h signature.h macros.h + +## end gnulib module rawmemchr-tests + ## begin gnulib module read-file-tests TESTS += test-read-file @@ -338,6 +569,47 @@ EXTRA_DIST += test-read-file.c ## end gnulib module read-file-tests +## begin gnulib module same-inode + + +EXTRA_DIST += same-inode.h + +## end gnulib module same-inode + +## begin gnulib module setenv + + +EXTRA_DIST += setenv.c + +EXTRA_libtests_a_SOURCES += setenv.c + +## end gnulib module setenv + +## begin gnulib module setenv-tests + +TESTS += test-setenv +check_PROGRAMS += test-setenv +EXTRA_DIST += test-setenv.c signature.h macros.h + +## end gnulib module setenv-tests + +## begin gnulib module signbit-tests + +TESTS += test-signbit +check_PROGRAMS += test-signbit + +EXTRA_DIST += test-signbit.c minus-zero.h macros.h + +## end gnulib module signbit-tests + +## begin gnulib module sleep-tests + +TESTS += test-sleep +check_PROGRAMS += test-sleep +EXTRA_DIST += test-sleep.c signature.h macros.h + +## end gnulib module sleep-tests + ## begin gnulib module snippet/_Noreturn # Because this Makefile snippet defines a variable used by other @@ -437,6 +709,23 @@ EXTRA_DIST += test-sockets.c ## end gnulib module sockets-tests +## begin gnulib module stat + + +EXTRA_DIST += stat.c + +EXTRA_libtests_a_SOURCES += stat.c + +## end gnulib module stat + +## begin gnulib module stat-tests + +TESTS += test-stat +check_PROGRAMS += test-stat +EXTRA_DIST += test-stat.h test-stat.c signature.h macros.h + +## end gnulib module stat-tests + ## begin gnulib module stdbool-tests TESTS += test-stdbool @@ -477,6 +766,14 @@ EXTRA_DIST += test-stdlib.c test-sys_wait.h ## end gnulib module stdlib-tests +## begin gnulib module strchrnul-tests + +TESTS += test-strchrnul +check_PROGRAMS += test-strchrnul +EXTRA_DIST += test-strchrnul.c signature.h macros.h + +## end gnulib module strchrnul-tests + ## begin gnulib module strerror-tests TESTS += test-strerror @@ -501,6 +798,14 @@ EXTRA_DIST += test-strings.c ## end gnulib module strings-tests +## begin gnulib module strnlen-tests + +TESTS += test-strnlen +check_PROGRAMS += test-strnlen +EXTRA_DIST += test-strnlen.c zerosize-ptr.h signature.h macros.h + +## end gnulib module strnlen-tests + ## begin gnulib module strverscmp-tests TESTS += test-strverscmp @@ -509,6 +814,23 @@ EXTRA_DIST += test-strverscmp.c signature.h macros.h ## end gnulib module strverscmp-tests +## begin gnulib module symlink + + +EXTRA_DIST += symlink.c + +EXTRA_libtests_a_SOURCES += symlink.c + +## end gnulib module symlink + +## begin gnulib module symlink-tests + +TESTS += test-symlink +check_PROGRAMS += test-symlink +EXTRA_DIST += test-symlink.h test-symlink.c signature.h macros.h + +## end gnulib module symlink-tests + ## begin gnulib module sys_socket-tests TESTS += test-sys_socket @@ -541,6 +863,14 @@ EXTRA_DIST += test-sys_uio.c ## end gnulib module sys_uio-tests +## begin gnulib module sysexits-tests + +TESTS += test-sysexits +check_PROGRAMS += test-sysexits +EXTRA_DIST += test-sysexits.c + +## end gnulib module sysexits-tests + ## begin gnulib module time-tests TESTS += test-time @@ -565,6 +895,23 @@ EXTRA_DIST += test-unistd.c ## end gnulib module unistd-tests +## begin gnulib module unsetenv + + +EXTRA_DIST += unsetenv.c + +EXTRA_libtests_a_SOURCES += unsetenv.c + +## end gnulib module unsetenv + +## begin gnulib module unsetenv-tests + +TESTS += test-unsetenv +check_PROGRAMS += test-unsetenv +EXTRA_DIST += test-unsetenv.c signature.h macros.h + +## end gnulib module unsetenv-tests + ## begin gnulib module vasnprintf-tests TESTS += test-vasnprintf @@ -610,6 +957,22 @@ EXTRA_DIST += test-version-etc.c test-version-etc.sh ## end gnulib module version-etc-tests +## begin gnulib module vfprintf-posix-tests + +TESTS += test-vfprintf-posix.sh +check_PROGRAMS += test-vfprintf-posix +EXTRA_DIST += test-vfprintf-posix.sh test-vfprintf-posix.c test-fprintf-posix.h test-printf-posix.output signature.h macros.h + +## end gnulib module vfprintf-posix-tests + +## begin gnulib module vprintf-posix-tests + +TESTS += test-vprintf-posix.sh +check_PROGRAMS += test-vprintf-posix +EXTRA_DIST += test-vprintf-posix.sh test-vprintf-posix.c test-printf-posix.h test-printf-posix.output signature.h macros.h + +## end gnulib module vprintf-posix-tests + ## begin gnulib module vsnprintf-tests TESTS += test-vsnprintf @@ -627,12 +990,6 @@ EXTRA_DIST += test-wchar.c ## end gnulib module wchar-tests -## begin gnulib module dummy - -libtests_a_SOURCES += dummy.c - -## end gnulib module dummy - # Clean up after Solaris cc. clean-local: rm -rf SunWS_cache diff --git a/gl/tests/dummy.c b/gl/tests/dummy.c deleted file mode 100644 index c958ea05d8..0000000000 --- a/gl/tests/dummy.c +++ /dev/null @@ -1,42 +0,0 @@ -/* A dummy file, to prevent empty libraries from breaking builds. - Copyright (C) 2004, 2007, 2009-2011 Free Software Foundation, Inc. - - This program 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 3 of the License, or - (at your option) any later version. - - 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, see <http://www.gnu.org/licenses/>. */ - -/* Some systems, reportedly OpenBSD and Mac OS X, refuse to create - libraries without any object files. You might get an error like: - - > ar cru .libs/libgl.a - > ar: no archive members specified - - Compiling this file, and adding its object file to the library, will - prevent the library from being empty. */ - -/* Some systems, such as Solaris with cc 5.0, refuse to work with libraries - that don't export any symbol. You might get an error like: - - > cc ... libgnu.a - > ild: (bad file) garbled symbol table in archive ../gllib/libgnu.a - - Compiling this file, and adding its object file to the library, will - prevent the library from exporting no symbols. */ - -#ifdef __sun -/* This declaration ensures that the library will export at least 1 symbol. */ -int gl_dummy_symbol; -#else -/* This declaration is solely to ensure that after preprocessing - this file is never empty. */ -typedef int dummy; -#endif diff --git a/gl/tests/dup2.c b/gl/tests/dup2.c new file mode 100644 index 0000000000..e00dc7b2e3 --- /dev/null +++ b/gl/tests/dup2.c @@ -0,0 +1,132 @@ +/* Duplicate an open file descriptor to a specified file descriptor. + + Copyright (C) 1999, 2004-2007, 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* written by Paul Eggert */ + +#include <config.h> + +/* Specification. */ +#include <unistd.h> + +#include <errno.h> +#include <fcntl.h> + +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +/* Get declarations of the Win32 API functions. */ +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +#endif + +#if HAVE_DUP2 + +# undef dup2 + +int +rpl_dup2 (int fd, int desired_fd) +{ + int result; +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + /* If fd is closed, mingw hangs on dup2 (fd, fd). If fd is open, + dup2 (fd, fd) returns 0, but all further attempts to use fd in + future dup2 calls will hang. */ + if (fd == desired_fd) + { + if ((HANDLE) _get_osfhandle (fd) == INVALID_HANDLE_VALUE) + { + errno = EBADF; + return -1; + } + return fd; + } + /* Wine 1.0.1 return 0 when desired_fd is negative but not -1: + http://bugs.winehq.org/show_bug.cgi?id=21289 */ + if (desired_fd < 0) + { + errno = EBADF; + return -1; + } +# elif !defined __linux__ + /* On Haiku, dup2 (fd, fd) mistakenly clears FD_CLOEXEC. */ + if (fd == desired_fd) + return fcntl (fd, F_GETFL) == -1 ? -1 : fd; +# endif + result = dup2 (fd, desired_fd); +# ifdef __linux__ + /* Correct a Linux return value. + <http://git.kernel.org/?p=linux/kernel/git/stable/linux-2.6.30.y.git;a=commitdiff;h=2b79bc4f7ebbd5af3c8b867968f9f15602d5f802> + */ + if (fd == desired_fd && result == (unsigned int) -EBADF) + { + errno = EBADF; + result = -1; + } +# endif + if (result == 0) + result = desired_fd; + /* Correct a cygwin 1.5.x errno value. */ + else if (result == -1 && errno == EMFILE) + errno = EBADF; +# if REPLACE_FCHDIR + if (fd != desired_fd && result != -1) + result = _gl_register_dup (fd, result); +# endif + return result; +} + +#else /* !HAVE_DUP2 */ + +/* On older platforms, dup2 did not exist. */ + +# ifndef F_DUPFD +static int +dupfd (int fd, int desired_fd) +{ + int duplicated_fd = dup (fd); + if (duplicated_fd < 0 || duplicated_fd == desired_fd) + return duplicated_fd; + else + { + int r = dupfd (fd, desired_fd); + int e = errno; + close (duplicated_fd); + errno = e; + return r; + } +} +# endif + +int +dup2 (int fd, int desired_fd) +{ + int result = fcntl (fd, F_GETFL) < 0 ? -1 : fd; + if (result == -1 || fd == desired_fd) + return result; + close (desired_fd); +# ifdef F_DUPFD + result = fcntl (fd, F_DUPFD, desired_fd); +# if REPLACE_FCHDIR + if (0 <= result) + result = _gl_register_dup (fd, result); +# endif +# else + result = dupfd (fd, desired_fd); +# endif + if (result == -1 && (errno == EMFILE || errno == EINVAL)) + errno = EBADF; + return result; +} +#endif /* !HAVE_DUP2 */ diff --git a/gl/tests/fpucw.h b/gl/tests/fpucw.h deleted file mode 100644 index 07403bf72b..0000000000 --- a/gl/tests/fpucw.h +++ /dev/null @@ -1,107 +0,0 @@ -/* Manipulating the FPU control word. - Copyright (C) 2007-2011 Free Software Foundation, Inc. - Written by Bruno Haible <bruno@clisp.org>, 2007. - - This program 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 3 of the License, or - (at your option) any later version. - - 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, see <http://www.gnu.org/licenses/>. */ - -#ifndef _FPUCW_H -#define _FPUCW_H - -/* The i386 floating point hardware (the 387 compatible FPU, not the modern - SSE/SSE2 hardware) has a controllable rounding precision. It is specified - through the 'PC' bits in the FPU control word ('fctrl' register). (See - the GNU libc i386 <fpu_control.h> header for details.) - - On some platforms, such as Linux or Solaris, the default precision setting - is set to "extended precision". This means that 'long double' instructions - operate correctly, but 'double' computations often produce slightly - different results as on strictly IEEE 754 conforming systems. - - On some platforms, such as NetBSD, the default precision is set to - "double precision". This means that 'long double' instructions will operate - only as 'double', i.e. lead wrong results. - - The FPU control word is under control of the application, i.e. it is - not required to be set either way by the ABI. (In fact, the i386 ABI - http://refspecs.freestandards.org/elf/abi386-4.pdf page 3-12 = page 38 - is not clear about it. But in any case, gcc treats the control word - like a "preserved" register: it emits code that assumes that the control - word is preserved across calls, and it restores the control word at the - end of functions that modify it.) - - See Vincent Lefèvre's page http://www.vinc17.org/research/extended.en.html - for a good explanation. - See http://www.uwsg.iu.edu/hypermail/linux/kernel/0103.0/0453.html for - some argumentation which setting should be the default. */ - -/* This header file provides the following facilities: - fpucw_t integral type holding the value of 'fctrl' - FPU_PC_MASK bit mask denoting the precision control - FPU_PC_DOUBLE precision control for 53 bits mantissa - FPU_PC_EXTENDED precision control for 64 bits mantissa - GET_FPUCW () yields the current FPU control word - SET_FPUCW (word) sets the FPU control word - DECL_LONG_DOUBLE_ROUNDING variable declaration for - BEGIN/END_LONG_DOUBLE_ROUNDING - BEGIN_LONG_DOUBLE_ROUNDING () starts a sequence of instructions with - 'long double' safe operation precision - END_LONG_DOUBLE_ROUNDING () ends a sequence of instructions with - 'long double' safe operation precision - */ - -/* Inline assembler like this works only with GNU C. */ -#if (defined __i386__ || defined __x86_64__) && defined __GNUC__ - -typedef unsigned short fpucw_t; /* glibc calls this fpu_control_t */ - -# define FPU_PC_MASK 0x0300 -# define FPU_PC_DOUBLE 0x200 /* glibc calls this _FPU_DOUBLE */ -# define FPU_PC_EXTENDED 0x300 /* glibc calls this _FPU_EXTENDED */ - -# define GET_FPUCW() \ - ({ fpucw_t _cw; \ - __asm__ __volatile__ ("fnstcw %0" : "=m" (*&_cw)); \ - _cw; \ - }) -# define SET_FPUCW(word) \ - (void)({ fpucw_t _ncw = (word); \ - __asm__ __volatile__ ("fldcw %0" : : "m" (*&_ncw)); \ - }) - -# define DECL_LONG_DOUBLE_ROUNDING \ - fpucw_t oldcw; -# define BEGIN_LONG_DOUBLE_ROUNDING() \ - (void)(oldcw = GET_FPUCW (), \ - SET_FPUCW ((oldcw & ~FPU_PC_MASK) | FPU_PC_EXTENDED)) -# define END_LONG_DOUBLE_ROUNDING() \ - SET_FPUCW (oldcw) - -#else - -typedef unsigned int fpucw_t; - -# define FPU_PC_MASK 0 -# define FPU_PC_DOUBLE 0 -# define FPU_PC_EXTENDED 0 - -# define GET_FPUCW() 0 -# define SET_FPUCW(word) (void)(word) - -# define DECL_LONG_DOUBLE_ROUNDING -# define BEGIN_LONG_DOUBLE_ROUNDING() -# define END_LONG_DOUBLE_ROUNDING() - -#endif - -#endif /* _FPUCW_H */ diff --git a/gl/tests/getcwd-lgpl.c b/gl/tests/getcwd-lgpl.c new file mode 100644 index 0000000000..27614228a0 --- /dev/null +++ b/gl/tests/getcwd-lgpl.c @@ -0,0 +1,125 @@ +/* Copyright (C) 2011 Free Software Foundation, Inc. + This file is part of gnulib. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Specification */ +#include <unistd.h> + +#include <errno.h> +#include <string.h> + +#if GNULIB_GETCWD +/* Favor GPL getcwd.c if both getcwd and getcwd-lgpl modules are in use. */ +typedef int dummy; +#else + +/* Get the name of the current working directory, and put it in SIZE + bytes of BUF. Returns NULL if the directory couldn't be determined + (perhaps because the absolute name was longer than PATH_MAX, or + because of missing read/search permissions on parent directories) + or SIZE was too small. If successful, returns BUF. If BUF is + NULL, an array is allocated with `malloc'; the array is SIZE bytes + long, unless SIZE == 0, in which case it is as big as + necessary. */ + +# undef getcwd +char * +rpl_getcwd (char *buf, size_t size) +{ + char *ptr; + char *result; + + /* Handle single size operations. */ + if (buf) + { + if (!size) + { + errno = EINVAL; + return NULL; + } + return getcwd (buf, size); + } + + if (size) + { + buf = malloc (size); + if (!buf) + { + errno = ENOMEM; + return NULL; + } + result = getcwd (buf, size); + if (!result) + { + int saved_errno = errno; + free (buf); + errno = saved_errno; + } + return result; + } + + /* Flexible sizing requested. Avoid over-allocation for the common + case of a name that fits within a 4k page, minus some space for + local variables, to be sure we don't skip over a guard page. */ + { + char tmp[4032]; + size = sizeof tmp; + ptr = getcwd (tmp, size); + if (ptr) + { + result = strdup (ptr); + if (!result) + errno = ENOMEM; + return result; + } + if (errno != ERANGE) + return NULL; + } + + /* My what a large directory name we have. */ + do + { + size <<= 1; + ptr = realloc (buf, size); + if (ptr == NULL) + { + free (buf); + errno = ENOMEM; + return NULL; + } + buf = ptr; + result = getcwd (buf, size); + } + while (!result && errno == ERANGE); + + if (!result) + { + int saved_errno = errno; + free (buf); + errno = saved_errno; + } + else + { + /* Trim to fit, if possible. */ + result = realloc (buf, strlen (buf) + 1); + if (!result) + result = buf; + } + return result; +} + +#endif diff --git a/gl/tests/ignore-value.h b/gl/tests/ignore-value.h new file mode 100644 index 0000000000..f021a1ac8e --- /dev/null +++ b/gl/tests/ignore-value.h @@ -0,0 +1,62 @@ +/* ignore a function return without a compiler warning + + Copyright (C) 2008-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Jim Meyering, Eric Blake and Pádraig Brady. */ + +/* Use "ignore_value" to avoid a warning when using a function declared with + gcc's warn_unused_result attribute, but for which you really do want to + ignore the result. Traditionally, people have used a "(void)" cast to + indicate that a function's return value is deliberately unused. However, + if the function is declared with __attribute__((warn_unused_result)), + gcc issues a warning even with the cast. + + Caution: most of the time, you really should heed gcc's warning, and + check the return value. However, in those exceptional cases in which + you're sure you know what you're doing, use this function. + + For the record, here's one of the ignorable warnings: + "copy.c:233: warning: ignoring return value of 'fchown', + declared with attribute warn_unused_result". */ + +#ifndef _GL_IGNORE_VALUE_H +# define _GL_IGNORE_VALUE_H + +# ifndef _GL_ATTRIBUTE_DEPRECATED +/* The __attribute__((__deprecated__)) feature + is available in gcc versions 3.1 and newer. */ +# if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 1) +# define _GL_ATTRIBUTE_DEPRECATED /* empty */ +# else +# define _GL_ATTRIBUTE_DEPRECATED __attribute__ ((__deprecated__)) +# endif +# endif + +/* The __attribute__((__warn_unused_result__)) feature + is available in gcc versions 3.4 and newer, + while the typeof feature has been available since 2.7 at least. */ +# if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) +# define ignore_value(x) ((void) (x)) +# else +# define ignore_value(x) (({ __typeof__ (x) __x = (x); (void) __x; })) +# endif + +/* ignore_value works for scalars, pointers and aggregates; + deprecate ignore_ptr. */ +static inline void _GL_ATTRIBUTE_DEPRECATED +ignore_ptr (void *p) { (void) p; } /* deprecated: use ignore_value */ + +#endif diff --git a/gl/tests/lstat.c b/gl/tests/lstat.c new file mode 100644 index 0000000000..b26065ede2 --- /dev/null +++ b/gl/tests/lstat.c @@ -0,0 +1,91 @@ +/* Work around a bug of lstat on some systems + + Copyright (C) 1997-2006, 2008-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* written by Jim Meyering */ + +#include <config.h> + +#if !HAVE_LSTAT +/* On systems that lack symlinks, our replacement <sys/stat.h> already + defined lstat as stat, so there is nothing further to do other than + avoid an empty file. */ +typedef int dummy; +#else /* HAVE_LSTAT */ + +/* Get the original definition of lstat. It might be defined as a macro. */ +# define __need_system_sys_stat_h +# include <sys/types.h> +# include <sys/stat.h> +# undef __need_system_sys_stat_h + +static inline int +orig_lstat (const char *filename, struct stat *buf) +{ + return lstat (filename, buf); +} + +/* Specification. */ +# include <sys/stat.h> + +# include <string.h> +# include <errno.h> + +/* lstat works differently on Linux and Solaris systems. POSIX (see + `pathname resolution' in the glossary) requires that programs like + `ls' take into consideration the fact that FILE has a trailing slash + when FILE is a symbolic link. On Linux and Solaris 10 systems, the + lstat function already has the desired semantics (in treating + `lstat ("symlink/", sbuf)' just like `lstat ("symlink/.", sbuf)', + but on Solaris 9 and earlier it does not. + + If FILE has a trailing slash and specifies a symbolic link, + then use stat() to get more info on the referent of FILE. + If the referent is a non-directory, then set errno to ENOTDIR + and return -1. Otherwise, return stat's result. */ + +int +rpl_lstat (const char *file, struct stat *sbuf) +{ + size_t len; + int lstat_result = orig_lstat (file, sbuf); + + if (lstat_result != 0) + return lstat_result; + + /* This replacement file can blindly check against '/' rather than + using the ISSLASH macro, because all platforms with '\\' either + lack symlinks (mingw) or have working lstat (cygwin) and thus do + not compile this file. 0 len should have already been filtered + out above, with a failure return of ENOENT. */ + len = strlen (file); + if (file[len - 1] != '/' || S_ISDIR (sbuf->st_mode)) + return 0; + + /* At this point, a trailing slash is only permitted on + symlink-to-dir; but it should have found information on the + directory, not the symlink. Call stat() to get info about the + link's referent. Our replacement stat guarantees valid results, + even if the symlink is not pointing to a directory. */ + if (!S_ISLNK (sbuf->st_mode)) + { + errno = ENOTDIR; + return -1; + } + return stat (file, sbuf); +} + +#endif /* HAVE_LSTAT */ diff --git a/gl/tests/malloca.c b/gl/tests/malloca.c new file mode 100644 index 0000000000..ce071f13a7 --- /dev/null +++ b/gl/tests/malloca.c @@ -0,0 +1,139 @@ +/* Safe automatic memory allocation. + Copyright (C) 2003, 2006-2007, 2009-2011 Free Software Foundation, Inc. + Written by Bruno Haible <bruno@clisp.org>, 2003. + + This program 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 3, or (at your option) + any later version. + + 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. */ + +#define _GL_USE_STDLIB_ALLOC 1 +#include <config.h> + +/* Specification. */ +#include "malloca.h" + +#include "verify.h" + +/* The speed critical point in this file is freea() applied to an alloca() + result: it must be fast, to match the speed of alloca(). The speed of + mmalloca() and freea() in the other case are not critical, because they + are only invoked for big memory sizes. */ + +#if HAVE_ALLOCA + +/* Store the mmalloca() results in a hash table. This is needed to reliably + distinguish a mmalloca() result and an alloca() result. + + Although it is possible that the same pointer is returned by alloca() and + by mmalloca() at different times in the same application, it does not lead + to a bug in freea(), because: + - Before a pointer returned by alloca() can point into malloc()ed memory, + the function must return, and once this has happened the programmer must + not call freea() on it anyway. + - Before a pointer returned by mmalloca() can point into the stack, it + must be freed. The only function that can free it is freea(), and + when freea() frees it, it also removes it from the hash table. */ + +#define MAGIC_NUMBER 0x1415fb4a +#define MAGIC_SIZE sizeof (int) +/* This is how the header info would look like without any alignment + considerations. */ +struct preliminary_header { void *next; char room[MAGIC_SIZE]; }; +/* But the header's size must be a multiple of sa_alignment_max. */ +#define HEADER_SIZE \ + (((sizeof (struct preliminary_header) + sa_alignment_max - 1) / sa_alignment_max) * sa_alignment_max) +struct header { void *next; char room[HEADER_SIZE - sizeof (struct preliminary_header) + MAGIC_SIZE]; }; +verify (HEADER_SIZE == sizeof (struct header)); +/* We make the hash table quite big, so that during lookups the probability + of empty hash buckets is quite high. There is no need to make the hash + table resizable, because when the hash table gets filled so much that the + lookup becomes slow, it means that the application has memory leaks. */ +#define HASH_TABLE_SIZE 257 +static void * mmalloca_results[HASH_TABLE_SIZE]; + +#endif + +void * +mmalloca (size_t n) +{ +#if HAVE_ALLOCA + /* Allocate one more word, that serves as an indicator for malloc()ed + memory, so that freea() of an alloca() result is fast. */ + size_t nplus = n + HEADER_SIZE; + + if (nplus >= n) + { + char *p = (char *) malloc (nplus); + + if (p != NULL) + { + size_t slot; + + p += HEADER_SIZE; + + /* Put a magic number into the indicator word. */ + ((int *) p)[-1] = MAGIC_NUMBER; + + /* Enter p into the hash table. */ + slot = (unsigned long) p % HASH_TABLE_SIZE; + ((struct header *) (p - HEADER_SIZE))->next = mmalloca_results[slot]; + mmalloca_results[slot] = p; + + return p; + } + } + /* Out of memory. */ + return NULL; +#else +# if !MALLOC_0_IS_NONNULL + if (n == 0) + n = 1; +# endif + return malloc (n); +#endif +} + +#if HAVE_ALLOCA +void +freea (void *p) +{ + /* mmalloca() may have returned NULL. */ + if (p != NULL) + { + /* Attempt to quickly distinguish the mmalloca() result - which has + a magic indicator word - and the alloca() result - which has an + uninitialized indicator word. It is for this test that sa_increment + additional bytes are allocated in the alloca() case. */ + if (((int *) p)[-1] == MAGIC_NUMBER) + { + /* Looks like a mmalloca() result. To see whether it really is one, + perform a lookup in the hash table. */ + size_t slot = (unsigned long) p % HASH_TABLE_SIZE; + void **chain = &mmalloca_results[slot]; + for (; *chain != NULL;) + { + if (*chain == p) + { + /* Found it. Remove it from the hash table and free it. */ + char *p_begin = (char *) p - HEADER_SIZE; + *chain = ((struct header *) p_begin)->next; + free (p_begin); + return; + } + chain = &((struct header *) ((char *) *chain - HEADER_SIZE))->next; + } + } + /* At this point, we know it was not a mmalloca() result. */ + } +} +#endif diff --git a/gl/tests/malloca.h b/gl/tests/malloca.h new file mode 100644 index 0000000000..7083a58f5b --- /dev/null +++ b/gl/tests/malloca.h @@ -0,0 +1,134 @@ +/* Safe automatic memory allocation. + Copyright (C) 2003-2007, 2009-2011 Free Software Foundation, Inc. + Written by Bruno Haible <bruno@clisp.org>, 2003. + + This program 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 3, or (at your option) + any later version. + + 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. */ + +#ifndef _MALLOCA_H +#define _MALLOCA_H + +#include <alloca.h> +#include <stddef.h> +#include <stdlib.h> + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* safe_alloca(N) is equivalent to alloca(N) when it is safe to call + alloca(N); otherwise it returns NULL. It either returns N bytes of + memory allocated on the stack, that lasts until the function returns, + or NULL. + Use of safe_alloca should be avoided: + - inside arguments of function calls - undefined behaviour, + - in inline functions - the allocation may actually last until the + calling function returns. +*/ +#if HAVE_ALLOCA +/* The OS usually guarantees only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + allocate anything larger than 4096 bytes. Also care for the possibility + of a few compiler-allocated temporary stack slots. + This must be a macro, not an inline function. */ +# define safe_alloca(N) ((N) < 4032 ? alloca (N) : NULL) +#else +# define safe_alloca(N) ((void) (N), NULL) +#endif + +/* malloca(N) is a safe variant of alloca(N). It allocates N bytes of + memory allocated on the stack, that must be freed using freea() before + the function returns. Upon failure, it returns NULL. */ +#if HAVE_ALLOCA +# define malloca(N) \ + ((N) < 4032 - sa_increment \ + ? (void *) ((char *) alloca ((N) + sa_increment) + sa_increment) \ + : mmalloca (N)) +#else +# define malloca(N) \ + mmalloca (N) +#endif +extern void * mmalloca (size_t n); + +/* Free a block of memory allocated through malloca(). */ +#if HAVE_ALLOCA +extern void freea (void *p); +#else +# define freea free +#endif + +/* nmalloca(N,S) is an overflow-safe variant of malloca (N * S). + It allocates an array of N objects, each with S bytes of memory, + on the stack. S must be positive and N must be nonnegative. + The array must be freed using freea() before the function returns. */ +#if 1 +/* Cf. the definition of xalloc_oversized. */ +# define nmalloca(n, s) \ + ((n) > (size_t) (sizeof (ptrdiff_t) <= sizeof (size_t) ? -1 : -2) / (s) \ + ? NULL \ + : malloca ((n) * (s))) +#else +extern void * nmalloca (size_t n, size_t s); +#endif + + +#ifdef __cplusplus +} +#endif + + +/* ------------------- Auxiliary, non-public definitions ------------------- */ + +/* Determine the alignment of a type at compile time. */ +#if defined __GNUC__ +# define sa_alignof __alignof__ +#elif defined __cplusplus + template <class type> struct sa_alignof_helper { char __slot1; type __slot2; }; +# define sa_alignof(type) offsetof (sa_alignof_helper<type>, __slot2) +#elif defined __hpux + /* Work around a HP-UX 10.20 cc bug with enums constants defined as offsetof + values. */ +# define sa_alignof(type) (sizeof (type) <= 4 ? 4 : 8) +#elif defined _AIX + /* Work around an AIX 3.2.5 xlc bug with enums constants defined as offsetof + values. */ +# define sa_alignof(type) (sizeof (type) <= 4 ? 4 : 8) +#else +# define sa_alignof(type) offsetof (struct { char __slot1; type __slot2; }, __slot2) +#endif + +enum +{ +/* The desired alignment of memory allocations is the maximum alignment + among all elementary types. */ + sa_alignment_long = sa_alignof (long), + sa_alignment_double = sa_alignof (double), +#if HAVE_LONG_LONG_INT + sa_alignment_longlong = sa_alignof (long long), +#endif + sa_alignment_longdouble = sa_alignof (long double), + sa_alignment_max = ((sa_alignment_long - 1) | (sa_alignment_double - 1) +#if HAVE_LONG_LONG_INT + | (sa_alignment_longlong - 1) +#endif + | (sa_alignment_longdouble - 1) + ) + 1, +/* The increment that guarantees room for a magic word must be >= sizeof (int) + and a multiple of sa_alignment_max. */ + sa_increment = ((sizeof (int) + sa_alignment_max - 1) / sa_alignment_max) * sa_alignment_max +}; + +#endif /* _MALLOCA_H */ diff --git a/gl/tests/malloca.valgrind b/gl/tests/malloca.valgrind new file mode 100644 index 0000000000..52f0a50f57 --- /dev/null +++ b/gl/tests/malloca.valgrind @@ -0,0 +1,7 @@ +# Suppress a valgrind message about use of uninitialized memory in freea(). +# This use is OK because it provides only a speedup. +{ + freea + Memcheck:Cond + fun:freea +} diff --git a/gl/tests/minus-zero.h b/gl/tests/minus-zero.h new file mode 100644 index 0000000000..942978119e --- /dev/null +++ b/gl/tests/minus-zero.h @@ -0,0 +1,74 @@ +/* Macros for floating-point negative zero. + Copyright (C) 2010-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Keep in sync with m4/minus-zero.m4! */ + +#include <float.h> + + +/* minus_zerof represents the value -0.0f. */ + +/* HP cc on HP-UX 10.20 has a bug with the constant expression -0.0f. + ICC 10.0 has a bug when optimizing the expression -zero. + The expression -FLT_MIN * FLT_MIN does not work when cross-compiling + to PowerPC on MacOS X 10.5. */ +#if defined __hpux || defined __sgi || defined __ICC +static float +compute_minus_zerof (void) +{ + return -FLT_MIN * FLT_MIN; +} +# define minus_zerof compute_minus_zerof () +#else +float minus_zerof = -0.0f; +#endif + + +/* minus_zerod represents the value -0.0. */ + +/* HP cc on HP-UX 10.20 has a bug with the constant expression -0.0. + ICC 10.0 has a bug when optimizing the expression -zero. + The expression -DBL_MIN * DBL_MIN does not work when cross-compiling + to PowerPC on MacOS X 10.5. */ +#if defined __hpux || defined __sgi || defined __ICC +static double +compute_minus_zerod (void) +{ + return -DBL_MIN * DBL_MIN; +} +# define minus_zerod compute_minus_zerod () +#else +double minus_zerod = -0.0; +#endif + + +/* minus_zerol represents the value -0.0L. */ + +/* HP cc on HP-UX 10.20 has a bug with the constant expression -0.0L. + IRIX cc can't put -0.0L into .data, but can compute at runtime. + ICC 10.0 has a bug when optimizing the expression -zero. + The expression -LDBL_MIN * LDBL_MIN does not work when cross-compiling + to PowerPC on MacOS X 10.5. */ +#if defined __hpux || defined __sgi || defined __ICC +static long double +compute_minus_zerol (void) +{ + return -LDBL_MIN * LDBL_MIN; +} +# define minus_zerol compute_minus_zerol () +#else +long double minus_zerol = -0.0L; +#endif diff --git a/gl/tests/nan.h b/gl/tests/nan.h new file mode 100644 index 0000000000..5e1c0c3798 --- /dev/null +++ b/gl/tests/nan.h @@ -0,0 +1,60 @@ +/* Macros for not-a-number. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + + +/* NaNf () returns a 'float' not-a-number. */ + +/* The Compaq (ex-DEC) C 6.4 compiler chokes on the expression 0.0 / 0.0. */ +#ifdef __DECC +static float +NaNf () +{ + static float zero = 0.0f; + return zero / zero; +} +#else +# define NaNf() (0.0f / 0.0f) +#endif + + +/* NaNd () returns a 'double' not-a-number. */ + +/* The Compaq (ex-DEC) C 6.4 compiler chokes on the expression 0.0 / 0.0. */ +#ifdef __DECC +static double +NaNd () +{ + static double zero = 0.0; + return zero / zero; +} +#else +# define NaNd() (0.0 / 0.0) +#endif + + +/* NaNl () returns a 'long double' not-a-number. */ + +/* On Irix 6.5, gcc 3.4.3 can't compute compile-time NaN, and needs the + runtime type conversion. */ +#ifdef __sgi +static long double NaNl () +{ + double zero = 0.0; + return zero / zero; +} +#else +# define NaNl() (0.0L / 0.0L) +#endif diff --git a/gl/tests/open.c b/gl/tests/open.c new file mode 100644 index 0000000000..e60b619949 --- /dev/null +++ b/gl/tests/open.c @@ -0,0 +1,176 @@ +/* Open a descriptor to a file. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +/* Get the original definition of open. It might be defined as a macro. */ +#define __need_system_fcntl_h +#include <fcntl.h> +#undef __need_system_fcntl_h +#include <sys/types.h> + +static inline int +orig_open (const char *filename, int flags, mode_t mode) +{ + return open (filename, flags, mode); +} + +/* Specification. */ +#include <fcntl.h> + +#include <errno.h> +#include <stdarg.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#ifndef REPLACE_OPEN_DIRECTORY +# define REPLACE_OPEN_DIRECTORY 0 +#endif + +int +open (const char *filename, int flags, ...) +{ + mode_t mode; + int fd; + + mode = 0; + if (flags & O_CREAT) + { + va_list arg; + va_start (arg, flags); + + /* We have to use PROMOTED_MODE_T instead of mode_t, otherwise GCC 4 + creates crashing code when 'mode_t' is smaller than 'int'. */ + mode = va_arg (arg, PROMOTED_MODE_T); + + va_end (arg); + } + +#if GNULIB_defined_O_NONBLOCK + /* The only known platform that lacks O_NONBLOCK is mingw, but it + also lacks named pipes and Unix sockets, which are the only two + file types that require non-blocking handling in open(). + Therefore, it is safe to ignore O_NONBLOCK here. It is handy + that mingw also lacks openat(), so that is also covered here. */ + flags &= ~O_NONBLOCK; +#endif + +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + if (strcmp (filename, "/dev/null") == 0) + filename = "NUL"; +#endif + +#if OPEN_TRAILING_SLASH_BUG + /* If the filename ends in a slash and one of O_CREAT, O_WRONLY, O_RDWR + is specified, then fail. + Rationale: POSIX <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html> + says that + "A pathname that contains at least one non-slash character and that + ends with one or more trailing slashes shall be resolved as if a + single dot character ( '.' ) were appended to the pathname." + and + "The special filename dot shall refer to the directory specified by + its predecessor." + If the named file already exists as a directory, then + - if O_CREAT is specified, open() must fail because of the semantics + of O_CREAT, + - if O_WRONLY or O_RDWR is specified, open() must fail because POSIX + <http://www.opengroup.org/susv3/functions/open.html> says that it + fails with errno = EISDIR in this case. + If the named file does not exist or does not name a directory, then + - if O_CREAT is specified, open() must fail since open() cannot create + directories, + - if O_WRONLY or O_RDWR is specified, open() must fail because the + file does not contain a '.' directory. */ + if (flags & (O_CREAT | O_WRONLY | O_RDWR)) + { + size_t len = strlen (filename); + if (len > 0 && filename[len - 1] == '/') + { + errno = EISDIR; + return -1; + } + } +#endif + + fd = orig_open (filename, flags, mode); + +#if REPLACE_FCHDIR + /* Implementing fchdir and fdopendir requires the ability to open a + directory file descriptor. If open doesn't support that (as on + mingw), we use a dummy file that behaves the same as directories + on Linux (ie. always reports EOF on attempts to read()), and + override fstat() in fchdir.c to hide the fact that we have a + dummy. */ + if (REPLACE_OPEN_DIRECTORY && fd < 0 && errno == EACCES + && ((flags & O_ACCMODE) == O_RDONLY + || (O_SEARCH != O_RDONLY && (flags & O_ACCMODE) == O_SEARCH))) + { + struct stat statbuf; + if (stat (filename, &statbuf) == 0 && S_ISDIR (statbuf.st_mode)) + { + /* Maximum recursion depth of 1. */ + fd = open ("/dev/null", flags, mode); + if (0 <= fd) + fd = _gl_register_fd (fd, filename); + } + else + errno = EACCES; + } +#endif + +#if OPEN_TRAILING_SLASH_BUG + /* If the filename ends in a slash and fd does not refer to a directory, + then fail. + Rationale: POSIX <http://www.opengroup.org/susv3/basedefs/xbd_chap04.html> + says that + "A pathname that contains at least one non-slash character and that + ends with one or more trailing slashes shall be resolved as if a + single dot character ( '.' ) were appended to the pathname." + and + "The special filename dot shall refer to the directory specified by + its predecessor." + If the named file without the slash is not a directory, open() must fail + with ENOTDIR. */ + if (fd >= 0) + { + /* We know len is positive, since open did not fail with ENOENT. */ + size_t len = strlen (filename); + if (filename[len - 1] == '/') + { + struct stat statbuf; + + if (fstat (fd, &statbuf) >= 0 && !S_ISDIR (statbuf.st_mode)) + { + close (fd); + errno = ENOTDIR; + return -1; + } + } + } +#endif + +#if REPLACE_FCHDIR + if (!REPLACE_OPEN_DIRECTORY && 0 <= fd) + fd = _gl_register_fd (fd, filename); +#endif + + return fd; +} diff --git a/gl/tests/putenv.c b/gl/tests/putenv.c new file mode 100644 index 0000000000..68e5fec31b --- /dev/null +++ b/gl/tests/putenv.c @@ -0,0 +1,132 @@ +/* Copyright (C) 1991, 1994, 1997-1998, 2000, 2003-2011 Free Software + Foundation, Inc. + + NOTE: The canonical source of this file is maintained with the GNU C + Library. Bugs can be reported to bug-glibc@prep.ai.mit.edu. + + This program 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 3 of the License, or any + later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Specification. */ +#include <stdlib.h> + +#include <stddef.h> + +/* Include errno.h *after* sys/types.h to work around header problems + on AIX 3.2.5. */ +#include <errno.h> +#ifndef __set_errno +# define __set_errno(ev) ((errno) = (ev)) +#endif + +#include <string.h> +#include <unistd.h> + +#if HAVE_GNU_LD +# define environ __environ +#else +extern char **environ; +#endif + +#if _LIBC +/* This lock protects against simultaneous modifications of `environ'. */ +# include <bits/libc-lock.h> +__libc_lock_define_initialized (static, envlock) +# define LOCK __libc_lock_lock (envlock) +# define UNLOCK __libc_lock_unlock (envlock) +#else +# define LOCK +# define UNLOCK +#endif + +static int +_unsetenv (const char *name) +{ + size_t len; + char **ep; + + if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) + { + __set_errno (EINVAL); + return -1; + } + + len = strlen (name); + + LOCK; + + ep = environ; + while (*ep != NULL) + if (!strncmp (*ep, name, len) && (*ep)[len] == '=') + { + /* Found it. Remove this pointer by moving later ones back. */ + char **dp = ep; + + do + dp[0] = dp[1]; + while (*dp++); + /* Continue the loop in case NAME appears again. */ + } + else + ++ep; + + UNLOCK; + + return 0; +} + + +/* Put STRING, which is of the form "NAME=VALUE", in the environment. + If STRING contains no `=', then remove STRING from the environment. */ +int +putenv (char *string) +{ + const char *const name_end = strchr (string, '='); + register size_t size; + register char **ep; + + if (name_end == NULL) + { + /* Remove the variable from the environment. */ + return _unsetenv (string); + } + + size = 0; + for (ep = environ; *ep != NULL; ++ep) + if (!strncmp (*ep, string, name_end - string) && + (*ep)[name_end - string] == '=') + break; + else + ++size; + + if (*ep == NULL) + { + static char **last_environ = NULL; + char **new_environ = (char **) malloc ((size + 2) * sizeof (char *)); + if (new_environ == NULL) + return -1; + (void) memcpy ((void *) new_environ, (void *) environ, + size * sizeof (char *)); + new_environ[size] = (char *) string; + new_environ[size + 1] = NULL; + free (last_environ); + last_environ = new_environ; + environ = new_environ; + } + else + *ep = string; + + return 0; +} diff --git a/gl/tests/same-inode.h b/gl/tests/same-inode.h new file mode 100644 index 0000000000..d434b94369 --- /dev/null +++ b/gl/tests/same-inode.h @@ -0,0 +1,25 @@ +/* Determine whether two stat buffers refer to the same file. + + Copyright (C) 2006, 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#ifndef SAME_INODE_H +# define SAME_INODE_H 1 + +# define SAME_INODE(Stat_buf_1, Stat_buf_2) \ + ((Stat_buf_1).st_ino == (Stat_buf_2).st_ino \ + && (Stat_buf_1).st_dev == (Stat_buf_2).st_dev) + +#endif diff --git a/gl/tests/setenv.c b/gl/tests/setenv.c new file mode 100644 index 0000000000..0a5f67dd04 --- /dev/null +++ b/gl/tests/setenv.c @@ -0,0 +1,390 @@ +/* Copyright (C) 1992, 1995-2003, 2005-2011 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#if !_LIBC +# define _GL_USE_STDLIB_ALLOC 1 +# include <config.h> +#endif + +/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc + optimizes away the name == NULL test below. */ +#define _GL_ARG_NONNULL(params) + +#include <alloca.h> + +/* Specification. */ +#include <stdlib.h> + +#include <errno.h> +#ifndef __set_errno +# define __set_errno(ev) ((errno) = (ev)) +#endif + +#include <string.h> +#if _LIBC || HAVE_UNISTD_H +# include <unistd.h> +#endif + +#if !_LIBC +# include "malloca.h" +#endif + +#if _LIBC || !HAVE_SETENV + +#if !_LIBC +# define __environ environ +#endif + +#if _LIBC +/* This lock protects against simultaneous modifications of `environ'. */ +# include <bits/libc-lock.h> +__libc_lock_define_initialized (static, envlock) +# define LOCK __libc_lock_lock (envlock) +# define UNLOCK __libc_lock_unlock (envlock) +#else +# define LOCK +# define UNLOCK +#endif + +/* In the GNU C library we must keep the namespace clean. */ +#ifdef _LIBC +# define setenv __setenv +# define clearenv __clearenv +# define tfind __tfind +# define tsearch __tsearch +#endif + +/* In the GNU C library implementation we try to be more clever and + allow arbitrarily many changes of the environment given that the used + values are from a small set. Outside glibc this will eat up all + memory after a while. */ +#if defined _LIBC || (defined HAVE_SEARCH_H && defined HAVE_TSEARCH \ + && defined __GNUC__) +# define USE_TSEARCH 1 +# include <search.h> +typedef int (*compar_fn_t) (const void *, const void *); + +/* This is a pointer to the root of the search tree with the known + values. */ +static void *known_values; + +# define KNOWN_VALUE(Str) \ + ({ \ + void *value = tfind (Str, &known_values, (compar_fn_t) strcmp); \ + value != NULL ? *(char **) value : NULL; \ + }) +# define STORE_VALUE(Str) \ + tsearch (Str, &known_values, (compar_fn_t) strcmp) + +#else +# undef USE_TSEARCH + +# define KNOWN_VALUE(Str) NULL +# define STORE_VALUE(Str) do { } while (0) + +#endif + + +/* If this variable is not a null pointer we allocated the current + environment. */ +static char **last_environ; + + +/* This function is used by `setenv' and `putenv'. The difference between + the two functions is that for the former must create a new string which + is then placed in the environment, while the argument of `putenv' + must be used directly. This is all complicated by the fact that we try + to reuse values once generated for a `setenv' call since we can never + free the strings. */ +int +__add_to_environ (const char *name, const char *value, const char *combined, + int replace) +{ + char **ep; + size_t size; + const size_t namelen = strlen (name); + const size_t vallen = value != NULL ? strlen (value) + 1 : 0; + + LOCK; + + /* We have to get the pointer now that we have the lock and not earlier + since another thread might have created a new environment. */ + ep = __environ; + + size = 0; + if (ep != NULL) + { + for (; *ep != NULL; ++ep) + if (!strncmp (*ep, name, namelen) && (*ep)[namelen] == '=') + break; + else + ++size; + } + + if (ep == NULL || *ep == NULL) + { + char **new_environ; +#ifdef USE_TSEARCH + char *new_value; +#endif + + /* We allocated this space; we can extend it. */ + new_environ = + (char **) (last_environ == NULL + ? malloc ((size + 2) * sizeof (char *)) + : realloc (last_environ, (size + 2) * sizeof (char *))); + if (new_environ == NULL) + { + /* It's easier to set errno to ENOMEM than to rely on the + 'malloc-posix' and 'realloc-posix' gnulib modules. */ + __set_errno (ENOMEM); + UNLOCK; + return -1; + } + + /* If the whole entry is given add it. */ + if (combined != NULL) + /* We must not add the string to the search tree since it belongs + to the user. */ + new_environ[size] = (char *) combined; + else + { + /* See whether the value is already known. */ +#ifdef USE_TSEARCH +# ifdef _LIBC + new_value = (char *) alloca (namelen + 1 + vallen); + __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), + value, vallen); +# else + new_value = (char *) malloca (namelen + 1 + vallen); + if (new_value == NULL) + { + __set_errno (ENOMEM); + UNLOCK; + return -1; + } + memcpy (new_value, name, namelen); + new_value[namelen] = '='; + memcpy (&new_value[namelen + 1], value, vallen); +# endif + + new_environ[size] = KNOWN_VALUE (new_value); + if (new_environ[size] == NULL) +#endif + { + new_environ[size] = (char *) malloc (namelen + 1 + vallen); + if (new_environ[size] == NULL) + { +#if defined USE_TSEARCH && !defined _LIBC + freea (new_value); +#endif + __set_errno (ENOMEM); + UNLOCK; + return -1; + } + +#ifdef USE_TSEARCH + memcpy (new_environ[size], new_value, namelen + 1 + vallen); +#else + memcpy (new_environ[size], name, namelen); + new_environ[size][namelen] = '='; + memcpy (&new_environ[size][namelen + 1], value, vallen); +#endif + /* And save the value now. We cannot do this when we remove + the string since then we cannot decide whether it is a + user string or not. */ + STORE_VALUE (new_environ[size]); + } +#if defined USE_TSEARCH && !defined _LIBC + freea (new_value); +#endif + } + + if (__environ != last_environ) + memcpy ((char *) new_environ, (char *) __environ, + size * sizeof (char *)); + + new_environ[size + 1] = NULL; + + last_environ = __environ = new_environ; + } + else if (replace) + { + char *np; + + /* Use the user string if given. */ + if (combined != NULL) + np = (char *) combined; + else + { +#ifdef USE_TSEARCH + char *new_value; +# ifdef _LIBC + new_value = alloca (namelen + 1 + vallen); + __mempcpy (__mempcpy (__mempcpy (new_value, name, namelen), "=", 1), + value, vallen); +# else + new_value = malloca (namelen + 1 + vallen); + if (new_value == NULL) + { + __set_errno (ENOMEM); + UNLOCK; + return -1; + } + memcpy (new_value, name, namelen); + new_value[namelen] = '='; + memcpy (&new_value[namelen + 1], value, vallen); +# endif + + np = KNOWN_VALUE (new_value); + if (np == NULL) +#endif + { + np = (char *) malloc (namelen + 1 + vallen); + if (np == NULL) + { +#if defined USE_TSEARCH && !defined _LIBC + freea (new_value); +#endif + __set_errno (ENOMEM); + UNLOCK; + return -1; + } + +#ifdef USE_TSEARCH + memcpy (np, new_value, namelen + 1 + vallen); +#else + memcpy (np, name, namelen); + np[namelen] = '='; + memcpy (&np[namelen + 1], value, vallen); +#endif + /* And remember the value. */ + STORE_VALUE (np); + } +#if defined USE_TSEARCH && !defined _LIBC + freea (new_value); +#endif + } + + *ep = np; + } + + UNLOCK; + + return 0; +} + +int +setenv (const char *name, const char *value, int replace) +{ + if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) + { + __set_errno (EINVAL); + return -1; + } + + return __add_to_environ (name, value, NULL, replace); +} + +/* The `clearenv' was planned to be added to POSIX.1 but probably + never made it. Nevertheless the POSIX.9 standard (POSIX bindings + for Fortran 77) requires this function. */ +int +clearenv (void) +{ + LOCK; + + if (__environ == last_environ && __environ != NULL) + { + /* We allocated this environment so we can free it. */ + free (__environ); + last_environ = NULL; + } + + /* Clear the environment pointer removes the whole environment. */ + __environ = NULL; + + UNLOCK; + + return 0; +} + +#ifdef _LIBC +static void +free_mem (void) +{ + /* Remove all traces. */ + clearenv (); + + /* Now remove the search tree. */ + __tdestroy (known_values, free); + known_values = NULL; +} +text_set_element (__libc_subfreeres, free_mem); + + +# undef setenv +# undef clearenv +weak_alias (__setenv, setenv) +weak_alias (__clearenv, clearenv) +#endif + +#endif /* _LIBC || !HAVE_SETENV */ + +/* The rest of this file is called into use when replacing an existing + but buggy setenv. Known bugs include failure to diagnose invalid + name, and consuming a leading '=' from value. */ +#if HAVE_SETENV + +# undef setenv +# if !HAVE_DECL_SETENV +extern int setenv (const char *, const char *, int); +# endif +# define STREQ(a, b) (strcmp (a, b) == 0) + +int +rpl_setenv (const char *name, const char *value, int replace) +{ + int result; + if (!name || !*name || strchr (name, '=')) + { + errno = EINVAL; + return -1; + } + /* Call the real setenv even if replace is 0, in case implementation + has underlying data to update, such as when environ changes. */ + result = setenv (name, value, replace); + if (result == 0 && replace && *value == '=') + { + char *tmp = getenv (name); + if (!STREQ (tmp, value)) + { + int saved_errno; + size_t len = strlen (value); + tmp = malloca (len + 2); + /* Since leading '=' is eaten, double it up. */ + *tmp = '='; + memcpy (tmp + 1, value, len + 1); + result = setenv (name, tmp, replace); + saved_errno = errno; + freea (tmp); + errno = saved_errno; + } + } + return result; +} + +#endif /* HAVE_SETENV */ diff --git a/gl/tests/stat.c b/gl/tests/stat.c new file mode 100644 index 0000000000..f07370dd06 --- /dev/null +++ b/gl/tests/stat.c @@ -0,0 +1,113 @@ +/* Work around platform bugs in stat. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* written by Eric Blake */ + +#include <config.h> + +/* Get the original definition of stat. It might be defined as a macro. */ +#define __need_system_sys_stat_h +#include <sys/types.h> +#include <sys/stat.h> +#undef __need_system_sys_stat_h + +static inline int +orig_stat (const char *filename, struct stat *buf) +{ + return stat (filename, buf); +} + +/* Specification. */ +#include <sys/stat.h> + +#include <errno.h> +#include <limits.h> +#include <stdbool.h> +#include <string.h> +#include "dosname.h" +#include "verify.h" + +/* Store information about NAME into ST. Work around bugs with + trailing slashes. Mingw has other bugs (such as st_ino always + being 0 on success) which this wrapper does not work around. But + at least this implementation provides the ability to emulate fchdir + correctly. */ + +int +rpl_stat (char const *name, struct stat *st) +{ + int result = orig_stat (name, st); +#if REPLACE_FUNC_STAT_FILE + /* Solaris 9 mistakenly succeeds when given a non-directory with a + trailing slash. */ + if (result == 0 && !S_ISDIR (st->st_mode)) + { + size_t len = strlen (name); + if (ISSLASH (name[len - 1])) + { + errno = ENOTDIR; + return -1; + } + } +#endif /* REPLACE_FUNC_STAT_FILE */ +#if REPLACE_FUNC_STAT_DIR + /* The only known systems where REPLACE_FUNC_STAT_DIR is needed also + have a constant PATH_MAX. */ +# ifndef PATH_MAX +# error "Please port this replacement to your platform" +# endif + + if (result == -1 && errno == ENOENT) + { + /* Due to mingw's oddities, there are some directories (like + c:\) where stat() only succeeds with a trailing slash, and + other directories (like c:\windows) where stat() only + succeeds without a trailing slash. But we want the two to be + synonymous, since chdir() manages either style. Likewise, Mingw also + reports ENOENT for names longer than PATH_MAX, when we want + ENAMETOOLONG, and for stat("file/"), when we want ENOTDIR. + Fortunately, mingw PATH_MAX is small enough for stack + allocation. */ + char fixed_name[PATH_MAX + 1] = {0}; + size_t len = strlen (name); + bool check_dir = false; + verify (PATH_MAX <= 4096); + if (PATH_MAX <= len) + errno = ENAMETOOLONG; + else if (len) + { + strcpy (fixed_name, name); + if (ISSLASH (fixed_name[len - 1])) + { + check_dir = true; + while (len && ISSLASH (fixed_name[len - 1])) + fixed_name[--len] = '\0'; + if (!len) + fixed_name[0] = '/'; + } + else + fixed_name[len++] = '/'; + result = orig_stat (fixed_name, st); + if (result == 0 && check_dir && !S_ISDIR (st->st_mode)) + { + result = -1; + errno = ENOTDIR; + } + } + } +#endif /* REPLACE_FUNC_STAT_DIR */ + return result; +} diff --git a/gl/tests/symlink.c b/gl/tests/symlink.c new file mode 100644 index 0000000000..2896cc9655 --- /dev/null +++ b/gl/tests/symlink.c @@ -0,0 +1,57 @@ +/* Stub for symlink(). + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Specification. */ +#include <unistd.h> + +#include <errno.h> +#include <string.h> +#include <sys/stat.h> + + +#if HAVE_SYMLINK + +# undef symlink + +/* Create a symlink, but reject trailing slash. */ +int +rpl_symlink (char const *contents, char const *name) +{ + size_t len = strlen (name); + if (len && name[len - 1] == '/') + { + struct stat st; + if (lstat (name, &st) == 0) + errno = EEXIST; + return -1; + } + return symlink (contents, name); +} + +#else /* !HAVE_SYMLINK */ + +/* The system does not support symlinks. */ +int +symlink (char const *contents _GL_UNUSED, + char const *name _GL_UNUSED) +{ + errno = ENOSYS; + return -1; +} + +#endif /* !HAVE_SYMLINK */ diff --git a/gl/tests/test-argp-2.sh b/gl/tests/test-argp-2.sh new file mode 100755 index 0000000000..20e0d9e8e5 --- /dev/null +++ b/gl/tests/test-argp-2.sh @@ -0,0 +1,113 @@ +#! /bin/sh +# Test suite for argp. +# Copyright (C) 2006-2011 Free Software Foundation, Inc. +# This file is part of the GNUlib Library. +# +# This program 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 3 of the License, or +# (at your option) any later version. +# +# 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, see <http://www.gnu.org/licenses/>. */ + +TMP=argp.$$ + +unset ARGP_HELP_FMT +ERR=0 + +func_compare() { +# If argp was compiled without base_name, it will display full program name. +# If run on mingw, it will display the program name with a .exe suffix. + sed '1{ + s,: [^ ]*/test-argp,: test-argp, + s,: test-argp\.exe,: test-argp, + }' | LC_ALL=C tr -d '\r' | diff -c $TMP - +} + +#### +# Test --usage output +cat > $TMP <<EOT +Usage: test-argp [-tvCSOlp?V] [-f FILE] [-r FILE] [-o[ARG]] [--test] + [--file=FILE] [--input=FILE] [--read=FILE] [--verbose] [--cantiga] + [--sonet] [--option] [--optional[=ARG]] [--limerick] [--poem] + [--help] [--usage] [--version] ARGS... +EOT + +./test-argp$EXEEXT --usage | func_compare || ERR=1 + +#### +# Test working usage-indent format + +cat > $TMP <<EOT +Usage: test-argp [-tvCSOlp?V] [-f FILE] [-r FILE] [-o[ARG]] [--test] +[--file=FILE] [--input=FILE] [--read=FILE] [--verbose] [--cantiga] [--sonet] +[--option] [--optional[=ARG]] [--limerick] [--poem] [--help] [--usage] +[--version] ARGS... +EOT + +ARGP_HELP_FMT='usage-indent=0' ./test-argp$EXEEXT --usage | func_compare || ERR=1 + +#### +# Test --help output +cat >$TMP <<EOT +Usage: test-argp [OPTION...] ARGS... +documentation string + + Main options + -t, --test + + Option Group 1 + -f, -r, --file=FILE, --input=FILE, --read=FILE + Option with a mandatory argument + -v, --verbose Simple option without arguments + + Option Group 1.1 + -C, --cantiga create a cantiga + -S, --sonet create a sonet + + Option Group 2 + -O, --option An option + + -o, --optional[=ARG] Option with an optional argument. ARG is one of + the following: + + many many units + one one unit + two two units + + Option Group 2.1 + -l, --limerick create a limerick + -p, --poem create a poem + + -?, --help give this help list + --usage give a short usage message + -V, --version print program version + +Mandatory or optional arguments to long options are also mandatory or optional +for any corresponding short options. + +Report bugs to <>. +EOT + +# Compare --help output, but filter out any bug-reporting email address. +./test-argp$EXEEXT --help \ + | sed 's/^\(Report bugs to \)<[^>]*>.$/\1<>./' | func_compare || ERR=1 + +#### +# Test ambiguous option handling + +./test-argp$EXEEXT --optio 2>/dev/null && ERR=1 + +#### +# Run built-in tests +./test-argp$EXEEXT || ERR=1 + +rm $TMP + +exit $ERR diff --git a/gl/tests/test-argp.c b/gl/tests/test-argp.c new file mode 100644 index 0000000000..8fab727c9a --- /dev/null +++ b/gl/tests/test-argp.c @@ -0,0 +1,491 @@ +/* Test suite for argp. + Copyright (C) 2006-2007, 2009-2011 Free Software Foundation, Inc. + This file is part of the GNUlib Library. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include "argp.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#if HAVE_STRINGS_H +# include <strings.h> +#endif +#include "progname.h" + +struct test_args +{ + int test; + int verbose; + char *file; + int read; + char *hidden; + int opt; + char *optional; + int optional_set; + int group_2_1_option; + int group_1_1_option; +}; + +static struct argp_option group1_option[] = { + { NULL, 0, NULL, 0, "Option Group 1", 0 }, + { "verbose", 'v', NULL, 0, "Simple option without arguments", 1 }, + { "file", 'f', "FILE", 0, "Option with a mandatory argument", 1 }, + { "input", 0, NULL, OPTION_ALIAS, NULL, 1 }, + { "read", 'r', NULL, OPTION_ALIAS, NULL, 1 }, + { "hidden", 'H', "FILE", OPTION_HIDDEN, "Hidden option", 1 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +static error_t +group1_parser (int key, char *arg, struct argp_state *state) +{ + struct test_args *args = state->input; + + switch (key) + { + case 'v': + args->verbose++; + break; + + case 'r': + args->read = 1; + /* fall through */ + case 'f': + args->file = arg; + break; + + case 'H': + args->hidden = arg; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +struct argp group1_argp = { + group1_option, + group1_parser +}; + +struct argp_child group1_child = { + &group1_argp, + 0, + "", + 1 +}; + + +static struct argp_option group1_1_option[] = { + { NULL, 0, NULL, 0, "Option Group 1.1", 0 }, + { "cantiga", 'C', NULL, 0, "create a cantiga" }, + { "sonet", 'S', NULL, 0, "create a sonet" }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +static error_t +group1_1_parser (int key, char *arg, struct argp_state *state) +{ + struct test_args *args = state->input; + switch (key) + { + case 'C': + case 'S': + args->group_1_1_option = key; + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +struct argp group1_1_argp = { + group1_1_option, + group1_1_parser +}; + +struct argp_child group1_1_child = { + &group1_1_argp, + 0, + "", + 2 +}; + + +static struct argp_option group2_option[] = { + { NULL, 0, NULL, 0, "Option Group 2", 0 }, + { "option", 'O', NULL, 0, "An option", 1 }, + { "optional", 'o', "ARG", OPTION_ARG_OPTIONAL, + "Option with an optional argument. ARG is one of the following:", 2 }, + { "one", 0, NULL, OPTION_DOC | OPTION_NO_TRANS, "one unit", 3 }, + { "two", 0, NULL, OPTION_DOC | OPTION_NO_TRANS, "two units", 3 }, + { "many", 0, NULL, OPTION_DOC | OPTION_NO_TRANS, "many units", 3 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +static error_t +group2_parser (int key, char *arg, struct argp_state *state) +{ + struct test_args *args = state->input; + + switch (key) + { + case 'O': + args->opt = 1; + break; + + case 'o': + args->optional_set = 1; + args->optional = arg; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +struct argp group2_argp = { + group2_option, + group2_parser +}; + +struct argp_child group2_child = { + &group2_argp, + 0, + "", + 2 +}; + + +static struct argp_option group2_1_option[] = { + { NULL, 0, NULL, 0, "Option Group 2.1", 0 }, + { "poem", 'p', NULL, 0, "create a poem" }, + { "limerick", 'l', NULL, 0, "create a limerick" }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +static error_t +group2_1_parser (int key, char *arg, struct argp_state *state) +{ + struct test_args *args = state->input; + switch (key) + { + case 'p': + case 'e': + args->group_2_1_option = key; + break; + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +struct argp group2_1_argp = { + group2_1_option, + group2_1_parser +}; + +struct argp_child group2_1_child = { + &group2_1_argp, + 0, + "", + 2 +}; + + +static struct argp_option main_options[] = { + { NULL, 0, NULL, 0, "Main options", 0 }, + { "test", 't', NULL, 0, NULL, 1 }, + { NULL, 0, NULL, 0, NULL, 0 } +}; + +static error_t +parse_opt (int key, char *arg, struct argp_state *state) +{ + struct test_args *args = state->input; + int i; + + switch (key) + { + case ARGP_KEY_INIT: + for (i = 0; state->root_argp->children[i].argp; i++) + state->child_inputs[i] = args; + break; + + case 't': + args->test = 1; + break; + + default: + return ARGP_ERR_UNKNOWN; + } + return 0; +} + +const char *argp_program_version = "test_argp (" PACKAGE_NAME ") " VERSION; +const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">"; +static char doc[] = "documentation string"; + +struct argp test_argp = { + main_options, + parse_opt, + "ARGS...", + doc, + NULL, + NULL, + NULL +}; + +#define NARGS(a) (sizeof(a) / sizeof((a)[0]) - 1) +#define ARGV0 "test-argp" +#define init_args(a) memset (&(a), 0, sizeof (a)); + +#define INIT_TEST_COMMON(n) \ + int argc = NARGS (argv); \ + struct test_args test_args; \ + init_args (test_args); \ + test_number = n; + +#define INIT_TEST1(n, arg1) \ + char *argv[] = { ARGV0, arg1, NULL }; \ + INIT_TEST_COMMON (n) + +#define INIT_TEST2(n, arg1, arg2) \ + char *argv[] = { ARGV0, arg1, arg2, NULL }; \ + INIT_TEST_COMMON (n) + +#define INIT_TEST3(n, arg1, arg2, arg3) \ + char *argv[] = { ARGV0, arg1, arg2, arg3, NULL }; \ + INIT_TEST_COMMON (n) + +int test_number; +unsigned failure_count = 0; + +void +fail (const char *msg) +{ + fprintf (stderr, "Test %d: %s\n", test_number, msg); + failure_count++; +} + +void +test1 (struct argp *argp) +{ + INIT_TEST1 (1, "--test"); + if (argp_parse (argp, argc, argv, 0, NULL, &test_args)) + fail ("argp_parse failed"); + else if (test_args.test != 1) + fail ("option not processed"); +} + +void +test2 (struct argp *argp) +{ + INIT_TEST1 (2, "-t"); + if (argp_parse (argp, argc, argv, 0, NULL, &test_args)) + fail ("argp_parse failed"); + else if (test_args.test != 1) + fail ("option not processed"); +} + +void +test_file (struct argp *argp, int argc, char **argv, struct test_args *args) +{ + if (argp_parse (argp, argc, argv, 0, NULL, args)) + fail ("argp_parse failed"); + else if (!args->file) + fail ("option not processed"); + else if (strcmp (args->file, "FILE")) + fail ("option processed incorrectly"); +} + +void +test3 (struct argp *argp) +{ + INIT_TEST1 (3, "--file=FILE"); + test_file (argp, argc, argv, &test_args); +} + +void +test4 (struct argp *argp) +{ + INIT_TEST2 (4, "--file", "FILE"); + test_file (argp, argc, argv, &test_args); +} + +void +test5 (struct argp *argp) +{ + INIT_TEST1 (5, "--input=FILE"); + test_file (argp, argc, argv, &test_args); +} + +void +test6 (struct argp *argp) +{ + INIT_TEST2 (6, "--input", "FILE"); + test_file (argp, argc, argv, &test_args); +} + +void +test_optional (struct argp *argp, int argc, char **argv, + struct test_args *args, const char *val, const char *a) +{ + int index; + if (argp_parse (argp, argc, argv, 0, &index, args)) + fail ("argp_parse failed"); + else if (!args->optional_set) + fail ("option not processed"); + + if (!val) + { + if (args->optional) + fail ("option processed incorrectly"); + } + else if (strcmp (args->optional, val)) + fail ("option processed incorrectly"); + + if (a) + { + if (index == argc) + fail ("expected command line argument not found"); + else if (strcmp (argv[index], a)) + fail ("expected command line argument does not match"); + } +} + +void +test7 (struct argp *argp) +{ + INIT_TEST1 (7, "-oARG"); + test_optional (argp, argc, argv, &test_args, "ARG", NULL); +} + +void +test8 (struct argp *argp) +{ + INIT_TEST2 (8, "-o", "ARG"); + test_optional (argp, argc, argv, &test_args, NULL, "ARG"); +} + +void +test9 (struct argp *argp) +{ + INIT_TEST1 (9, "--optional=ARG"); + test_optional (argp, argc, argv, &test_args, "ARG", NULL); +} + +void +test10 (struct argp *argp) +{ + INIT_TEST2 (10, "--optional", "ARG"); + test_optional (argp, argc, argv, &test_args, NULL, "ARG"); +} + +void +test11 (struct argp *argp) +{ + INIT_TEST1 (11, "--optiona=ARG"); + test_optional (argp, argc, argv, &test_args, "ARG", NULL); +} + +void +test12 (struct argp *argp) +{ + INIT_TEST3 (12, "--option", "--optional=OPT", "FILE"); + test_optional (argp, argc, argv, &test_args, "OPT", "FILE"); +} + +void +test13 (struct argp *argp) +{ + INIT_TEST1 (1, "--cantiga"); + if (argp_parse (argp, argc, argv, 0, NULL, &test_args)) + fail ("argp_parse failed"); + else if (test_args.group_1_1_option != 'C') + fail ("option not processed"); +} + +void +test14 (struct argp *argp) +{ + INIT_TEST1 (1, "--limerick"); + if (argp_parse (argp, argc, argv, 0, NULL, &test_args)) + fail ("argp_parse failed"); + else if (test_args.group_2_1_option != 'l') + fail ("option not processed"); +} + +void +test15 (struct argp *argp) +{ + INIT_TEST2 (1, "-r", "FILE"); + test_file (argp, argc, argv, &test_args); + if (!test_args.read) + fail ("short alias not recognized properly"); +} + + +typedef void (*test_fp) (struct argp *argp); + +test_fp test_fun[] = { + test1, test2, test3, test4, + test5, test6, test7, test8, + test9, test10, test11, test12, + test13, test14, test15, + NULL +}; + +int +main (int argc, char **argv) +{ + struct argp_child argp_children[3], group1_children[2], group2_children[2]; + test_fp *fun; + + set_program_name (argv[0]); + + group1_children[0] = group1_1_child; + group1_children[1].argp = NULL; + group1_argp.children = group1_children; + + group2_children[0] = group2_1_child; + group2_children[1].argp = NULL; + group2_argp.children = group2_children; + + argp_children[0] = group1_child; + argp_children[1] = group2_child; + argp_children[2].argp = NULL; + test_argp.children = argp_children; + + if (argc > 0) + { + struct test_args test_args; + init_args (test_args); + return argp_parse (&test_argp, argc, argv, 0, NULL, &test_args); + } + + for (fun = test_fun; *fun; fun++) + (*fun) (&test_argp); + + if (failure_count) + return 1; + + return 0; +} diff --git a/gl/tests/test-dirent.c b/gl/tests/test-dirent.c new file mode 100644 index 0000000000..212644abf6 --- /dev/null +++ b/gl/tests/test-dirent.c @@ -0,0 +1,32 @@ +/* Test of <dirent.h> substitute. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <ebb9@byu.net>, 2009. */ + +#include <config.h> + +#include <dirent.h> + +/* Check for existence of required types. */ +static DIR *dir _GL_UNUSED; +static struct dirent d; +static ino_t i; + +int +main (void) +{ + return d.d_name[0] + i; +} diff --git a/gl/tests/test-dup2.c b/gl/tests/test-dup2.c new file mode 100644 index 0000000000..e2ad88bcca --- /dev/null +++ b/gl/tests/test-dup2.c @@ -0,0 +1,198 @@ +/* Test duplicating file descriptors. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <ebb9@byu.net>, 2009. */ + +#include <config.h> + +#include <unistd.h> + +#include "signature.h" +SIGNATURE_CHECK (dup2, int, (int, int)); + +#include <errno.h> +#include <fcntl.h> + +#include "binary-io.h" + +#if GNULIB_TEST_CLOEXEC +# include "cloexec.h" +#endif + +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +/* Get declarations of the Win32 API functions. */ +# define WIN32_LEAN_AND_MEAN +# include <windows.h> +#endif + +#include "macros.h" + +/* Return non-zero if FD is open. */ +static int +is_open (int fd) +{ +#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + /* On Win32, the initial state of unassigned standard file + descriptors is that they are open but point to an + INVALID_HANDLE_VALUE, and there is no fcntl. */ + return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE; +#else +# ifndef F_GETFL +# error Please port fcntl to your platform +# endif + return 0 <= fcntl (fd, F_GETFL); +#endif +} + +#if GNULIB_TEST_CLOEXEC +/* Return non-zero if FD is open and inheritable across exec/spawn. */ +static int +is_inheritable (int fd) +{ +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + /* On Win32, the initial state of unassigned standard file + descriptors is that they are open but point to an + INVALID_HANDLE_VALUE, and there is no fcntl. */ + HANDLE h = (HANDLE) _get_osfhandle (fd); + DWORD flags; + if (h == INVALID_HANDLE_VALUE || GetHandleInformation (h, &flags) == 0) + return 0; + return (flags & HANDLE_FLAG_INHERIT) != 0; +# else +# ifndef F_GETFD +# error Please port fcntl to your platform +# endif + int i = fcntl (fd, F_GETFD); + return 0 <= i && (i & FD_CLOEXEC) == 0; +# endif +} +#endif /* GNULIB_TEST_CLOEXEC */ + +#if !O_BINARY +# define setmode(f,m) zero () +static int zero (void) { return 0; } +#endif + +/* Return non-zero if FD is open in the given MODE, which is either + O_TEXT or O_BINARY. */ +static int +is_mode (int fd, int mode) +{ + int value = setmode (fd, O_BINARY); + setmode (fd, value); + return mode == value; +} + +int +main (void) +{ + const char *file = "test-dup2.tmp"; + char buffer[1]; + int fd = open (file, O_CREAT | O_TRUNC | O_RDWR, 0600); + + /* Assume std descriptors were provided by invoker. */ + ASSERT (STDERR_FILENO < fd); + ASSERT (is_open (fd)); + /* Ignore any other fd's leaked into this process. */ + close (fd + 1); + close (fd + 2); + ASSERT (!is_open (fd + 1)); + ASSERT (!is_open (fd + 2)); + + /* Assigning to self must be a no-op. */ + ASSERT (dup2 (fd, fd) == fd); + ASSERT (is_open (fd)); + + /* The source must be valid. */ + errno = 0; + ASSERT (dup2 (-1, fd) == -1); + ASSERT (errno == EBADF); + errno = 0; + ASSERT (dup2 (AT_FDCWD, fd) == -1); + ASSERT (errno == EBADF); + ASSERT (is_open (fd)); + + /* If the source is not open, then the destination is unaffected. */ + errno = 0; + ASSERT (dup2 (fd + 1, fd + 1) == -1); + ASSERT (errno == EBADF); + ASSERT (!is_open (fd + 1)); + errno = 0; + ASSERT (dup2 (fd + 1, fd) == -1); + ASSERT (errno == EBADF); + ASSERT (is_open (fd)); + + /* The destination must be valid. */ + errno = 0; + ASSERT (dup2 (fd, -2) == -1); + ASSERT (errno == EBADF); + errno = 0; + ASSERT (dup2 (fd, 10000000) == -1); + ASSERT (errno == EBADF); + + /* Using dup2 can skip fds. */ + ASSERT (dup2 (fd, fd + 2) == fd + 2); + ASSERT (is_open (fd)); + ASSERT (!is_open (fd + 1)); + ASSERT (is_open (fd + 2)); + + /* Verify that dup2 closes the previous occupant of a fd. */ + ASSERT (open ("/dev/null", O_WRONLY, 0600) == fd + 1); + ASSERT (dup2 (fd + 1, fd) == fd); + ASSERT (close (fd + 1) == 0); + ASSERT (write (fd, "1", 1) == 1); + ASSERT (dup2 (fd + 2, fd) == fd); + ASSERT (lseek (fd, 0, SEEK_END) == 0); + ASSERT (write (fd + 2, "2", 1) == 1); + ASSERT (lseek (fd, 0, SEEK_SET) == 0); + ASSERT (read (fd, buffer, 1) == 1); + ASSERT (*buffer == '2'); + +#if GNULIB_TEST_CLOEXEC + /* Any new fd created by dup2 must not be cloexec. */ + ASSERT (close (fd + 2) == 0); + ASSERT (dup_cloexec (fd) == fd + 1); + ASSERT (!is_inheritable (fd + 1)); + ASSERT (dup2 (fd + 1, fd + 1) == fd + 1); + ASSERT (!is_inheritable (fd + 1)); + ASSERT (dup2 (fd + 1, fd + 2) == fd + 2); + ASSERT (!is_inheritable (fd + 1)); + ASSERT (is_inheritable (fd + 2)); + errno = 0; + ASSERT (dup2 (fd + 1, -1) == -1); + ASSERT (errno == EBADF); + ASSERT (!is_inheritable (fd + 1)); +#endif + + /* On systems that distinguish between text and binary mode, dup2 + reuses the mode of the source. */ + setmode (fd, O_BINARY); + ASSERT (is_mode (fd, O_BINARY)); + ASSERT (dup2 (fd, fd + 1) == fd + 1); + ASSERT (is_mode (fd + 1, O_BINARY)); + setmode (fd, O_TEXT); + ASSERT (is_mode (fd, O_TEXT)); + ASSERT (dup2 (fd, fd + 1) == fd + 1); + ASSERT (is_mode (fd + 1, O_TEXT)); + + /* Clean up. */ + ASSERT (close (fd + 2) == 0); + ASSERT (close (fd + 1) == 0); + ASSERT (close (fd) == 0); + ASSERT (unlink (file) == 0); + + return 0; +} diff --git a/gl/tests/test-environ.c b/gl/tests/test-environ.c new file mode 100644 index 0000000000..11df789611 --- /dev/null +++ b/gl/tests/test-environ.c @@ -0,0 +1,44 @@ +/* Test of environ variable. + Copyright (C) 2008-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2008. */ + +#include <config.h> + +#include <unistd.h> + +#include <string.h> + +int +main () +{ + /* The environment variables that are set even in the weirdest situations + are HOME and PATH. + POSIX says that HOME is initialized by the system, and that PATH may be + unset. But in practice it's more frequent to see HOME unset and PATH + set. So we test the presence of PATH. */ + char **remaining_variables = environ; + char *string; + + for (; (string = *remaining_variables) != NULL; remaining_variables++) + { + if (strncmp (string, "PATH=", 5) == 0) + /* Found the PATH environment variable. */ + return 0; + } + /* Failed to find the PATH environment variable. */ + return 1; +} diff --git a/gl/tests/test-fprintf-posix.h b/gl/tests/test-fprintf-posix.h new file mode 100644 index 0000000000..9481aaa16f --- /dev/null +++ b/gl/tests/test-fprintf-posix.h @@ -0,0 +1,151 @@ +/* Test of POSIX compatible vsprintf() and sprintf() functions. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +static void +test_function (int (*my_fprintf) (FILE *, const char *, ...)) +{ + /* Here we don't test output that may be platform dependent. + The bulk of the tests is done as part of the 'vasnprintf-posix' module. */ + + /* Test support of size specifiers as in C99. */ + + my_fprintf (stdout, "%ju %d\n", (uintmax_t) 12345671, 33, 44, 55); + + my_fprintf (stdout, "%zu %d\n", (size_t) 12345672, 33, 44, 55); + + my_fprintf (stdout, "%tu %d\n", (ptrdiff_t) 12345673, 33, 44, 55); + + /* Test the support of the 'a' and 'A' conversion specifier for hexadecimal + output of floating-point numbers. */ + + /* Positive zero. */ + my_fprintf (stdout, "%a %d\n", 0.0, 33, 44, 55); + + /* Positive infinity. */ + my_fprintf (stdout, "%a %d\n", 1.0 / 0.0, 33, 44, 55); + + /* Negative infinity. */ + my_fprintf (stdout, "%a %d\n", -1.0 / 0.0, 33, 44, 55); + + /* FLAG_ZERO with infinite number. */ + my_fprintf (stdout, "%010a %d\n", 1.0 / 0.0, 33, 44, 55); + + /* Test the support of the %f format directive. */ + + /* A positive number. */ + my_fprintf (stdout, "%f %d\n", 12.75, 33, 44, 55); + + /* A larger positive number. */ + my_fprintf (stdout, "%f %d\n", 1234567.0, 33, 44, 55); + + /* A negative number. */ + my_fprintf (stdout, "%f %d\n", -0.03125, 33, 44, 55); + + /* Positive zero. */ + my_fprintf (stdout, "%f %d\n", 0.0, 33, 44, 55); + + /* FLAG_ZERO. */ + my_fprintf (stdout, "%015f %d\n", 1234.0, 33, 44, 55); + + /* Precision. */ + my_fprintf (stdout, "%.f %d\n", 1234.0, 33, 44, 55); + + /* Precision with no rounding. */ + my_fprintf (stdout, "%.2f %d\n", 999.95, 33, 44, 55); + + /* Precision with rounding. */ + my_fprintf (stdout, "%.2f %d\n", 999.996, 33, 44, 55); + + /* A positive number. */ + my_fprintf (stdout, "%Lf %d\n", 12.75L, 33, 44, 55); + + /* A larger positive number. */ + my_fprintf (stdout, "%Lf %d\n", 1234567.0L, 33, 44, 55); + + /* A negative number. */ + my_fprintf (stdout, "%Lf %d\n", -0.03125L, 33, 44, 55); + + /* Positive zero. */ + my_fprintf (stdout, "%Lf %d\n", 0.0L, 33, 44, 55); + + /* FLAG_ZERO. */ + my_fprintf (stdout, "%015Lf %d\n", 1234.0L, 33, 44, 55); + + /* Precision. */ + my_fprintf (stdout, "%.Lf %d\n", 1234.0L, 33, 44, 55); + + /* Precision with no rounding. */ + my_fprintf (stdout, "%.2Lf %d\n", 999.95L, 33, 44, 55); + + /* Precision with rounding. */ + my_fprintf (stdout, "%.2Lf %d\n", 999.996L, 33, 44, 55); + + /* Test the support of the %F format directive. */ + + /* A positive number. */ + my_fprintf (stdout, "%F %d\n", 12.75, 33, 44, 55); + + /* A larger positive number. */ + my_fprintf (stdout, "%F %d\n", 1234567.0, 33, 44, 55); + + /* A negative number. */ + my_fprintf (stdout, "%F %d\n", -0.03125, 33, 44, 55); + + /* Positive zero. */ + my_fprintf (stdout, "%F %d\n", 0.0, 33, 44, 55); + + /* FLAG_ZERO. */ + my_fprintf (stdout, "%015F %d\n", 1234.0, 33, 44, 55); + + /* Precision. */ + my_fprintf (stdout, "%.F %d\n", 1234.0, 33, 44, 55); + + /* Precision with no rounding. */ + my_fprintf (stdout, "%.2F %d\n", 999.95, 33, 44, 55); + + /* Precision with rounding. */ + my_fprintf (stdout, "%.2F %d\n", 999.996, 33, 44, 55); + + /* A positive number. */ + my_fprintf (stdout, "%LF %d\n", 12.75L, 33, 44, 55); + + /* A larger positive number. */ + my_fprintf (stdout, "%LF %d\n", 1234567.0L, 33, 44, 55); + + /* A negative number. */ + my_fprintf (stdout, "%LF %d\n", -0.03125L, 33, 44, 55); + + /* Positive zero. */ + my_fprintf (stdout, "%LF %d\n", 0.0L, 33, 44, 55); + + /* FLAG_ZERO. */ + my_fprintf (stdout, "%015LF %d\n", 1234.0L, 33, 44, 55); + + /* Precision. */ + my_fprintf (stdout, "%.LF %d\n", 1234.0L, 33, 44, 55); + + /* Precision with no rounding. */ + my_fprintf (stdout, "%.2LF %d\n", 999.95L, 33, 44, 55); + + /* Precision with rounding. */ + my_fprintf (stdout, "%.2LF %d\n", 999.996L, 33, 44, 55); + + /* Test the support of the POSIX/XSI format strings with positions. */ + + my_fprintf (stdout, "%2$d %1$d\n", 33, 55); +} diff --git a/gl/tests/test-frexp.c b/gl/tests/test-frexp.c new file mode 100644 index 0000000000..4ed24d2902 --- /dev/null +++ b/gl/tests/test-frexp.c @@ -0,0 +1,196 @@ +/* Test of splitting a double into fraction and mantissa. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +#include <math.h> + +#include "signature.h" +SIGNATURE_CHECK (frexp, double, (double, int *)); + +#include <float.h> + +#include "isnand-nolibm.h" +#include "minus-zero.h" +#include "nan.h" +#include "macros.h" + +/* Avoid some warnings from "gcc -Wshadow". + This file doesn't use the exp() function. */ +#undef exp +#define exp exponent + +static double +my_ldexp (double x, int d) +{ + for (; d > 0; d--) + x *= 2.0; + for (; d < 0; d++) + x *= 0.5; + return x; +} + +int +main () +{ + int i; + /* The use of 'volatile' guarantees that excess precision bits are dropped + when dealing with denormalized numbers. It is necessary on x86 systems + where double-floats are not IEEE compliant by default, to avoid that the + results become platform and compiler option dependent. 'volatile' is a + portable alternative to gcc's -ffloat-store option. */ + volatile double x; + + { /* NaN. */ + int exp = -9999; + double mantissa; + x = NaNd (); + mantissa = frexp (x, &exp); + ASSERT (isnand (mantissa)); + } + + { /* Positive infinity. */ + int exp = -9999; + double mantissa; + x = 1.0 / 0.0; + mantissa = frexp (x, &exp); + ASSERT (mantissa == x); + } + + { /* Negative infinity. */ + int exp = -9999; + double mantissa; + x = -1.0 / 0.0; + mantissa = frexp (x, &exp); + ASSERT (mantissa == x); + } + + { /* Positive zero. */ + int exp = -9999; + double mantissa; + x = 0.0; + mantissa = frexp (x, &exp); + ASSERT (exp == 0); + ASSERT (mantissa == x); + ASSERT (!signbit (mantissa)); + } + + { /* Negative zero. */ + int exp = -9999; + double mantissa; + x = minus_zerod; + mantissa = frexp (x, &exp); + ASSERT (exp == 0); + ASSERT (mantissa == x); + ASSERT (signbit (mantissa)); + } + + for (i = 1, x = 1.0; i <= DBL_MAX_EXP; i++, x *= 2.0) + { + int exp = -9999; + double mantissa = frexp (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.5); + } + for (i = 1, x = 1.0; i >= DBL_MIN_EXP; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = frexp (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.5); + } + for (; i >= DBL_MIN_EXP - 100 && x > 0.0; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = frexp (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.5); + } + + for (i = 1, x = -1.0; i <= DBL_MAX_EXP; i++, x *= 2.0) + { + int exp = -9999; + double mantissa = frexp (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == -0.5); + } + for (i = 1, x = -1.0; i >= DBL_MIN_EXP; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = frexp (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == -0.5); + } + for (; i >= DBL_MIN_EXP - 100 && x < 0.0; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = frexp (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == -0.5); + } + + for (i = 1, x = 1.01; i <= DBL_MAX_EXP; i++, x *= 2.0) + { + int exp = -9999; + double mantissa = frexp (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.505); + } + for (i = 1, x = 1.01; i >= DBL_MIN_EXP; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = frexp (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.505); + } + for (; i >= DBL_MIN_EXP - 100 && x > 0.0; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = frexp (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa >= 0.5); + ASSERT (mantissa < 1.0); + ASSERT (mantissa == my_ldexp (x, - exp)); + } + + for (i = 1, x = 1.73205; i <= DBL_MAX_EXP; i++, x *= 2.0) + { + int exp = -9999; + double mantissa = frexp (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.866025); + } + for (i = 1, x = 1.73205; i >= DBL_MIN_EXP; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = frexp (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.866025); + } + for (; i >= DBL_MIN_EXP - 100 && x > 0.0; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = frexp (x, &exp); + ASSERT (exp == i || exp == i + 1); + ASSERT (mantissa >= 0.5); + ASSERT (mantissa < 1.0); + ASSERT (mantissa == my_ldexp (x, - exp)); + } + + return 0; +} diff --git a/gl/tests/test-frexpl.c b/gl/tests/test-frexpl.c new file mode 100644 index 0000000000..ccb547b037 --- /dev/null +++ b/gl/tests/test-frexpl.c @@ -0,0 +1,208 @@ +/* Test of splitting a 'long double' into fraction and mantissa. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +#include <math.h> + +#include "signature.h" +SIGNATURE_CHECK (frexpl, long double, (long double, int *)); + +#include <float.h> + +#include "fpucw.h" +#include "isnanl-nolibm.h" +#include "minus-zero.h" +#include "nan.h" +#include "macros.h" + +/* Avoid some warnings from "gcc -Wshadow". + This file doesn't use the exp() function. */ +#undef exp +#define exp exponent + +/* On MIPS IRIX machines, LDBL_MIN_EXP is -1021, but the smallest reliable + exponent for 'long double' is -964. Similarly, on PowerPC machines, + LDBL_MIN_EXP is -1021, but the smallest reliable exponent for 'long double' + is -968. For exponents below that, the precision may be truncated to the + precision used for 'double'. */ +#ifdef __sgi +# define MIN_NORMAL_EXP (LDBL_MIN_EXP + 57) +#elif defined __ppc || defined __ppc__ || defined __powerpc || defined __powerpc__ +# define MIN_NORMAL_EXP (LDBL_MIN_EXP + 53) +#else +# define MIN_NORMAL_EXP LDBL_MIN_EXP +#endif + +static long double +my_ldexp (long double x, int d) +{ + for (; d > 0; d--) + x *= 2.0L; + for (; d < 0; d++) + x *= 0.5L; + return x; +} + +int +main () +{ + int i; + long double x; + DECL_LONG_DOUBLE_ROUNDING + + BEGIN_LONG_DOUBLE_ROUNDING (); + + { /* NaN. */ + int exp = -9999; + long double mantissa; + x = NaNl (); + mantissa = frexpl (x, &exp); + ASSERT (isnanl (mantissa)); + } + + { /* Positive infinity. */ + int exp = -9999; + long double mantissa; + x = 1.0L / 0.0L; + mantissa = frexpl (x, &exp); + ASSERT (mantissa == x); + } + + { /* Negative infinity. */ + int exp = -9999; + long double mantissa; + x = -1.0L / 0.0L; + mantissa = frexpl (x, &exp); + ASSERT (mantissa == x); + } + + { /* Positive zero. */ + int exp = -9999; + long double mantissa; + x = 0.0L; + mantissa = frexpl (x, &exp); + ASSERT (exp == 0); + ASSERT (mantissa == x); + ASSERT (!signbit (mantissa)); + } + + { /* Negative zero. */ + int exp = -9999; + long double mantissa; + x = minus_zerol; + mantissa = frexpl (x, &exp); + ASSERT (exp == 0); + ASSERT (mantissa == x); + ASSERT (signbit (mantissa)); + } + + for (i = 1, x = 1.0L; i <= LDBL_MAX_EXP; i++, x *= 2.0L) + { + int exp = -9999; + long double mantissa = frexpl (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.5L); + } + for (i = 1, x = 1.0L; i >= MIN_NORMAL_EXP; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = frexpl (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.5L); + } + for (; i >= LDBL_MIN_EXP - 100 && x > 0.0L; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = frexpl (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.5L); + } + + for (i = 1, x = -1.0L; i <= LDBL_MAX_EXP; i++, x *= 2.0L) + { + int exp = -9999; + long double mantissa = frexpl (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == -0.5L); + } + for (i = 1, x = -1.0L; i >= MIN_NORMAL_EXP; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = frexpl (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == -0.5L); + } + for (; i >= LDBL_MIN_EXP - 100 && x < 0.0L; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = frexpl (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == -0.5L); + } + + for (i = 1, x = 1.01L; i <= LDBL_MAX_EXP; i++, x *= 2.0L) + { + int exp = -9999; + long double mantissa = frexpl (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.505L); + } + for (i = 1, x = 1.01L; i >= MIN_NORMAL_EXP; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = frexpl (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.505L); + } + for (; i >= LDBL_MIN_EXP - 100 && x > 0.0L; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = frexpl (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa >= 0.5L); + ASSERT (mantissa < 1.0L); + ASSERT (mantissa == my_ldexp (x, - exp)); + } + + for (i = 1, x = 1.73205L; i <= LDBL_MAX_EXP; i++, x *= 2.0L) + { + int exp = -9999; + long double mantissa = frexpl (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.866025L); + } + for (i = 1, x = 1.73205L; i >= MIN_NORMAL_EXP; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = frexpl (x, &exp); + ASSERT (exp == i); + ASSERT (mantissa == 0.866025L); + } + for (; i >= LDBL_MIN_EXP - 100 && x > 0.0L; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = frexpl (x, &exp); + ASSERT (exp == i || exp == i + 1); + ASSERT (mantissa >= 0.5L); + ASSERT (mantissa < 1.0L); + ASSERT (mantissa == my_ldexp (x, - exp)); + } + + return 0; +} diff --git a/gl/tests/test-fseeko3.c b/gl/tests/test-fseeko3.c new file mode 100644 index 0000000000..41f2233d00 --- /dev/null +++ b/gl/tests/test-fseeko3.c @@ -0,0 +1,51 @@ +/* Test of fseeko() function. + Copyright (C) 2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <eblake@redhat.com>, 2011. */ + +#include <config.h> + +#include <stdio.h> + +#include <stdlib.h> + +#include "macros.h" + +int +main (int argc, char **argv) +{ + int do_initial_ftell = atoi (argv[1]); + const char *filename = argv[2]; + FILE *fp = fopen (filename, "r"); + ASSERT (fp != NULL); + + if (do_initial_ftell) + { + off_t pos = ftell (fp); + ASSERT (pos == 0); + } + + ASSERT (fseeko (fp, 0, SEEK_END) == 0); + + { + off_t pos = ftell (fp); + ASSERT (pos > 0); + } + + ASSERT (fclose (fp) == 0); + + return 0; +} diff --git a/gl/tests/test-fseeko3.sh b/gl/tests/test-fseeko3.sh new file mode 100755 index 0000000000..c50b4a2258 --- /dev/null +++ b/gl/tests/test-fseeko3.sh @@ -0,0 +1,7 @@ +#!/bin/sh + +./test-fseeko3${EXEEXT} 0 "$srcdir/test-fseeko3.sh" || exit 1 + +./test-fseeko3${EXEEXT} 1 "$srcdir/test-fseeko3.sh" || exit 1 + +exit 0 diff --git a/gl/tests/test-fseterr.c b/gl/tests/test-fseterr.c new file mode 100644 index 0000000000..cbd97faf45 --- /dev/null +++ b/gl/tests/test-fseterr.c @@ -0,0 +1,44 @@ +/* Test setting the error indicator of a stream. + Copyright (C) 2007, 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +#include "fseterr.h" + +#include <stdio.h> +#include <stdlib.h> + +int +main () +{ + /* All streams are initially created with the error indicator cleared. */ + if (ferror (stdout)) + abort (); + + /* Verify that fseterr() works. */ + fseterr (stdout); + if (!ferror (stdout)) + abort (); + + /* Verify fseterr's effect can be undone by clearerr(). */ + clearerr (stdout); + if (ferror (stdout)) + abort (); + + return 0; +} diff --git a/gl/tests/test-getcwd-lgpl.c b/gl/tests/test-getcwd-lgpl.c new file mode 100644 index 0000000000..69a7b90ecb --- /dev/null +++ b/gl/tests/test-getcwd-lgpl.c @@ -0,0 +1,102 @@ +/* Test of getcwd() function. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <unistd.h> + +#include "signature.h" +SIGNATURE_CHECK (getcwd, char *, (char *, size_t)); + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "macros.h" + +int +main (int argc, char **argv) +{ + char *pwd1; + char *pwd2; + /* If the user provides an argument, attempt to chdir there first. */ + if (1 < argc) + { + if (chdir (argv[1]) == 0) + printf ("changed to directory %s\n", argv[1]); + } + + pwd1 = getcwd (NULL, 0); + ASSERT (pwd1 && *pwd1); + if (1 < argc) + printf ("cwd=%s\n", pwd1); + + /* Make sure the result is usable. */ + ASSERT (chdir (pwd1) == 0); + ASSERT (chdir (".//./.") == 0); + + /* Make sure that result is normalized. */ + pwd2 = getcwd (NULL, 0); + ASSERT (pwd2); + ASSERT (strcmp (pwd1, pwd2) == 0); + free (pwd2); + { + size_t len = strlen (pwd1); + ssize_t i = len - 10; + if (i < 1) + i = 1; + pwd2 = getcwd (NULL, len + 1); + ASSERT (pwd2); + free (pwd2); + pwd2 = malloc (len + 2); + for ( ; i <= len; i++) + { + char *tmp; + errno = 0; + ASSERT (getcwd (pwd2, i) == NULL); + ASSERT (errno == ERANGE); + /* Allow either glibc or BSD behavior, since POSIX allows both. */ + errno = 0; + tmp = getcwd (NULL, i); + if (tmp) + { + ASSERT (strcmp (pwd1, tmp) == 0); + free (tmp); + } + else + { + ASSERT (errno == ERANGE); + } + } + ASSERT (getcwd (pwd2, len + 1) == pwd2); + pwd2[len] = '/'; + pwd2[len + 1] = '\0'; + } + ASSERT (strstr (pwd2, "/./") == NULL); + ASSERT (strstr (pwd2, "/../") == NULL); + ASSERT (strstr (pwd2 + 1 + (pwd2[1] == '/'), "//") == NULL); + + /* Validate a POSIX requirement on size. */ + errno = 0; + ASSERT (getcwd(pwd2, 0) == NULL); + ASSERT (errno == EINVAL); + + free (pwd1); + free (pwd2); + + return 0; +} diff --git a/gl/tests/test-getopt.c b/gl/tests/test-getopt.c new file mode 100644 index 0000000000..69f2cfa748 --- /dev/null +++ b/gl/tests/test-getopt.c @@ -0,0 +1,99 @@ +/* Test of command line argument processing. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2009. */ + +#include <config.h> + +/* None of the files accessed by this test are large, so disable the + ftell link warning if we are not using the gnulib ftell module. */ +#define _GL_NO_LARGE_FILES + +#if GNULIB_TEST_GETOPT_GNU +# include <getopt.h> + +# ifndef __getopt_argv_const +# define __getopt_argv_const const +# endif +# include "signature.h" +SIGNATURE_CHECK (getopt_long, int, (int, char *__getopt_argv_const *, + char const *, struct option const *, + int *)); +SIGNATURE_CHECK (getopt_long_only, int, (int, char *__getopt_argv_const *, + char const *, struct option const *, + int *)); + +#endif + +#include <unistd.h> + +#include "signature.h" +SIGNATURE_CHECK (getopt, int, (int, char * const[], char const *)); + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +/* This test intentionally remaps stderr. So, we arrange to have fd 10 + (outside the range of interesting fd's during the test) set up to + duplicate the original stderr. */ + +#define BACKUP_STDERR_FILENO 10 +#define ASSERT_STREAM myerr +#include "macros.h" + +static FILE *myerr; + +#include "test-getopt.h" +#if GNULIB_TEST_GETOPT_GNU +# include "test-getopt_long.h" +#endif + +int +main (void) +{ + /* This test validates that stderr is used correctly, so move the + original into fd 10. */ + if (dup2 (STDERR_FILENO, BACKUP_STDERR_FILENO) != BACKUP_STDERR_FILENO + || (myerr = fdopen (BACKUP_STDERR_FILENO, "w")) == NULL) + return 2; + + ASSERT (freopen ("test-getopt.tmp", "w", stderr) == stderr); + + /* These default values are required by POSIX. */ + ASSERT (optind == 1); + ASSERT (opterr != 0); + + setenv ("POSIXLY_CORRECT", "1", 1); + test_getopt (); + +#if GNULIB_TEST_GETOPT_GNU + test_getopt_long_posix (); +#endif + + unsetenv ("POSIXLY_CORRECT"); + test_getopt (); + +#if GNULIB_TEST_GETOPT_GNU + test_getopt_long (); + test_getopt_long_only (); +#endif + + ASSERT (fclose (stderr) == 0); + ASSERT (remove ("test-getopt.tmp") == 0); + + return 0; +} diff --git a/gl/tests/test-getopt.h b/gl/tests/test-getopt.h new file mode 100644 index 0000000000..f7b3911309 --- /dev/null +++ b/gl/tests/test-getopt.h @@ -0,0 +1,1391 @@ +/* Test of command line argument processing. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2009. */ + +#include <stdbool.h> + +/* The glibc/gnulib implementation of getopt supports setting optind = + 0, but not all other implementations do. This matters for getopt. + But for getopt_long, we require GNU compatibility. */ +#if defined __GETOPT_PREFIX || (__GLIBC__ >= 2 && !defined __UCLIBC__) +# define OPTIND_MIN 0 +#elif HAVE_DECL_OPTRESET +# define OPTIND_MIN (optreset = 1) +#else +# define OPTIND_MIN 1 +#endif + +static void +getopt_loop (int argc, const char **argv, + const char *options, + int *a_seen, int *b_seen, + const char **p_value, const char **q_value, + int *non_options_count, const char **non_options, + int *unrecognized, bool *message_issued) +{ + int c; + int pos = ftell (stderr); + + while ((c = getopt (argc, (char **) argv, options)) != -1) + { + switch (c) + { + case 'a': + (*a_seen)++; + break; + case 'b': + (*b_seen)++; + break; + case 'p': + *p_value = optarg; + break; + case 'q': + *q_value = optarg; + break; + case '\1': + /* Must only happen with option '-' at the beginning. */ + ASSERT (options[0] == '-'); + non_options[(*non_options_count)++] = optarg; + break; + case ':': + /* Must only happen with option ':' at the beginning. */ + ASSERT (options[0] == ':' + || ((options[0] == '-' || options[0] == '+') + && options[1] == ':')); + /* fall through */ + case '?': + *unrecognized = optopt; + break; + default: + *unrecognized = c; + break; + } + } + + *message_issued = pos < ftell (stderr); +} + +static void +test_getopt (void) +{ + int start; + bool posixly = !!getenv ("POSIXLY_CORRECT"); + /* See comment in getopt.c: + glibc gets a LSB-compliant getopt. + Standalone applications get a POSIX-compliant getopt. */ +#if defined __GETOPT_PREFIX || !(__GLIBC__ >= 2 || defined __MINGW32__) + /* Using getopt from gnulib or from a non-glibc system. */ + posixly = true; +#endif + + /* Test processing of boolean options. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-a"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "ab", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-b"; + argv[argc++] = "-a"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "ab", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 1); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 3); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-ba"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "ab", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 1); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-ab"; + argv[argc++] = "-a"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "ab", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 2); + ASSERT (b_seen == 1); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 3); + ASSERT (!output); + } + + /* Test processing of options with arguments. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-pfoo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "p:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "p:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 3); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-ab"; + argv[argc++] = "-q"; + argv[argc++] = "baz"; + argv[argc++] = "-pfoo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 1); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value != NULL && strcmp (q_value, "baz") == 0); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 5); + ASSERT (!output); + } + +#if GNULIB_TEST_GETOPT_GNU + /* Test processing of options with optional arguments. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-pfoo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "p::q::", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "p::q::", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "abp::q::", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 3); + ASSERT (!output); + } +#endif /* GNULIB_TEST_GETOPT_GNU */ + + /* Check that invalid options are recognized; and that both opterr + and leading ':' can silence output. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "-x"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 42; + getopt_loop (argc, argv, "abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 'x'); + ASSERT (optind == 5); + ASSERT (output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "-x"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 0; + getopt_loop (argc, argv, "abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 'x'); + ASSERT (optind == 5); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "-x"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, ":abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 'x'); + ASSERT (optind == 5); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "-:"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 42; + getopt_loop (argc, argv, "abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == ':'); + ASSERT (optind == 5); + ASSERT (output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "-:"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 0; + getopt_loop (argc, argv, "abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == ':'); + ASSERT (optind == 5); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "-:"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, ":abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == ':'); + ASSERT (optind == 5); + ASSERT (!output); + } + + /* Check for missing argument behavior. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-ap"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 'p'); + ASSERT (optind == 2); + ASSERT (output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-ap"; + argv[argc] = NULL; + optind = start; + opterr = 0; + getopt_loop (argc, argv, "abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 'p'); + ASSERT (optind == 2); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-ap"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, ":abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 'p'); + ASSERT (optind == 2); + ASSERT (!output); + } + + /* Check that by default, non-options arguments are moved to the end. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + if (posixly) + { + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 1); + ASSERT (!output); + } + else + { + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "-p") == 0); + ASSERT (strcmp (argv[2], "billy") == 0); + ASSERT (strcmp (argv[3], "-a") == 0); + ASSERT (strcmp (argv[4], "donald") == 0); + ASSERT (strcmp (argv[5], "duck") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 4); + ASSERT (!output); + } + } + + /* Check that '--' ends the argument processing. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[20]; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "--"; + argv[argc++] = "-b"; + argv[argc++] = "foo"; + argv[argc++] = "-q"; + argv[argc++] = "johnny"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + if (posixly) + { + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "--") == 0); + ASSERT (strcmp (argv[7], "-b") == 0); + ASSERT (strcmp (argv[8], "foo") == 0); + ASSERT (strcmp (argv[9], "-q") == 0); + ASSERT (strcmp (argv[10], "johnny") == 0); + ASSERT (strcmp (argv[11], "bar") == 0); + ASSERT (argv[12] == NULL); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 1); + ASSERT (!output); + } + else + { + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "-p") == 0); + ASSERT (strcmp (argv[2], "billy") == 0); + ASSERT (strcmp (argv[3], "-a") == 0); + ASSERT (strcmp (argv[4], "--") == 0); + ASSERT (strcmp (argv[5], "donald") == 0); + ASSERT (strcmp (argv[6], "duck") == 0); + ASSERT (strcmp (argv[7], "-b") == 0); + ASSERT (strcmp (argv[8], "foo") == 0); + ASSERT (strcmp (argv[9], "-q") == 0); + ASSERT (strcmp (argv[10], "johnny") == 0); + ASSERT (strcmp (argv[11], "bar") == 0); + ASSERT (argv[12] == NULL); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 5); + ASSERT (!output); + } + } + +#if GNULIB_TEST_GETOPT_GNU + /* Check that the '-' flag causes non-options to be returned in order. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "-abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 3); + ASSERT (strcmp (non_options[0], "donald") == 0); + ASSERT (strcmp (non_options[1], "duck") == 0); + ASSERT (strcmp (non_options[2], "bar") == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 7); + ASSERT (!output); + } + + /* Check that '--' ends the argument processing. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[20]; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "--"; + argv[argc++] = "-b"; + argv[argc++] = "foo"; + argv[argc++] = "-q"; + argv[argc++] = "johnny"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "-abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "--") == 0); + ASSERT (strcmp (argv[7], "-b") == 0); + ASSERT (strcmp (argv[8], "foo") == 0); + ASSERT (strcmp (argv[9], "-q") == 0); + ASSERT (strcmp (argv[10], "johnny") == 0); + ASSERT (strcmp (argv[11], "bar") == 0); + ASSERT (argv[12] == NULL); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0); + ASSERT (q_value == NULL); + ASSERT (!output); + if (non_options_count == 2) + { + /* glibc behaviour. */ + ASSERT (non_options_count == 2); + ASSERT (strcmp (non_options[0], "donald") == 0); + ASSERT (strcmp (non_options[1], "duck") == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 7); + } + else + { + /* Another valid behaviour. */ + ASSERT (non_options_count == 7); + ASSERT (strcmp (non_options[0], "donald") == 0); + ASSERT (strcmp (non_options[1], "duck") == 0); + ASSERT (strcmp (non_options[2], "-b") == 0); + ASSERT (strcmp (non_options[3], "foo") == 0); + ASSERT (strcmp (non_options[4], "-q") == 0); + ASSERT (strcmp (non_options[5], "johnny") == 0); + ASSERT (strcmp (non_options[6], "bar") == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 12); + } + } + + /* Check that the '-' flag has to come first. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "abp:q:-", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + if (posixly) + { + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 1); + ASSERT (!output); + } + else + { + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "-p") == 0); + ASSERT (strcmp (argv[2], "billy") == 0); + ASSERT (strcmp (argv[3], "-a") == 0); + ASSERT (strcmp (argv[4], "donald") == 0); + ASSERT (strcmp (argv[5], "duck") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 4); + ASSERT (!output); + } + } + + /* Check that the '+' flag causes the first non-option to terminate the + loop. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "+abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 1); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-+"; + argv[argc] = NULL; + optind = start; + getopt_loop (argc, argv, "+abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == '+'); + ASSERT (optind == 2); + ASSERT (output); + } + + /* Check that '--' ends the argument processing. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[20]; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "--"; + argv[argc++] = "-b"; + argv[argc++] = "foo"; + argv[argc++] = "-q"; + argv[argc++] = "johnny"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "+abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "--") == 0); + ASSERT (strcmp (argv[7], "-b") == 0); + ASSERT (strcmp (argv[8], "foo") == 0); + ASSERT (strcmp (argv[9], "-q") == 0); + ASSERT (strcmp (argv[10], "johnny") == 0); + ASSERT (strcmp (argv[11], "bar") == 0); + ASSERT (argv[12] == NULL); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 1); + ASSERT (!output); + } +#endif /* GNULIB_TEST_GETOPT_GNU */ + + /* Check that the '+' flag has to come first. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "abp:q:+", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + if (posixly) + { + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 1); + ASSERT (!output); + } + else + { + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "-p") == 0); + ASSERT (strcmp (argv[2], "billy") == 0); + ASSERT (strcmp (argv[3], "-a") == 0); + ASSERT (strcmp (argv[4], "donald") == 0); + ASSERT (strcmp (argv[5], "duck") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 4); + ASSERT (!output); + } + } + +#if GNULIB_TEST_GETOPT_GNU + /* If GNU extensions are supported, require compliance with POSIX + interpretation on leading '+' behavior. + http://austingroupbugs.net/view.php?id=191 */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + opterr = 1; + getopt_loop (argc, argv, "+:abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 1); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc] = NULL; + optind = start; + getopt_loop (argc, argv, "+:abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 'p'); + ASSERT (optind == 2); + ASSERT (!output); + } + for (start = OPTIND_MIN; start <= 1; start++) + { + int a_seen = 0; + int b_seen = 0; + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + bool output; + int argc = 0; + const char *argv[10]; + + argv[argc++] = "program"; + argv[argc++] = "-b"; + argv[argc++] = "-p"; + argv[argc] = NULL; + optind = start; + getopt_loop (argc, argv, "+:abp:q:", + &a_seen, &b_seen, &p_value, &q_value, + &non_options_count, non_options, &unrecognized, &output); + ASSERT (a_seen == 0); + ASSERT (b_seen == 1); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 'p'); + ASSERT (optind == 3); + ASSERT (!output); + } + + /* Check that 'W' does not dump core: + http://sourceware.org/bugzilla/show_bug.cgi?id=12922 + Technically, POSIX says the presence of ';' in the opt-string + gives unspecified behavior, so we only test this when GNU compliance + is desired. */ + for (start = OPTIND_MIN; start <= 1; start++) + { + int argc = 0; + const char *argv[10]; + int pos = ftell (stderr); + + argv[argc++] = "program"; + argv[argc++] = "-W"; + argv[argc++] = "dummy"; + argv[argc] = NULL; + optind = start; + opterr = 1; + ASSERT (getopt (argc, (char **) argv, "W;") == 'W'); + ASSERT (ftell (stderr) == pos); + ASSERT (optind == 2); + } +#endif /* GNULIB_TEST_GETOPT_GNU */ +} diff --git a/gl/tests/test-getopt_long.h b/gl/tests/test-getopt_long.h new file mode 100644 index 0000000000..c1035b1664 --- /dev/null +++ b/gl/tests/test-getopt_long.h @@ -0,0 +1,2144 @@ +/* Test of command line argument processing. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2009. */ + +static int a_seen; +static int b_seen; +static int q_seen; + +static const struct option long_options_required[] = + { + { "alpha", no_argument, NULL, 'a' }, + { "beta", no_argument, &b_seen, 1 }, + { "prune", required_argument, NULL, 'p' }, + { "quetsche", required_argument, &q_seen, 1 }, + { "xtremely-",no_argument, NULL, 1003 }, + { "xtra", no_argument, NULL, 1001 }, + { "xtreme", no_argument, NULL, 1002 }, + { "xtremely", no_argument, NULL, 1003 }, + { NULL, 0, NULL, 0 } + }; + +static const struct option long_options_optional[] = + { + { "alpha", no_argument, NULL, 'a' }, + { "beta", no_argument, &b_seen, 1 }, + { "prune", optional_argument, NULL, 'p' }, + { "quetsche", optional_argument, &q_seen, 1 }, + { NULL, 0, NULL, 0 } + }; + +static void +getopt_long_loop (int argc, const char **argv, + const char *options, const struct option *long_options, + const char **p_value, const char **q_value, + int *non_options_count, const char **non_options, + int *unrecognized) +{ + int option_index = -1; + int c; + + opterr = 0; + q_seen = 0; + while ((c = getopt_long (argc, (char **) argv, options, long_options, + &option_index)) + != -1) + { + switch (c) + { + case 0: + /* An option with a non-NULL flag pointer was processed. */ + if (q_seen) + *q_value = optarg; + break; + case 'a': + a_seen++; + break; + case 'b': + b_seen = 1; + break; + case 'p': + *p_value = optarg; + break; + case 'q': + *q_value = optarg; + break; + case '\1': + /* Must only happen with option '-' at the beginning. */ + ASSERT (options[0] == '-'); + non_options[(*non_options_count)++] = optarg; + break; + case ':': + /* Must only happen with option ':' at the beginning. */ + ASSERT (options[0] == ':' + || ((options[0] == '-' || options[0] == '+') + && options[1] == ':')); + /* fall through */ + case '?': + *unrecognized = optopt; + break; + default: + *unrecognized = c; + break; + } + } +} + +/* Reduce casting, so we can use string literals elsewhere. + getopt_long takes an array of char*, but luckily does not modify + those elements, so we can pass const char*. */ +static int +do_getopt_long (int argc, const char **argv, const char *shortopts, + const struct option *longopts, int *longind) +{ + return getopt_long (argc, (char **) argv, shortopts, longopts, longind); +} + +static void +test_getopt_long (void) +{ + int start; + + /* Test disambiguation of options. */ + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "--x"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long (argc, argv, "ab", long_options_required, &option_index); + ASSERT (c == '?'); + ASSERT (optopt == 0); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "--xt"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long (argc, argv, "ab", long_options_required, &option_index); + ASSERT (c == '?'); + ASSERT (optopt == 0); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "--xtr"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long (argc, argv, "ab", long_options_required, &option_index); + ASSERT (c == '?'); + ASSERT (optopt == 0); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "--xtra"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long (argc, argv, "ab", long_options_required, &option_index); + ASSERT (c == 1001); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "--xtre"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long (argc, argv, "ab", long_options_required, &option_index); + ASSERT (c == '?'); + ASSERT (optopt == 0); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "--xtrem"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long (argc, argv, "ab", long_options_required, &option_index); + ASSERT (c == '?'); + ASSERT (optopt == 0); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "--xtreme"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long (argc, argv, "ab", long_options_required, &option_index); + ASSERT (c == 1002); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "--xtremel"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long (argc, argv, "ab", long_options_required, &option_index); + ASSERT (c == 1003); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "--xtremely"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long (argc, argv, "ab", long_options_required, &option_index); + ASSERT (c == 1003); + } + + /* Check that -W handles unknown options. */ + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-W"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long (argc, argv, "W;", long_options_required, &option_index); + ASSERT (c == '?'); + ASSERT (optopt == 'W'); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-Wunknown"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long (argc, argv, "W;", long_options_required, &option_index); + /* glibc and BSD behave differently here, but for now, we allow + both behaviors since W support is not frequently used. */ + if (c == '?') + { + ASSERT (optopt == 0); + ASSERT (optarg == NULL); + } + else + { + ASSERT (c == 'W'); + ASSERT (strcmp (optarg, "unknown") == 0); + } + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-W"; + argv[argc++] = "unknown"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long (argc, argv, "W;", long_options_required, &option_index); + /* glibc and BSD behave differently here, but for now, we allow + both behaviors since W support is not frequently used. */ + if (c == '?') + { + ASSERT (optopt == 0); + ASSERT (optarg == NULL); + } + else + { + ASSERT (c == 'W'); + ASSERT (strcmp (optarg, "unknown") == 0); + } + } + + /* Test that 'W' does not dump core: + http://sourceware.org/bugzilla/show_bug.cgi?id=12922 */ + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-W"; + argv[argc++] = "dummy"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long (argc, argv, "W;", NULL, &option_index); + ASSERT (c == 'W'); + ASSERT (optind == 2); + } + + /* Test processing of boolean short options. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-a"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "ab", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-b"; + argv[argc++] = "-a"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "ab", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 1); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 3); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-ba"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "ab", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 1); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-ab"; + argv[argc++] = "-a"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "ab", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 2); + ASSERT (b_seen == 1); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 3); + } + + /* Test processing of boolean long options. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "--alpha"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "ab", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "--beta"; + argv[argc++] = "--alpha"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "ab", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 1); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 3); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "--alpha"; + argv[argc++] = "--beta"; + argv[argc++] = "--alpha"; + argv[argc++] = "--beta"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "ab", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 2); + ASSERT (b_seen == 1); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 5); + } + + /* Test processing of boolean long options via -W. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-Walpha"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abW;", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-W"; + argv[argc++] = "beta"; + argv[argc++] = "-W"; + argv[argc++] = "alpha"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "aW;b", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 1); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 5); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-Walpha"; + argv[argc++] = "-Wbeta"; + argv[argc++] = "-Walpha"; + argv[argc++] = "-Wbeta"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "W;ab", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 2); + ASSERT (b_seen == 1); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 5); + } + + /* Test processing of short options with arguments. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-pfoo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 3); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-ab"; + argv[argc++] = "-q"; + argv[argc++] = "baz"; + argv[argc++] = "-pfoo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 1); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value != NULL && strcmp (q_value, "baz") == 0); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 5); + } + + /* Test processing of long options with arguments. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "--p=foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "--p"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 3); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-ab"; + argv[argc++] = "--q"; + argv[argc++] = "baz"; + argv[argc++] = "--p=foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 1); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value != NULL && strcmp (q_value, "baz") == 0); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 5); + } + + /* Test processing of long options with arguments via -W. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-Wp=foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p:q:W;", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-W"; + argv[argc++] = "p"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p:W;q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 4); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-ab"; + argv[argc++] = "-Wq"; + argv[argc++] = "baz"; + argv[argc++] = "-W"; + argv[argc++] = "p=foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "W;abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 1); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value != NULL && strcmp (q_value, "baz") == 0); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 6); + } + + /* Test processing of short options with optional arguments. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-pfoo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p::q::", long_options_optional, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p::q::", long_options_optional, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abp::q::", long_options_optional, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 3); + } + + /* Test processing of long options with optional arguments. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "--p=foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p::q::", long_options_optional, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "--p"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p::q::", long_options_optional, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "--p="; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p::q::", long_options_optional, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && *p_value == '\0'); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "--p"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abp::q::", long_options_optional, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 3); + } + + /* Test processing of long options with optional arguments via -W. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-Wp=foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p::q::W;", long_options_optional, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-Wp"; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p::q::W;", long_options_optional, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-Wp="; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "W;p::q::", long_options_optional, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && *p_value == '\0'); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-W"; + argv[argc++] = "p="; + argv[argc++] = "foo"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "W;p::q::", long_options_optional, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && *p_value == '\0'); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 3); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-W"; + argv[argc++] = "p"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "W;abp::q::", long_options_optional, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + /* ASSERT (p_value == NULL); */ + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 4); + } + + /* Check that invalid options are recognized. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "-x"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 'x'); + ASSERT (optind == 5); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "-:"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == ':'); + ASSERT (optind == 5); + } + + /* Check that unexpected arguments are recognized. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "--a="; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 'a'); + ASSERT (optind == 4); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "foo"; + argv[argc++] = "--b="; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "foo") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + /* When flag is non-zero, glibc sets optopt anyway, but BSD + leaves optopt unchanged. */ + ASSERT (unrecognized == 1 || unrecognized == 0); + ASSERT (optind == 4); + } + + /* Check that by default, non-options arguments are moved to the end. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "-p") == 0); + ASSERT (strcmp (argv[2], "billy") == 0); + ASSERT (strcmp (argv[3], "-a") == 0); + ASSERT (strcmp (argv[4], "donald") == 0); + ASSERT (strcmp (argv[5], "duck") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 4); + } + + /* Check that '--' ends the argument processing. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[20]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "--"; + argv[argc++] = "-b"; + argv[argc++] = "foo"; + argv[argc++] = "-q"; + argv[argc++] = "johnny"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "-p") == 0); + ASSERT (strcmp (argv[2], "billy") == 0); + ASSERT (strcmp (argv[3], "-a") == 0); + ASSERT (strcmp (argv[4], "--") == 0); + ASSERT (strcmp (argv[5], "donald") == 0); + ASSERT (strcmp (argv[6], "duck") == 0); + ASSERT (strcmp (argv[7], "-b") == 0); + ASSERT (strcmp (argv[8], "foo") == 0); + ASSERT (strcmp (argv[9], "-q") == 0); + ASSERT (strcmp (argv[10], "johnny") == 0); + ASSERT (strcmp (argv[11], "bar") == 0); + ASSERT (argv[12] == NULL); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 5); + } + + /* Check that the '-' flag causes non-options to be returned in order. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "-abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 3); + ASSERT (strcmp (non_options[0], "donald") == 0); + ASSERT (strcmp (non_options[1], "duck") == 0); + ASSERT (strcmp (non_options[2], "bar") == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 7); + } + + /* Check that '--' ends the argument processing. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[20]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "--"; + argv[argc++] = "-b"; + argv[argc++] = "foo"; + argv[argc++] = "-q"; + argv[argc++] = "johnny"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "-abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "--") == 0); + ASSERT (strcmp (argv[7], "-b") == 0); + ASSERT (strcmp (argv[8], "foo") == 0); + ASSERT (strcmp (argv[9], "-q") == 0); + ASSERT (strcmp (argv[10], "johnny") == 0); + ASSERT (strcmp (argv[11], "bar") == 0); + ASSERT (argv[12] == NULL); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0); + ASSERT (q_value == NULL); + if (non_options_count == 2) + { + /* glibc behaviour. */ + ASSERT (non_options_count == 2); + ASSERT (strcmp (non_options[0], "donald") == 0); + ASSERT (strcmp (non_options[1], "duck") == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 7); + } + else + { + /* Another valid behaviour. */ + ASSERT (non_options_count == 7); + ASSERT (strcmp (non_options[0], "donald") == 0); + ASSERT (strcmp (non_options[1], "duck") == 0); + ASSERT (strcmp (non_options[2], "-b") == 0); + ASSERT (strcmp (non_options[3], "foo") == 0); + ASSERT (strcmp (non_options[4], "-q") == 0); + ASSERT (strcmp (non_options[5], "johnny") == 0); + ASSERT (strcmp (non_options[6], "bar") == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 12); + } + } + + /* Check that the '-' flag has to come first. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abp:q:-", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "-p") == 0); + ASSERT (strcmp (argv[2], "billy") == 0); + ASSERT (strcmp (argv[3], "-a") == 0); + ASSERT (strcmp (argv[4], "donald") == 0); + ASSERT (strcmp (argv[5], "duck") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 4); + } + + /* Check that the '+' flag causes the first non-option to terminate the + loop. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "+abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 1); + } + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-+"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "+abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == '+'); + ASSERT (optind == 2); + } + + /* Check that '--' ends the argument processing. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[20]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "--"; + argv[argc++] = "-b"; + argv[argc++] = "foo"; + argv[argc++] = "-q"; + argv[argc++] = "johnny"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "+abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "--") == 0); + ASSERT (strcmp (argv[7], "-b") == 0); + ASSERT (strcmp (argv[8], "foo") == 0); + ASSERT (strcmp (argv[9], "-q") == 0); + ASSERT (strcmp (argv[10], "johnny") == 0); + ASSERT (strcmp (argv[11], "bar") == 0); + ASSERT (argv[12] == NULL); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 1); + } + + /* Check that the '+' flag has to come first. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abp:q:+", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "-p") == 0); + ASSERT (strcmp (argv[2], "billy") == 0); + ASSERT (strcmp (argv[3], "-a") == 0); + ASSERT (strcmp (argv[4], "donald") == 0); + ASSERT (strcmp (argv[5], "duck") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 1); + ASSERT (b_seen == 0); + ASSERT (p_value != NULL && strcmp (p_value, "billy") == 0); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 4); + } +} + +/* Test behavior of getopt_long when POSIXLY_CORRECT is set in the + environment. Options with optional arguments should not change + behavior just because of an environment variable. + http://lists.gnu.org/archive/html/bug-m4/2006-09/msg00028.html */ +static void +test_getopt_long_posix (void) +{ + int start; + + /* Check that POSIXLY_CORRECT stops parsing the same as leading '+'. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "donald"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc++] = "duck"; + argv[argc++] = "-a"; + argv[argc++] = "bar"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "abp:q:", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (strcmp (argv[0], "program") == 0); + ASSERT (strcmp (argv[1], "donald") == 0); + ASSERT (strcmp (argv[2], "-p") == 0); + ASSERT (strcmp (argv[3], "billy") == 0); + ASSERT (strcmp (argv[4], "duck") == 0); + ASSERT (strcmp (argv[5], "-a") == 0); + ASSERT (strcmp (argv[6], "bar") == 0); + ASSERT (argv[7] == NULL); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 1); + } + + /* Check that POSIXLY_CORRECT doesn't change optional arguments. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-p"; + argv[argc++] = "billy"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "p::", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 0); + ASSERT (b_seen == 0); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 2); + } + + /* Check that leading - still sees options after non-options. */ + for (start = 0; start <= 1; start++) + { + const char *p_value = NULL; + const char *q_value = NULL; + int non_options_count = 0; + const char *non_options[10]; + int unrecognized = 0; + int argc = 0; + const char *argv[10]; + a_seen = 0; + b_seen = 0; + + argv[argc++] = "program"; + argv[argc++] = "-a"; + argv[argc++] = "billy"; + argv[argc++] = "-b"; + argv[argc] = NULL; + optind = start; + getopt_long_loop (argc, argv, "-ab", long_options_required, + &p_value, &q_value, + &non_options_count, non_options, &unrecognized); + ASSERT (a_seen == 1); + ASSERT (b_seen == 1); + ASSERT (p_value == NULL); + ASSERT (q_value == NULL); + ASSERT (non_options_count == 1); + ASSERT (strcmp (non_options[0], "billy") == 0); + ASSERT (unrecognized == 0); + ASSERT (optind == 4); + } +} + +/* Reduce casting, so we can use string literals elsewhere. + getopt_long_only takes an array of char*, but luckily does not + modify those elements, so we can pass const char*. */ +static int +do_getopt_long_only (int argc, const char **argv, const char *shortopts, + const struct option *longopts, int *longind) +{ + return getopt_long_only (argc, (char **) argv, shortopts, longopts, longind); +} + +static void +test_getopt_long_only (void) +{ + /* Test disambiguation of options. */ + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-x"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long_only (argc, argv, "ab", long_options_required, + &option_index); + ASSERT (c == '?'); + ASSERT (optopt == 0); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-x"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long_only (argc, argv, "abx", long_options_required, + &option_index); + ASSERT (c == 'x'); + ASSERT (optopt == 0); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "--x"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long_only (argc, argv, "abx", long_options_required, + &option_index); + ASSERT (c == '?'); + ASSERT (optopt == 0); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-b"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + b_seen = 0; + c = do_getopt_long_only (argc, argv, "abx", long_options_required, + &option_index); + ASSERT (c == 'b'); + ASSERT (b_seen == 0); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "--b"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + b_seen = 0; + c = do_getopt_long_only (argc, argv, "abx", long_options_required, + &option_index); + ASSERT (c == 0); + ASSERT (b_seen == 1); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-xt"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long_only (argc, argv, "ab", long_options_required, + &option_index); + ASSERT (c == '?'); + ASSERT (optopt == 0); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-xt"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long_only (argc, argv, "abx", long_options_required, + &option_index); + ASSERT (c == '?'); + ASSERT (optopt == 0); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-xtra"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long_only (argc, argv, "ab", long_options_required, + &option_index); + ASSERT (c == 1001); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-xtreme"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long_only (argc, argv, "abx:", long_options_required, + &option_index); + ASSERT (c == 1002); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-xtremel"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long_only (argc, argv, "ab", long_options_required, + &option_index); + /* glibc getopt_long_only is intentionally different from + getopt_long when handling a prefix that is common to two + spellings, when both spellings have the same option directives. + BSD getopt_long_only treats both cases the same. */ + ASSERT (c == 1003 || c == '?'); + ASSERT (optind == 2); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-xtremel"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long_only (argc, argv, "abx::", long_options_required, + &option_index); + /* glibc getopt_long_only is intentionally different from + getopt_long when handling a prefix that is common to two + spellings, when both spellings have the same option directives. + BSD getopt_long_only treats both cases the same. */ + ASSERT (c == 1003 || c == '?'); + ASSERT (optind == 2); + ASSERT (optarg == NULL); + } + { + int argc = 0; + const char *argv[10]; + int option_index; + int c; + + argv[argc++] = "program"; + argv[argc++] = "-xtras"; + argv[argc] = NULL; + optind = 1; + opterr = 0; + c = do_getopt_long_only (argc, argv, "abx::", long_options_required, + &option_index); + ASSERT (c == 'x'); + ASSERT (strcmp (optarg, "tras") == 0); + } +} diff --git a/gl/tests/test-ignore-value.c b/gl/tests/test-ignore-value.c new file mode 100644 index 0000000000..6953f4cadf --- /dev/null +++ b/gl/tests/test-ignore-value.c @@ -0,0 +1,84 @@ +/* Test the "ignore-value" module. + + Copyright (C) 2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake. */ + +#include <config.h> + +#include "ignore-value.h" + +#include <stdio.h> + +#ifndef _GL_ATTRIBUTE_RETURN_CHECK +# if __GNUC__ < 3 || (__GNUC__ == 3 && __GNUC_MINOR__ < 4) +# define _GL_ATTRIBUTE_RETURN_CHECK +# else +# define _GL_ATTRIBUTE_RETURN_CHECK __attribute__((__warn_unused_result__)) +# endif +#endif + +struct s { int i; }; +static char doChar (void) _GL_ATTRIBUTE_RETURN_CHECK; +static int doInt (void) _GL_ATTRIBUTE_RETURN_CHECK; +static off_t doOff (void) _GL_ATTRIBUTE_RETURN_CHECK; +static void *doPtr (void) _GL_ATTRIBUTE_RETURN_CHECK; +static struct s doStruct (void) _GL_ATTRIBUTE_RETURN_CHECK; + +static char +doChar (void) +{ + return 0; +} + +static int +doInt (void) +{ + return 0; +} + +static off_t +doOff (void) +{ + return 0; +} + +static void * +doPtr (void) +{ + return NULL; +} + +static struct s +doStruct (void) +{ + static struct s s1; + return s1; +} + +int +main (void) +{ + /* If this test can compile with -Werror and the same warnings as + the rest of the project, then we are properly silencing warnings + about ignored return values. */ + ignore_value (doChar ()); + ignore_value (doInt ()); + ignore_value (doOff ()); + ignore_value (doPtr ()); + ignore_value (doStruct ()); + return 0; +} diff --git a/gl/tests/test-isnand-nolibm.c b/gl/tests/test-isnand-nolibm.c new file mode 100644 index 0000000000..d120459234 --- /dev/null +++ b/gl/tests/test-isnand-nolibm.c @@ -0,0 +1,22 @@ +/* Test of isnand() substitute. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include "isnand-nolibm.h" + +#include "test-isnand.h" + diff --git a/gl/tests/test-isnand.h b/gl/tests/test-isnand.h new file mode 100644 index 0000000000..de69331efd --- /dev/null +++ b/gl/tests/test-isnand.h @@ -0,0 +1,62 @@ +/* Test of isnand() substitute. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <limits.h> + +#include "minus-zero.h" +#include "nan.h" +#include "macros.h" + +int +main () +{ + /* Finite values. */ + ASSERT (!isnand (3.141)); + ASSERT (!isnand (3.141e30)); + ASSERT (!isnand (3.141e-30)); + ASSERT (!isnand (-2.718)); + ASSERT (!isnand (-2.718e30)); + ASSERT (!isnand (-2.718e-30)); + ASSERT (!isnand (0.0)); + ASSERT (!isnand (minus_zerod)); + /* Infinite values. */ + ASSERT (!isnand (1.0 / 0.0)); + ASSERT (!isnand (-1.0 / 0.0)); + /* Quiet NaN. */ + ASSERT (isnand (NaNd ())); +#if defined DBL_EXPBIT0_WORD && defined DBL_EXPBIT0_BIT + /* Signalling NaN. */ + { + #define NWORDS \ + ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + typedef union { double value; unsigned int word[NWORDS]; } memory_double; + memory_double m; + m.value = NaNd (); +# if DBL_EXPBIT0_BIT > 0 + m.word[DBL_EXPBIT0_WORD] ^= (unsigned int) 1 << (DBL_EXPBIT0_BIT - 1); +# else + m.word[DBL_EXPBIT0_WORD + (DBL_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + ^= (unsigned int) 1 << (sizeof (unsigned int) * CHAR_BIT - 1); +# endif + m.word[DBL_EXPBIT0_WORD + (DBL_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + |= (unsigned int) 1 << DBL_EXPBIT0_BIT; + ASSERT (isnand (m.value)); + } +#endif + return 0; +} diff --git a/gl/tests/test-isnanf-nolibm.c b/gl/tests/test-isnanf-nolibm.c new file mode 100644 index 0000000000..6d720be911 --- /dev/null +++ b/gl/tests/test-isnanf-nolibm.c @@ -0,0 +1,21 @@ +/* Test of isnanf() substitute. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include "isnanf-nolibm.h" + +#include "test-isnanf.h" diff --git a/gl/tests/test-isnanf.h b/gl/tests/test-isnanf.h new file mode 100644 index 0000000000..f4b0e861fc --- /dev/null +++ b/gl/tests/test-isnanf.h @@ -0,0 +1,64 @@ +/* Test of isnanf() substitute. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <limits.h> + +#include "minus-zero.h" +#include "nan.h" +#include "macros.h" + +int +main () +{ + /* Finite values. */ + ASSERT (!isnanf (3.141f)); + ASSERT (!isnanf (3.141e30f)); + ASSERT (!isnanf (3.141e-30f)); + ASSERT (!isnanf (-2.718f)); + ASSERT (!isnanf (-2.718e30f)); + ASSERT (!isnanf (-2.718e-30f)); + ASSERT (!isnanf (0.0f)); + ASSERT (!isnanf (minus_zerof)); + /* Infinite values. */ + ASSERT (!isnanf (1.0f / 0.0f)); + ASSERT (!isnanf (-1.0f / 0.0f)); + /* Quiet NaN. */ + ASSERT (isnanf (NaNf ())); +#if defined FLT_EXPBIT0_WORD && defined FLT_EXPBIT0_BIT + /* Signalling NaN. */ + { + #define NWORDS \ + ((sizeof (float) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + typedef union { float value; unsigned int word[NWORDS]; } memory_float; + memory_float m; + m.value = NaNf (); +# if FLT_EXPBIT0_BIT > 0 + m.word[FLT_EXPBIT0_WORD] ^= (unsigned int) 1 << (FLT_EXPBIT0_BIT - 1); +# else + m.word[FLT_EXPBIT0_WORD + (FLT_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + ^= (unsigned int) 1 << (sizeof (unsigned int) * CHAR_BIT - 1); +# endif + if (FLT_EXPBIT0_WORD < NWORDS / 2) + m.word[FLT_EXPBIT0_WORD + 1] |= (unsigned int) 1 << FLT_EXPBIT0_BIT; + else + m.word[0] |= (unsigned int) 1; + ASSERT (isnanf (m.value)); + } +#endif + return 0; +} diff --git a/gl/tests/test-isnanl-nolibm.c b/gl/tests/test-isnanl-nolibm.c new file mode 100644 index 0000000000..532208782e --- /dev/null +++ b/gl/tests/test-isnanl-nolibm.c @@ -0,0 +1,23 @@ +/* Test of isnanl() substitute. + Copyright (C) 2007, 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +#include "isnanl-nolibm.h" + +#include "test-isnanl.h" diff --git a/gl/tests/test-isnanl.h b/gl/tests/test-isnanl.h new file mode 100644 index 0000000000..c07f3a9646 --- /dev/null +++ b/gl/tests/test-isnanl.h @@ -0,0 +1,126 @@ +/* Test of isnanl() substitute. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <float.h> +#include <limits.h> + +#include "minus-zero.h" +#include "nan.h" +#include "macros.h" + +int +main () +{ + #define NWORDS \ + ((sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + typedef union { unsigned int word[NWORDS]; long double value; } + memory_long_double; + + /* Finite values. */ + ASSERT (!isnanl (3.141L)); + ASSERT (!isnanl (3.141e30L)); + ASSERT (!isnanl (3.141e-30L)); + ASSERT (!isnanl (-2.718L)); + ASSERT (!isnanl (-2.718e30L)); + ASSERT (!isnanl (-2.718e-30L)); + ASSERT (!isnanl (0.0L)); + ASSERT (!isnanl (minus_zerol)); + /* Infinite values. */ + ASSERT (!isnanl (1.0L / 0.0L)); + ASSERT (!isnanl (-1.0L / 0.0L)); + /* Quiet NaN. */ + ASSERT (isnanl (NaNl ())); + +#if defined LDBL_EXPBIT0_WORD && defined LDBL_EXPBIT0_BIT + /* A bit pattern that is different from a Quiet NaN. With a bit of luck, + it's a Signalling NaN. */ + { + memory_long_double m; + m.value = NaNl (); +# if LDBL_EXPBIT0_BIT > 0 + m.word[LDBL_EXPBIT0_WORD] ^= (unsigned int) 1 << (LDBL_EXPBIT0_BIT - 1); +# else + m.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + ^= (unsigned int) 1 << (sizeof (unsigned int) * CHAR_BIT - 1); +# endif + m.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + |= (unsigned int) 1 << LDBL_EXPBIT0_BIT; + ASSERT (isnanl (m.value)); + } +#endif + +#if ((defined __ia64 && LDBL_MANT_DIG == 64) || (defined __x86_64__ || defined __amd64__) || (defined __i386 || defined __i386__ || defined _I386 || defined _M_IX86 || defined _X86_)) +/* Representation of an 80-bit 'long double' as an initializer for a sequence + of 'unsigned int' words. */ +# ifdef WORDS_BIGENDIAN +# define LDBL80_WORDS(exponent,manthi,mantlo) \ + { ((unsigned int) (exponent) << 16) | ((unsigned int) (manthi) >> 16), \ + ((unsigned int) (manthi) << 16) | (unsigned int) (mantlo) >> 16), \ + (unsigned int) (mantlo) << 16 \ + } +# else +# define LDBL80_WORDS(exponent,manthi,mantlo) \ + { mantlo, manthi, exponent } +# endif + { /* Quiet NaN. */ + static memory_long_double x = + { LDBL80_WORDS (0xFFFF, 0xC3333333, 0x00000000) }; + ASSERT (isnanl (x.value)); + } + { + /* Signalling NaN. */ + static memory_long_double x = + { LDBL80_WORDS (0xFFFF, 0x83333333, 0x00000000) }; + ASSERT (isnanl (x.value)); + } + /* The isnanl function should recognize Pseudo-NaNs, Pseudo-Infinities, + Pseudo-Zeroes, Unnormalized Numbers, and Pseudo-Denormals, as defined in + Intel IA-64 Architecture Software Developer's Manual, Volume 1: + Application Architecture. + Table 5-2 "Floating-Point Register Encodings" + Figure 5-6 "Memory to Floating-Point Register Data Translation" + */ + { /* Pseudo-NaN. */ + static memory_long_double x = + { LDBL80_WORDS (0xFFFF, 0x40000001, 0x00000000) }; + ASSERT (isnanl (x.value)); + } + { /* Pseudo-Infinity. */ + static memory_long_double x = + { LDBL80_WORDS (0xFFFF, 0x00000000, 0x00000000) }; + ASSERT (isnanl (x.value)); + } + { /* Pseudo-Zero. */ + static memory_long_double x = + { LDBL80_WORDS (0x4004, 0x00000000, 0x00000000) }; + ASSERT (isnanl (x.value)); + } + { /* Unnormalized number. */ + static memory_long_double x = + { LDBL80_WORDS (0x4000, 0x63333333, 0x00000000) }; + ASSERT (isnanl (x.value)); + } + { /* Pseudo-Denormal. */ + static memory_long_double x = + { LDBL80_WORDS (0x0000, 0x83333333, 0x00000000) }; + ASSERT (isnanl (x.value)); + } +#endif + + return 0; +} diff --git a/gl/tests/test-lstat.c b/gl/tests/test-lstat.c new file mode 100644 index 0000000000..372e05653d --- /dev/null +++ b/gl/tests/test-lstat.c @@ -0,0 +1,60 @@ +/* Test of lstat() function. + Copyright (C) 2008-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Simon Josefsson, 2008; and Eric Blake, 2009. */ + +#include <config.h> + +#include <sys/stat.h> + +/* Caution: lstat may be a function-like macro. Although this + signature check must pass, it may be the signature of the real (and + broken) lstat rather than rpl_lstat. Most code should not use the + address of lstat. */ +#include "signature.h" +SIGNATURE_CHECK (lstat, int, (char const *, struct stat *)); + +#include <fcntl.h> +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +#include "same-inode.h" +#include "ignore-value.h" +#include "macros.h" + +#define BASE "test-lstat.t" + +#include "test-lstat.h" + +/* Wrapper around lstat, which works even if lstat is a function-like + macro, where test_lstat_func(lstat) would do the wrong thing. */ +static int +do_lstat (char const *name, struct stat *st) +{ + return lstat (name, st); +} + +int +main (void) +{ + /* Remove any leftovers from a previous partial run. */ + ignore_value (system ("rm -rf " BASE "*")); + + return test_lstat_func (do_lstat, true); +} diff --git a/gl/tests/test-lstat.h b/gl/tests/test-lstat.h new file mode 100644 index 0000000000..883c4e8c0b --- /dev/null +++ b/gl/tests/test-lstat.h @@ -0,0 +1,116 @@ +/* Test of lstat() function. + Copyright (C) 2008-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Simon Josefsson, 2008; and Eric Blake, 2009. */ + +/* This file is designed to test both lstat(n,buf) and + fstatat(AT_FDCWD,n,buf,AT_SYMLINK_NOFOLLOW). FUNC is the function + to test. Assumes that BASE and ASSERT are already defined, and + that appropriate headers are already included. If PRINT, warn + before skipping symlink tests with status 77. */ + +static int +test_lstat_func (int (*func) (char const *, struct stat *), bool print) +{ + struct stat st1; + struct stat st2; + + /* Test for common directories. */ + ASSERT (func (".", &st1) == 0); + ASSERT (func ("./", &st2) == 0); + ASSERT (SAME_INODE (st1, st2)); + ASSERT (S_ISDIR (st1.st_mode)); + ASSERT (S_ISDIR (st2.st_mode)); + ASSERT (func ("/", &st1) == 0); + ASSERT (func ("///", &st2) == 0); + ASSERT (SAME_INODE (st1, st2)); + ASSERT (S_ISDIR (st1.st_mode)); + ASSERT (S_ISDIR (st2.st_mode)); + ASSERT (func ("..", &st1) == 0); + ASSERT (S_ISDIR (st1.st_mode)); + + /* Test for error conditions. */ + errno = 0; + ASSERT (func ("", &st1) == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (func ("nosuch", &st1) == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (func ("nosuch/", &st1) == -1); + ASSERT (errno == ENOENT); + + ASSERT (close (creat (BASE "file", 0600)) == 0); + ASSERT (func (BASE "file", &st1) == 0); + ASSERT (S_ISREG (st1.st_mode)); + errno = 0; + ASSERT (func (BASE "file/", &st1) == -1); + ASSERT (errno == ENOTDIR); + + /* Now for some symlink tests, where supported. We set up: + link1 -> directory + link2 -> file + link3 -> dangling + link4 -> loop + then test behavior both with and without trailing slash. + */ + if (symlink (".", BASE "link1") != 0) + { + ASSERT (unlink (BASE "file") == 0); + if (print) + fputs ("skipping test: symlinks not supported on this file system\n", + stderr); + return 77; + } + ASSERT (symlink (BASE "file", BASE "link2") == 0); + ASSERT (symlink (BASE "nosuch", BASE "link3") == 0); + ASSERT (symlink (BASE "link4", BASE "link4") == 0); + + ASSERT (func (BASE "link1", &st1) == 0); + ASSERT (S_ISLNK (st1.st_mode)); + ASSERT (func (BASE "link1/", &st1) == 0); + ASSERT (stat (BASE "link1", &st2) == 0); + ASSERT (S_ISDIR (st1.st_mode)); + ASSERT (S_ISDIR (st2.st_mode)); + ASSERT (SAME_INODE (st1, st2)); + + ASSERT (func (BASE "link2", &st1) == 0); + ASSERT (S_ISLNK (st1.st_mode)); + errno = 0; + ASSERT (func (BASE "link2/", &st1) == -1); + ASSERT (errno == ENOTDIR); + + ASSERT (func (BASE "link3", &st1) == 0); + ASSERT (S_ISLNK (st1.st_mode)); + errno = 0; + ASSERT (func (BASE "link3/", &st1) == -1); + ASSERT (errno == ENOENT); + + ASSERT (func (BASE "link4", &st1) == 0); + ASSERT (S_ISLNK (st1.st_mode)); + errno = 0; + ASSERT (func (BASE "link4/", &st1) == -1); + ASSERT (errno == ELOOP); + + /* Cleanup. */ + ASSERT (unlink (BASE "file") == 0); + ASSERT (unlink (BASE "link1") == 0); + ASSERT (unlink (BASE "link2") == 0); + ASSERT (unlink (BASE "link3") == 0); + ASSERT (unlink (BASE "link4") == 0); + + return 0; +} diff --git a/gl/tests/test-malloc-gnu.c b/gl/tests/test-malloc-gnu.c new file mode 100644 index 0000000000..c2a3d6b66a --- /dev/null +++ b/gl/tests/test-malloc-gnu.c @@ -0,0 +1,29 @@ +/* Test of malloc function. + Copyright (C) 2010-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <stdlib.h> + +int +main () +{ + /* Check that malloc (0) is not a NULL pointer. */ + if (malloc (0) == NULL) + return 1; + + return 0; +} diff --git a/gl/tests/test-malloca.c b/gl/tests/test-malloca.c new file mode 100644 index 0000000000..92c86f206c --- /dev/null +++ b/gl/tests/test-malloca.c @@ -0,0 +1,62 @@ +/* Test of safe automatic memory allocation. + Copyright (C) 2005, 2007, 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2005. */ + +#include <config.h> + +#include "malloca.h" + +#include <stdlib.h> + +static void +do_allocation (int n) +{ + void *ptr = malloca (n); + freea (ptr); + safe_alloca (n); +} + +void (*func) (int) = do_allocation; + +int +main () +{ + int i; + + /* This slows down malloc a lot. */ + unsetenv ("MALLOC_PERTURB_"); + + /* Repeat a lot of times, to make sure there's no memory leak. */ + for (i = 0; i < 50000; i++) + { + /* Try various values. + n = 0 gave a crash on Alpha with gcc-2.5.8. + Some versions of MacOS X have a stack size limit of 512 KB. */ + func (34); + func (134); + func (399); + func (510823); + func (129321); + func (0); + func (4070); + func (4095); + func (1); + func (16582); + } + + return 0; +} diff --git a/gl/tests/test-math.c b/gl/tests/test-math.c new file mode 100644 index 0000000000..8565925f66 --- /dev/null +++ b/gl/tests/test-math.c @@ -0,0 +1,53 @@ +/* Test of <math.h> substitute. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +#include <math.h> + +#ifndef NAN +# error NAN should be defined +choke me +#endif + +#if 0 +/* Check that NAN expands into a constant expression. */ +static float n = NAN; +#endif + +/* Compare two numbers with ==. + This is a separate function because IRIX 6.5 "cc -O" miscompiles an + 'x == x' test. */ +static int +numeric_equal (double x, double y) +{ + return x == y; +} + +int +main (void) +{ + double d = NAN; + double zero = 0.0; + if (numeric_equal (d, d)) + return 1; + d = HUGE_VAL; + if (!numeric_equal (d, 1.0 / zero)) + return 1; + return 0; +} diff --git a/gl/tests/test-open.c b/gl/tests/test-open.c new file mode 100644 index 0000000000..3c5b2abdbb --- /dev/null +++ b/gl/tests/test-open.c @@ -0,0 +1,41 @@ +/* Test of opening a file descriptor. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +#include <fcntl.h> + +#include "signature.h" +SIGNATURE_CHECK (open, int, (char const *, int, ...)); + +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> + +#include "macros.h" + +#define BASE "test-open.t" + +#include "test-open.h" + +int +main (void) +{ + return test_open (open, true); +} diff --git a/gl/tests/test-open.h b/gl/tests/test-open.h new file mode 100644 index 0000000000..2ba5d137bf --- /dev/null +++ b/gl/tests/test-open.h @@ -0,0 +1,93 @@ +/* Test of opening a file descriptor. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +/* This file is designed to test both open(n,buf[,mode]) and + openat(AT_FDCWD,n,buf[,mode]). FUNC is the function to test. + Assumes that BASE and ASSERT are already defined, and that + appropriate headers are already included. If PRINT, warn before + skipping symlink tests with status 77. */ + +static int +test_open (int (*func) (char const *, int, ...), bool print) +{ + int fd; + /* Remove anything from prior partial run. */ + unlink (BASE "file"); + + /* Cannot create directory. */ + errno = 0; + ASSERT (func ("nonexist.ent/", O_CREAT | O_RDONLY, 0600) == -1); + ASSERT (errno == ENOTDIR || errno == EISDIR || errno == ENOENT + || errno == EINVAL); + + /* Create a regular file. */ + fd = func (BASE "file", O_CREAT | O_RDONLY, 0600); + ASSERT (0 <= fd); + ASSERT (close (fd) == 0); + + /* Trailing slash handling. */ + errno = 0; + ASSERT (func (BASE "file/", O_RDONLY) == -1); + ASSERT (errno == ENOTDIR || errno == EISDIR || errno == EINVAL); + + /* Directories cannot be opened for writing. */ + errno = 0; + ASSERT (func (".", O_WRONLY) == -1); + ASSERT (errno == EISDIR || errno == EACCES); + + /* /dev/null must exist, and be writable. */ + fd = func ("/dev/null", O_RDONLY); + ASSERT (0 <= fd); + { + char c; + ASSERT (read (fd, &c, 1) == 0); + } + ASSERT (close (fd) == 0); + fd = func ("/dev/null", O_WRONLY); + ASSERT (0 <= fd); + ASSERT (write (fd, "c", 1) == 1); + ASSERT (close (fd) == 0); + + /* Although O_NONBLOCK on regular files can be ignored, it must not + cause a failure. */ + fd = func (BASE "file", O_NONBLOCK | O_RDONLY); + ASSERT (0 <= fd); + ASSERT (close (fd) == 0); + + /* Symlink handling, where supported. */ + if (symlink (BASE "file", BASE "link") != 0) + { + ASSERT (unlink (BASE "file") == 0); + if (print) + fputs ("skipping test: symlinks not supported on this file system\n", + stderr); + return 77; + } + errno = 0; + ASSERT (func (BASE "link/", O_RDONLY) == -1); + ASSERT (errno == ENOTDIR); + fd = func (BASE "link", O_RDONLY); + ASSERT (0 <= fd); + ASSERT (close (fd) == 0); + + /* Cleanup. */ + ASSERT (unlink (BASE "file") == 0); + ASSERT (unlink (BASE "link") == 0); + + return 0; +} diff --git a/gl/tests/test-printf-frexp.c b/gl/tests/test-printf-frexp.c new file mode 100644 index 0000000000..d1b0d846f7 --- /dev/null +++ b/gl/tests/test-printf-frexp.c @@ -0,0 +1,119 @@ +/* Test of splitting a double into fraction and mantissa. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +#include "printf-frexp.h" + +#include <float.h> + +#include "macros.h" + +static double +my_ldexp (double x, int d) +{ + for (; d > 0; d--) + x *= 2.0; + for (; d < 0; d++) + x *= 0.5; + return x; +} + +int +main () +{ + int i; + /* The use of 'volatile' guarantees that excess precision bits are dropped + when dealing with denormalized numbers. It is necessary on x86 systems + where double-floats are not IEEE compliant by default, to avoid that the + results become platform and compiler option dependent. 'volatile' is a + portable alternative to gcc's -ffloat-store option. */ + volatile double x; + + for (i = 1, x = 1.0; i <= DBL_MAX_EXP; i++, x *= 2.0) + { + int exp = -9999; + double mantissa = printf_frexp (x, &exp); + ASSERT (exp == i - 1); + ASSERT (mantissa == 1.0); + } + for (i = 1, x = 1.0; i >= DBL_MIN_EXP; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = printf_frexp (x, &exp); + ASSERT (exp == i - 1); + ASSERT (mantissa == 1.0); + } + for (; i >= DBL_MIN_EXP - 100 && x > 0.0; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = printf_frexp (x, &exp); + ASSERT (exp == DBL_MIN_EXP - 1); + ASSERT (mantissa == my_ldexp (1.0, i - DBL_MIN_EXP)); + } + + for (i = 1, x = 1.01; i <= DBL_MAX_EXP; i++, x *= 2.0) + { + int exp = -9999; + double mantissa = printf_frexp (x, &exp); + ASSERT (exp == i - 1); + ASSERT (mantissa == 1.01); + } + for (i = 1, x = 1.01; i >= DBL_MIN_EXP; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = printf_frexp (x, &exp); + ASSERT (exp == i - 1); + ASSERT (mantissa == 1.01); + } + for (; i >= DBL_MIN_EXP - 100 && x > 0.0; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = printf_frexp (x, &exp); + ASSERT (exp == DBL_MIN_EXP - 1); + ASSERT (mantissa >= my_ldexp (1.0, i - DBL_MIN_EXP)); + ASSERT (mantissa <= my_ldexp (2.0, i - DBL_MIN_EXP)); + ASSERT (mantissa == my_ldexp (x, - exp)); + } + + for (i = 1, x = 1.73205; i <= DBL_MAX_EXP; i++, x *= 2.0) + { + int exp = -9999; + double mantissa = printf_frexp (x, &exp); + ASSERT (exp == i - 1); + ASSERT (mantissa == 1.73205); + } + for (i = 1, x = 1.73205; i >= DBL_MIN_EXP; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = printf_frexp (x, &exp); + ASSERT (exp == i - 1); + ASSERT (mantissa == 1.73205); + } + for (; i >= DBL_MIN_EXP - 100 && x > 0.0; i--, x *= 0.5) + { + int exp = -9999; + double mantissa = printf_frexp (x, &exp); + ASSERT (exp == DBL_MIN_EXP - 1); + ASSERT (mantissa >= my_ldexp (1.0, i - DBL_MIN_EXP)); + ASSERT (mantissa <= my_ldexp (2.0, i - DBL_MIN_EXP)); + ASSERT (mantissa == my_ldexp (x, - exp)); + } + + return 0; +} diff --git a/gl/tests/test-printf-frexpl.c b/gl/tests/test-printf-frexpl.c new file mode 100644 index 0000000000..4e9704f977 --- /dev/null +++ b/gl/tests/test-printf-frexpl.c @@ -0,0 +1,134 @@ +/* Test of splitting a 'long double' into fraction and mantissa. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +#include "printf-frexpl.h" + +#include <float.h> + +#include "fpucw.h" +#include "macros.h" + +/* On MIPS IRIX machines, LDBL_MIN_EXP is -1021, but the smallest reliable + exponent for 'long double' is -964. Similarly, on PowerPC machines, + LDBL_MIN_EXP is -1021, but the smallest reliable exponent for 'long double' + is -968. For exponents below that, the precision may be truncated to the + precision used for 'double'. */ +#ifdef __sgi +# define MIN_NORMAL_EXP (LDBL_MIN_EXP + 57) +# define MIN_SUBNORMAL_EXP MIN_NORMAL_EXP +#elif defined __ppc || defined __ppc__ || defined __powerpc || defined __powerpc__ +# define MIN_NORMAL_EXP (LDBL_MIN_EXP + 53) +# define MIN_SUBNORMAL_EXP MIN_NORMAL_EXP +#else +# define MIN_NORMAL_EXP LDBL_MIN_EXP +# define MIN_SUBNORMAL_EXP (LDBL_MIN_EXP - 100) +#endif + +static long double +my_ldexp (long double x, int d) +{ + for (; d > 0; d--) + x *= 2.0L; + for (; d < 0; d++) + x *= 0.5L; + return x; +} + +int +main () +{ + int i; + long double x; + DECL_LONG_DOUBLE_ROUNDING + + BEGIN_LONG_DOUBLE_ROUNDING (); + + for (i = 1, x = 1.0L; i <= LDBL_MAX_EXP; i++, x *= 2.0L) + { + int exp = -9999; + long double mantissa = printf_frexpl (x, &exp); + ASSERT (exp == i - 1); + ASSERT (mantissa == 1.0L); + } + for (i = 1, x = 1.0L; i >= MIN_NORMAL_EXP; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = printf_frexpl (x, &exp); + ASSERT (exp == i - 1); + ASSERT (mantissa == 1.0L); + } + for (; i >= MIN_SUBNORMAL_EXP && x > 0.0L; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = printf_frexpl (x, &exp); + ASSERT (exp == LDBL_MIN_EXP - 1); + ASSERT (mantissa == my_ldexp (1.0L, i - LDBL_MIN_EXP)); + } + + for (i = 1, x = 1.01L; i <= LDBL_MAX_EXP; i++, x *= 2.0L) + { + int exp = -9999; + long double mantissa = printf_frexpl (x, &exp); + ASSERT (exp == i - 1); + ASSERT (mantissa == 1.01L); + } + for (i = 1, x = 1.01L; i >= MIN_NORMAL_EXP; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = printf_frexpl (x, &exp); + ASSERT (exp == i - 1); + ASSERT (mantissa == 1.01L); + } + for (; i >= MIN_SUBNORMAL_EXP && x > 0.0L; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = printf_frexpl (x, &exp); + ASSERT (exp == LDBL_MIN_EXP - 1); + ASSERT (mantissa >= my_ldexp (1.0L, i - LDBL_MIN_EXP)); + ASSERT (mantissa <= my_ldexp (2.0L, i - LDBL_MIN_EXP)); + ASSERT (mantissa == my_ldexp (x, - exp)); + } + + for (i = 1, x = 1.73205L; i <= LDBL_MAX_EXP; i++, x *= 2.0L) + { + int exp = -9999; + long double mantissa = printf_frexpl (x, &exp); + ASSERT (exp == i - 1); + ASSERT (mantissa == 1.73205L); + } + for (i = 1, x = 1.73205L; i >= MIN_NORMAL_EXP; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = printf_frexpl (x, &exp); + ASSERT (exp == i - 1); + ASSERT (mantissa == 1.73205L); + } + for (; i >= MIN_SUBNORMAL_EXP && x > 0.0L; i--, x *= 0.5L) + { + int exp = -9999; + long double mantissa = printf_frexpl (x, &exp); + ASSERT (exp == LDBL_MIN_EXP - 1); + ASSERT (mantissa >= my_ldexp (1.0L, i - LDBL_MIN_EXP)); + ASSERT (mantissa <= my_ldexp (2.0L, i - LDBL_MIN_EXP)); + ASSERT (mantissa == my_ldexp (x, - exp)); + } + + return 0; +} diff --git a/gl/tests/test-printf-posix.h b/gl/tests/test-printf-posix.h new file mode 100644 index 0000000000..73365a5b9d --- /dev/null +++ b/gl/tests/test-printf-posix.h @@ -0,0 +1,153 @@ +/* Test of POSIX compatible vsprintf() and sprintf() functions. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +static void +test_function (int (*my_printf) (const char *, ...)) +{ + /* Here we don't test output that may be platform dependent. + The bulk of the tests is done as part of the 'vasnprintf-posix' module. */ + + /* Test support of size specifiers as in C99. */ + + my_printf ("%ju %d\n", (uintmax_t) 12345671, 33, 44, 55); + + my_printf ("%zu %d\n", (size_t) 12345672, 33, 44, 55); + + my_printf ("%tu %d\n", (ptrdiff_t) 12345673, 33, 44, 55); + + /* Test the support of the 'a' and 'A' conversion specifier for hexadecimal + output of floating-point numbers. */ + + /* Positive zero. */ + my_printf ("%a %d\n", 0.0, 33, 44, 55); + + /* Positive infinity. */ + my_printf ("%a %d\n", 1.0 / 0.0, 33, 44, 55); + + /* Negative infinity. */ + my_printf ("%a %d\n", -1.0 / 0.0, 33, 44, 55); + + /* FLAG_ZERO with infinite number. */ + /* "0000000inf 33" is not a valid result; see + <http://lists.gnu.org/archive/html/bug-gnulib/2007-04/msg00107.html> */ + my_printf ("%010a %d\n", 1.0 / 0.0, 33, 44, 55); + + /* Test the support of the %f format directive. */ + + /* A positive number. */ + my_printf ("%f %d\n", 12.75, 33, 44, 55); + + /* A larger positive number. */ + my_printf ("%f %d\n", 1234567.0, 33, 44, 55); + + /* A negative number. */ + my_printf ("%f %d\n", -0.03125, 33, 44, 55); + + /* Positive zero. */ + my_printf ("%f %d\n", 0.0, 33, 44, 55); + + /* FLAG_ZERO. */ + my_printf ("%015f %d\n", 1234.0, 33, 44, 55); + + /* Precision. */ + my_printf ("%.f %d\n", 1234.0, 33, 44, 55); + + /* Precision with no rounding. */ + my_printf ("%.2f %d\n", 999.95, 33, 44, 55); + + /* Precision with rounding. */ + my_printf ("%.2f %d\n", 999.996, 33, 44, 55); + + /* A positive number. */ + my_printf ("%Lf %d\n", 12.75L, 33, 44, 55); + + /* A larger positive number. */ + my_printf ("%Lf %d\n", 1234567.0L, 33, 44, 55); + + /* A negative number. */ + my_printf ("%Lf %d\n", -0.03125L, 33, 44, 55); + + /* Positive zero. */ + my_printf ("%Lf %d\n", 0.0L, 33, 44, 55); + + /* FLAG_ZERO. */ + my_printf ("%015Lf %d\n", 1234.0L, 33, 44, 55); + + /* Precision. */ + my_printf ("%.Lf %d\n", 1234.0L, 33, 44, 55); + + /* Precision with no rounding. */ + my_printf ("%.2Lf %d\n", 999.95L, 33, 44, 55); + + /* Precision with rounding. */ + my_printf ("%.2Lf %d\n", 999.996L, 33, 44, 55); + + /* Test the support of the %F format directive. */ + + /* A positive number. */ + my_printf ("%F %d\n", 12.75, 33, 44, 55); + + /* A larger positive number. */ + my_printf ("%F %d\n", 1234567.0, 33, 44, 55); + + /* A negative number. */ + my_printf ("%F %d\n", -0.03125, 33, 44, 55); + + /* Positive zero. */ + my_printf ("%F %d\n", 0.0, 33, 44, 55); + + /* FLAG_ZERO. */ + my_printf ("%015F %d\n", 1234.0, 33, 44, 55); + + /* Precision. */ + my_printf ("%.F %d\n", 1234.0, 33, 44, 55); + + /* Precision with no rounding. */ + my_printf ("%.2F %d\n", 999.95, 33, 44, 55); + + /* Precision with rounding. */ + my_printf ("%.2F %d\n", 999.996, 33, 44, 55); + + /* A positive number. */ + my_printf ("%LF %d\n", 12.75L, 33, 44, 55); + + /* A larger positive number. */ + my_printf ("%LF %d\n", 1234567.0L, 33, 44, 55); + + /* A negative number. */ + my_printf ("%LF %d\n", -0.03125L, 33, 44, 55); + + /* Positive zero. */ + my_printf ("%LF %d\n", 0.0L, 33, 44, 55); + + /* FLAG_ZERO. */ + my_printf ("%015LF %d\n", 1234.0L, 33, 44, 55); + + /* Precision. */ + my_printf ("%.LF %d\n", 1234.0L, 33, 44, 55); + + /* Precision with no rounding. */ + my_printf ("%.2LF %d\n", 999.95L, 33, 44, 55); + + /* Precision with rounding. */ + my_printf ("%.2LF %d\n", 999.996L, 33, 44, 55); + + /* Test the support of the POSIX/XSI format strings with positions. */ + + my_printf ("%2$d %1$d\n", 33, 55); +} diff --git a/gl/tests/test-printf-posix.output b/gl/tests/test-printf-posix.output new file mode 100644 index 0000000000..618825bb7b --- /dev/null +++ b/gl/tests/test-printf-posix.output @@ -0,0 +1,40 @@ +12345671 33 +12345672 33 +12345673 33 +0x0p+0 33 +inf 33 +-inf 33 + inf 33 +12.750000 33 +1234567.000000 33 +-0.031250 33 +0.000000 33 +00001234.000000 33 +1234 33 +999.95 33 +1000.00 33 +12.750000 33 +1234567.000000 33 +-0.031250 33 +0.000000 33 +00001234.000000 33 +1234 33 +999.95 33 +1000.00 33 +12.750000 33 +1234567.000000 33 +-0.031250 33 +0.000000 33 +00001234.000000 33 +1234 33 +999.95 33 +1000.00 33 +12.750000 33 +1234567.000000 33 +-0.031250 33 +0.000000 33 +00001234.000000 33 +1234 33 +999.95 33 +1000.00 33 +55 33 diff --git a/gl/tests/test-rawmemchr.c b/gl/tests/test-rawmemchr.c new file mode 100644 index 0000000000..be8feacf9b --- /dev/null +++ b/gl/tests/test-rawmemchr.c @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2008-2011 Free Software Foundation, Inc. + * Written by Eric Blake and Bruno Haible + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <string.h> + +#include "signature.h" +SIGNATURE_CHECK (rawmemchr, void *, (void const *, int)); + +#include <stdlib.h> + +#include "zerosize-ptr.h" +#include "macros.h" + +/* Calculating void * + int is not portable, so this wrapper converts + to char * to make the tests easier to write. */ +#define RAWMEMCHR (char *) rawmemchr + +int +main (void) +{ + size_t n = 0x100000; + char *input = malloc (n + 1); + ASSERT (input); + + input[0] = 'a'; + input[1] = 'b'; + memset (input + 2, 'c', 1024); + memset (input + 1026, 'd', n - 1028); + input[n - 2] = 'e'; + input[n - 1] = 'a'; + input[n] = '\0'; + + /* Basic behavior tests. */ + ASSERT (RAWMEMCHR (input, 'a') == input); + ASSERT (RAWMEMCHR (input, 'b') == input + 1); + ASSERT (RAWMEMCHR (input, 'c') == input + 2); + ASSERT (RAWMEMCHR (input, 'd') == input + 1026); + + ASSERT (RAWMEMCHR (input + 1, 'a') == input + n - 1); + ASSERT (RAWMEMCHR (input + 1, 'e') == input + n - 2); + ASSERT (RAWMEMCHR (input + 1, 0x789abc00 | 'e') == input + n - 2); + + ASSERT (RAWMEMCHR (input, '\0') == input + n); + + /* Alignment tests. */ + { + int i, j; + for (i = 0; i < 32; i++) + { + for (j = 0; j < 256; j++) + input[i + j] = j; + for (j = 0; j < 256; j++) + { + ASSERT (RAWMEMCHR (input + i, j) == input + i + j); + } + } + } + + /* Ensure that no unaligned oversized reads occur. */ + { + char *page_boundary = (char *) zerosize_ptr (); + size_t i; + + if (!page_boundary) + page_boundary = input + 4096; + memset (page_boundary - 512, '1', 511); + page_boundary[-1] = '2'; + for (i = 1; i <= 512; i++) + ASSERT (RAWMEMCHR (page_boundary - i, (i * 0x01010100) | '2') + == page_boundary - 1); + } + + free (input); + + return 0; +} diff --git a/gl/tests/test-setenv.c b/gl/tests/test-setenv.c new file mode 100644 index 0000000000..50eb71b3d2 --- /dev/null +++ b/gl/tests/test-setenv.c @@ -0,0 +1,56 @@ +/* Tests of setenv. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <ebb9@byu.net>, 2009. */ + +#include <config.h> + +#include <stdlib.h> + +#include "signature.h" +SIGNATURE_CHECK (setenv, int, (char const *, char const *, int)); + +#include <errno.h> +#include <string.h> +#include <unistd.h> + +#include "macros.h" + +int +main (void) +{ + /* Test overwriting. */ + ASSERT (setenv ("a", "==", -1) == 0); + ASSERT (setenv ("a", "2", 0) == 0); + ASSERT (strcmp (getenv ("a"), "==") == 0); + + /* Required to fail with EINVAL. */ + errno = 0; + ASSERT (setenv ("", "", 1) == -1); + ASSERT (errno == EINVAL); + errno = 0; + ASSERT (setenv ("a=b", "", 0) == -1); + ASSERT (errno == EINVAL); +#if 0 + /* glibc and gnulib's implementation guarantee this, but POSIX no + longer requires it: http://austingroupbugs.net/view.php?id=185 */ + errno = 0; + ASSERT (setenv (NULL, "", 0) == -1); + ASSERT (errno == EINVAL); +#endif + + return 0; +} diff --git a/gl/tests/test-signbit.c b/gl/tests/test-signbit.c new file mode 100644 index 0000000000..c8981498a1 --- /dev/null +++ b/gl/tests/test-signbit.c @@ -0,0 +1,176 @@ +/* Test of signbit() substitute. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +#include <math.h> + +/* signbit must be a macro. */ +#ifndef signbit +# error missing declaration +#endif + +#include <float.h> +#include <limits.h> + +#include "minus-zero.h" +#include "macros.h" + +float zerof = 0.0f; +double zerod = 0.0; +long double zerol = 0.0L; + +static void +test_signbitf () +{ + /* Finite values. */ + ASSERT (!signbit (3.141f)); + ASSERT (!signbit (3.141e30f)); + ASSERT (!signbit (3.141e-30f)); + ASSERT (signbit (-2.718f)); + ASSERT (signbit (-2.718e30f)); + ASSERT (signbit (-2.718e-30f)); + /* Zeros. */ + ASSERT (!signbit (0.0f)); + if (1.0f / minus_zerof < 0) + ASSERT (signbit (minus_zerof)); + else + ASSERT (!signbit (minus_zerof)); + /* Infinite values. */ + ASSERT (!signbit (1.0f / 0.0f)); + ASSERT (signbit (-1.0f / 0.0f)); + /* Quiet NaN. */ + (void) signbit (zerof / zerof); +#if defined FLT_EXPBIT0_WORD && defined FLT_EXPBIT0_BIT + /* Signalling NaN. */ + { + #define NWORDS \ + ((sizeof (float) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + typedef union { float value; unsigned int word[NWORDS]; } memory_float; + memory_float m; + m.value = zerof / zerof; +# if FLT_EXPBIT0_BIT > 0 + m.word[FLT_EXPBIT0_WORD] ^= (unsigned int) 1 << (FLT_EXPBIT0_BIT - 1); +# else + m.word[FLT_EXPBIT0_WORD + (FLT_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + ^= (unsigned int) 1 << (sizeof (unsigned int) * CHAR_BIT - 1); +# endif + if (FLT_EXPBIT0_WORD < NWORDS / 2) + m.word[FLT_EXPBIT0_WORD + 1] |= (unsigned int) 1 << FLT_EXPBIT0_BIT; + else + m.word[0] |= (unsigned int) 1; + (void) signbit (m.value); + #undef NWORDS + } +#endif +} + +static void +test_signbitd () +{ + /* Finite values. */ + ASSERT (!signbit (3.141)); + ASSERT (!signbit (3.141e30)); + ASSERT (!signbit (3.141e-30)); + ASSERT (signbit (-2.718)); + ASSERT (signbit (-2.718e30)); + ASSERT (signbit (-2.718e-30)); + /* Zeros. */ + ASSERT (!signbit (0.0)); + if (1.0 / minus_zerod < 0) + ASSERT (signbit (minus_zerod)); + else + ASSERT (!signbit (minus_zerod)); + /* Infinite values. */ + ASSERT (!signbit (1.0 / 0.0)); + ASSERT (signbit (-1.0 / 0.0)); + /* Quiet NaN. */ + (void) signbit (zerod / zerod); +#if defined DBL_EXPBIT0_WORD && defined DBL_EXPBIT0_BIT + /* Signalling NaN. */ + { + #define NWORDS \ + ((sizeof (double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + typedef union { double value; unsigned int word[NWORDS]; } memory_double; + memory_double m; + m.value = zerod / zerod; +# if DBL_EXPBIT0_BIT > 0 + m.word[DBL_EXPBIT0_WORD] ^= (unsigned int) 1 << (DBL_EXPBIT0_BIT - 1); +# else + m.word[DBL_EXPBIT0_WORD + (DBL_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + ^= (unsigned int) 1 << (sizeof (unsigned int) * CHAR_BIT - 1); +# endif + m.word[DBL_EXPBIT0_WORD + (DBL_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + |= (unsigned int) 1 << DBL_EXPBIT0_BIT; + (void) signbit (m.value); + #undef NWORDS + } +#endif +} + +static void +test_signbitl () +{ + /* Finite values. */ + ASSERT (!signbit (3.141L)); + ASSERT (!signbit (3.141e30L)); + ASSERT (!signbit (3.141e-30L)); + ASSERT (signbit (-2.718L)); + ASSERT (signbit (-2.718e30L)); + ASSERT (signbit (-2.718e-30L)); + /* Zeros. */ + ASSERT (!signbit (0.0L)); + if (1.0L / minus_zerol < 0) + ASSERT (signbit (minus_zerol)); + else + ASSERT (!signbit (minus_zerol)); + /* Infinite values. */ + ASSERT (!signbit (1.0L / 0.0L)); + ASSERT (signbit (-1.0L / 0.0L)); + /* Quiet NaN. */ + (void) signbit (zerol / zerol); +#if defined LDBL_EXPBIT0_WORD && defined LDBL_EXPBIT0_BIT + /* Signalling NaN. */ + { + #define NWORDS \ + ((sizeof (long double) + sizeof (unsigned int) - 1) / sizeof (unsigned int)) + typedef union { long double value; unsigned int word[NWORDS]; } memory_long_double; + memory_long_double m; + m.value = zerol / zerol; +# if LDBL_EXPBIT0_BIT > 0 + m.word[LDBL_EXPBIT0_WORD] ^= (unsigned int) 1 << (LDBL_EXPBIT0_BIT - 1); +# else + m.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + ^= (unsigned int) 1 << (sizeof (unsigned int) * CHAR_BIT - 1); +# endif + m.word[LDBL_EXPBIT0_WORD + (LDBL_EXPBIT0_WORD < NWORDS / 2 ? 1 : - 1)] + |= (unsigned int) 1 << LDBL_EXPBIT0_BIT; + (void) signbit (m.value); + #undef NWORDS + } +#endif +} + +int +main () +{ + test_signbitf (); + test_signbitd (); + test_signbitl (); + return 0; +} diff --git a/gl/tests/test-sleep.c b/gl/tests/test-sleep.c new file mode 100644 index 0000000000..3550e2b0f5 --- /dev/null +++ b/gl/tests/test-sleep.c @@ -0,0 +1,58 @@ +/* Test of sleep() function. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +#include <unistd.h> + +#include "signature.h" +SIGNATURE_CHECK (sleep, unsigned int, (unsigned int)); + +#include <signal.h> + +#include "macros.h" + +#if HAVE_DECL_ALARM +static void +handle_alarm (int sig) +{ + if (sig != SIGALRM) + _exit (1); +} +#endif + +int +main (void) +{ + ASSERT (sleep (1) <= 1); + + ASSERT (sleep (0) == 0); + +#if HAVE_DECL_ALARM + { + const unsigned int pentecost = 50 * 24 * 60 * 60; /* 50 days. */ + unsigned int remaining; + signal (SIGALRM, handle_alarm); + alarm (1); + remaining = sleep (pentecost); + ASSERT (pentecost - 10 < remaining && remaining <= pentecost); + } +#endif + + return 0; +} diff --git a/gl/tests/test-stat.c b/gl/tests/test-stat.c new file mode 100644 index 0000000000..cd74491f05 --- /dev/null +++ b/gl/tests/test-stat.c @@ -0,0 +1,55 @@ +/* Tests of stat. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <ebb9@byu.net>, 2009. */ + +#include <config.h> + +#include <sys/stat.h> + +/* Caution: stat may be a function-like macro. Although this + signature check must pass, it may be the signature of the real (and + broken) stat rather than rpl_stat. Most code should not use the + address of stat. */ +#include "signature.h" +SIGNATURE_CHECK (stat, int, (char const *, struct stat *)); + +#include <fcntl.h> +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> + +#include "same-inode.h" +#include "macros.h" + +#define BASE "test-stat.t" + +#include "test-stat.h" + +/* Wrapper around stat, which works even if stat is a function-like + macro, where test_stat_func(stat) would do the wrong thing. */ +static int +do_stat (char const *name, struct stat *st) +{ + return stat (name, st); +} + +int +main (void) +{ + return test_stat_func (do_stat, true); +} diff --git a/gl/tests/test-stat.h b/gl/tests/test-stat.h new file mode 100644 index 0000000000..3c8f7add0f --- /dev/null +++ b/gl/tests/test-stat.h @@ -0,0 +1,100 @@ +/* Tests of stat. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <ebb9@byu.net>, 2009. */ + +/* This file is designed to test both stat(n,buf) and + fstatat(AT_FDCWD,n,buf,0). FUNC is the function to test. Assumes + that BASE and ASSERT are already defined, and that appropriate + headers are already included. If PRINT, warn before skipping + symlink tests with status 77. */ + +static int +test_stat_func (int (*func) (char const *, struct stat *), bool print) +{ + struct stat st1; + struct stat st2; + char *cwd = getcwd (NULL, 0); + + ASSERT (cwd); + ASSERT (func (".", &st1) == 0); + ASSERT (func ("./", &st2) == 0); + ASSERT (SAME_INODE (st1, st2)); + ASSERT (func (cwd, &st2) == 0); + ASSERT (SAME_INODE (st1, st2)); + ASSERT (func ("/", &st1) == 0); + ASSERT (func ("///", &st2) == 0); + ASSERT (SAME_INODE (st1, st2)); + + errno = 0; + ASSERT (func ("", &st1) == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (func ("nosuch", &st1) == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (func ("nosuch/", &st1) == -1); + ASSERT (errno == ENOENT); + + ASSERT (close (creat (BASE "file", 0600)) == 0); + ASSERT (func (BASE "file", &st1) == 0); + errno = 0; + ASSERT (func (BASE "file/", &st1) == -1); + ASSERT (errno == ENOTDIR); + + /* Now for some symlink tests, where supported. We set up: + link1 -> directory + link2 -> file + link3 -> dangling + link4 -> loop + then test behavior with trailing slash. + */ + if (symlink (".", BASE "link1") != 0) + { + ASSERT (unlink (BASE "file") == 0); + if (print) + fputs ("skipping test: symlinks not supported on this file system\n", + stderr); + return 77; + } + ASSERT (symlink (BASE "file", BASE "link2") == 0); + ASSERT (symlink (BASE "nosuch", BASE "link3") == 0); + ASSERT (symlink (BASE "link4", BASE "link4") == 0); + + ASSERT (func (BASE "link1/", &st1) == 0); + ASSERT (S_ISDIR (st1.st_mode)); + + errno = 0; + ASSERT (func (BASE "link2/", &st1) == -1); + ASSERT (errno == ENOTDIR); + + errno = 0; + ASSERT (func (BASE "link3/", &st1) == -1); + ASSERT (errno == ENOENT); + + errno = 0; + ASSERT (func (BASE "link4/", &st1) == -1); + ASSERT (errno == ELOOP); + + /* Cleanup. */ + ASSERT (unlink (BASE "file") == 0); + ASSERT (unlink (BASE "link1") == 0); + ASSERT (unlink (BASE "link2") == 0); + ASSERT (unlink (BASE "link3") == 0); + ASSERT (unlink (BASE "link4") == 0); + + return 0; +} diff --git a/gl/tests/test-strchrnul.c b/gl/tests/test-strchrnul.c new file mode 100644 index 0000000000..6ea8adc312 --- /dev/null +++ b/gl/tests/test-strchrnul.c @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2008-2011 Free Software Foundation, Inc. + * Written by Eric Blake and Bruno Haible + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <string.h> + +#include "signature.h" +SIGNATURE_CHECK (strchrnul, char *, (char const *, int)); + +#include <stdlib.h> + +#include "macros.h" + +int +main (void) +{ + size_t n = 0x100000; + char *input = malloc (n + 1); + ASSERT (input); + + input[0] = 'a'; + input[1] = 'b'; + memset (input + 2, 'c', 1024); + memset (input + 1026, 'd', n - 1028); + input[n - 2] = 'e'; + input[n - 1] = 'a'; + input[n] = '\0'; + + /* Basic behavior tests. */ + ASSERT (strchrnul (input, 'a') == input); + ASSERT (strchrnul (input, 'b') == input + 1); + ASSERT (strchrnul (input, 'c') == input + 2); + ASSERT (strchrnul (input, 'd') == input + 1026); + + ASSERT (strchrnul (input + 1, 'a') == input + n - 1); + ASSERT (strchrnul (input + 1, 'e') == input + n - 2); + + ASSERT (strchrnul (input, 'f') == input + n); + ASSERT (strchrnul (input, '\0') == input + n); + + /* Check that a very long haystack is handled quickly if the byte is + found near the beginning. */ + { + size_t repeat = 10000; + for (; repeat > 0; repeat--) + { + ASSERT (strchrnul (input, 'c') == input + 2); + } + } + + /* Alignment tests. */ + { + int i, j; + for (i = 0; i < 32; i++) + { + for (j = 0; j < 256; j++) + input[i + j] = (j + 1) & 0xff; + for (j = 1; j < 256; j++) + { + ASSERT (strchrnul (input + i, j) == input + i + j - 1); + input[i + j - 1] = (j == 1 ? 2 : 1); + ASSERT (strchrnul (input + i, j) == input + i + 255); + input[i + j - 1] = j; + } + } + } + + free (input); + + return 0; +} diff --git a/gl/tests/test-strnlen.c b/gl/tests/test-strnlen.c new file mode 100644 index 0000000000..18d6fcdbeb --- /dev/null +++ b/gl/tests/test-strnlen.c @@ -0,0 +1,68 @@ +/* + * Copyright (C) 2010-2011 Free Software Foundation, Inc. + * Written by Eric Blake + * + * This program 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 3 of the License, or + * (at your option) any later version. + * + * 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +#include <string.h> + +#include "signature.h" +SIGNATURE_CHECK (strnlen, size_t, (char const *, size_t)); + +#include <stdlib.h> + +#include "zerosize-ptr.h" +#include "macros.h" + +int +main (void) +{ + size_t i; + char *page_boundary = (char *) zerosize_ptr (); + if (!page_boundary) + { + page_boundary = malloc (0x1000); + ASSERT (page_boundary); + page_boundary += 0x1000; + } + + /* Basic behavior tests. */ + ASSERT (strnlen ("a", 0) == 0); + ASSERT (strnlen ("a", 1) == 1); + ASSERT (strnlen ("a", 2) == 1); + ASSERT (strnlen ("", 0x100000) == 0); + + /* Memory fence and alignment testing. */ + for (i = 0; i < 512; i++) + { + char *start = page_boundary - i; + size_t j = i; + memset (start, 'x', i); + do + { + if (i != j) + { + start[j] = 0; + ASSERT (strnlen (start, i + j) == j); + } + ASSERT (strnlen (start, i) == j); + ASSERT (strnlen (start, j) == j); + } + while (j--); + } + + return 0; +} diff --git a/gl/tests/test-symlink.c b/gl/tests/test-symlink.c new file mode 100644 index 0000000000..367e04541f --- /dev/null +++ b/gl/tests/test-symlink.c @@ -0,0 +1,47 @@ +/* Tests of symlink. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <ebb9@byu.net>, 2009. */ + +#include <config.h> + +#include <unistd.h> + +#include "signature.h" +SIGNATURE_CHECK (symlink, int, (char const *, char const *)); + +#include <fcntl.h> +#include <errno.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/stat.h> + +#include "ignore-value.h" +#include "macros.h" + +#define BASE "test-symlink.t" + +#include "test-symlink.h" + +int +main (void) +{ + /* Remove any leftovers from a previous partial run. */ + ignore_value (system ("rm -rf " BASE "*")); + + return test_symlink (symlink, true); +} diff --git a/gl/tests/test-symlink.h b/gl/tests/test-symlink.h new file mode 100644 index 0000000000..4d9392962d --- /dev/null +++ b/gl/tests/test-symlink.h @@ -0,0 +1,95 @@ +/* Tests of symlink. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <ebb9@byu.net>, 2009. */ + +/* This file is designed to test both symlink(a,b) and + symlinkat(a,AT_FDCWD,b). FUNC is the function to test. Assumes + that BASE and ASSERT are already defined, and that appropriate + headers are already included. If PRINT, warn before skipping + symlink tests with status 77. */ + +static int +test_symlink (int (*func) (char const *, char const *), bool print) +{ + if (func ("nowhere", BASE "link1")) + { + if (print) + fputs ("skipping test: symlinks not supported on this file system\n", + stderr); + return 77; + } + + /* Some systems allow the creation of 0-length symlinks as a synonym + for "."; but most reject it. */ + { + int status; + errno = 0; + status = func ("", BASE "link2"); + if (status == -1) + ASSERT (errno == ENOENT || errno == EINVAL); + else + { + ASSERT (status == 0); + ASSERT (unlink (BASE "link2") == 0); + } + } + + /* Sanity checks of failures. */ + errno = 0; + ASSERT (func ("nowhere", "") == -1); + ASSERT (errno == ENOENT); + errno = 0; + ASSERT (func ("nowhere", ".") == -1); + ASSERT (errno == EEXIST || errno == EINVAL); + errno = 0; + ASSERT (func ("somewhere", BASE "link1") == -1); + ASSERT (errno == EEXIST); + errno = 0; + ASSERT (func ("nowhere", BASE "link2/") == -1); + ASSERT (errno == ENOTDIR || errno == ENOENT); + ASSERT (mkdir (BASE "dir", 0700) == 0); + errno = 0; + ASSERT (func ("nowhere", BASE "dir") == -1); + ASSERT (errno == EEXIST); + errno = 0; + ASSERT (func ("nowhere", BASE "dir/") == -1); + ASSERT (errno == EEXIST || errno == EINVAL); + ASSERT (close (creat (BASE "file", 0600)) == 0); + errno = 0; + ASSERT (func ("nowhere", BASE "file") == -1); + ASSERT (errno == EEXIST); + errno = 0; + ASSERT (func ("nowhere", BASE "file/") == -1); + ASSERT (errno == EEXIST || errno == ENOTDIR || errno == ENOENT); + + /* Trailing slash must always be rejected. */ + ASSERT (unlink (BASE "link1") == 0); + ASSERT (func (BASE "link2", BASE "link1") == 0); + errno = 0; + ASSERT (func (BASE "nowhere", BASE "link1/") == -1); + ASSERT (errno == EEXIST || errno == ENOTDIR || errno == ENOENT); + errno = 0; + ASSERT (unlink (BASE "link2") == -1); + ASSERT (errno == ENOENT); + + /* Cleanup. */ + ASSERT (rmdir (BASE "dir") == 0); + ASSERT (unlink (BASE "file") == 0); + ASSERT (unlink (BASE "link1") == 0); + + return 0; +} diff --git a/gl/tests/test-sysexits.c b/gl/tests/test-sysexits.c new file mode 100644 index 0000000000..0d9a22c41c --- /dev/null +++ b/gl/tests/test-sysexits.c @@ -0,0 +1,52 @@ +/* Test of <sysexits.h> substitute. + Copyright (C) 2007, 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +#include <sysexits.h> + +int exitcode; + +int +main () +{ + /* Check that all EX_* symbols are defined to integer constant expressions + with mutually different values. */ + switch (exitcode) + { + case EX_OK: + case EX_USAGE: + case EX_DATAERR: + case EX_NOINPUT: + case EX_NOUSER: + case EX_NOHOST: + case EX_UNAVAILABLE: + case EX_SOFTWARE: + case EX_OSERR: + case EX_OSFILE: + case EX_CANTCREAT: + case EX_IOERR: + case EX_TEMPFAIL: + case EX_PROTOCOL: + case EX_NOPERM: + case EX_CONFIG: + break; + } + + return 0; +} diff --git a/gl/tests/test-unsetenv.c b/gl/tests/test-unsetenv.c new file mode 100644 index 0000000000..9c9443b89f --- /dev/null +++ b/gl/tests/test-unsetenv.c @@ -0,0 +1,61 @@ +/* Tests of unsetenv. + Copyright (C) 2009-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Eric Blake <ebb9@byu.net>, 2009. */ + +#include <config.h> + +#include <stdlib.h> + +#include "signature.h" +SIGNATURE_CHECK (unsetenv, int, (char const *)); + +#include <errno.h> +#include <string.h> +#include <unistd.h> + +#include "macros.h" + +int +main (void) +{ + char entry[] = "b=2"; + + /* Test removal when multiple entries present. */ + ASSERT (putenv ((char *) "a=1") == 0); + ASSERT (putenv (entry) == 0); + entry[0] = 'a'; /* Unspecified what getenv("a") would be at this point. */ + ASSERT (unsetenv ("a") == 0); /* Both entries will be removed. */ + ASSERT (getenv ("a") == NULL); + ASSERT (unsetenv ("a") == 0); + + /* Required to fail with EINVAL. */ + errno = 0; + ASSERT (unsetenv ("") == -1); + ASSERT (errno == EINVAL); + errno = 0; + ASSERT (unsetenv ("a=b") == -1); + ASSERT (errno == EINVAL); +#if 0 + /* glibc and gnulib's implementation guarantee this, but POSIX no + longer requires it: http://austingroupbugs.net/view.php?id=185 */ + errno = 0; + ASSERT (unsetenv (NULL) == -1); + ASSERT (errno == EINVAL); +#endif + + return 0; +} diff --git a/gl/tests/test-vfprintf-posix.c b/gl/tests/test-vfprintf-posix.c new file mode 100644 index 0000000000..1db31126ed --- /dev/null +++ b/gl/tests/test-vfprintf-posix.c @@ -0,0 +1,52 @@ +/* Test of POSIX compatible vfprintf() function. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +#include <stdio.h> + +#include "signature.h" +SIGNATURE_CHECK (vfprintf, int, (FILE *, char const *, va_list)); + +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include "macros.h" + +#include "test-fprintf-posix.h" + +static int +my_fprintf (FILE *fp, const char *format, ...) +{ + va_list args; + int ret; + + va_start (args, format); + ret = vfprintf (fp, format, args); + va_end (args); + return ret; +} + +int +main (int argc, char *argv[]) +{ + test_function (my_fprintf); + return 0; +} diff --git a/gl/tests/test-vfprintf-posix.sh b/gl/tests/test-vfprintf-posix.sh new file mode 100755 index 0000000000..74339ba080 --- /dev/null +++ b/gl/tests/test-vfprintf-posix.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +tmpfiles="" +trap 'rm -fr $tmpfiles' 1 2 3 15 + +tmpfiles="$tmpfiles t-vfprintf-posix.tmp t-vfprintf-posix.out" +./test-vfprintf-posix${EXEEXT} > t-vfprintf-posix.tmp || exit 1 +LC_ALL=C tr -d '\r' < t-vfprintf-posix.tmp > t-vfprintf-posix.out || exit 1 + +: ${DIFF=diff} +${DIFF} "${srcdir}/test-printf-posix.output" t-vfprintf-posix.out +result=$? + +rm -fr $tmpfiles + +exit $result diff --git a/gl/tests/test-vprintf-posix.c b/gl/tests/test-vprintf-posix.c new file mode 100644 index 0000000000..fcad8af8cb --- /dev/null +++ b/gl/tests/test-vprintf-posix.c @@ -0,0 +1,52 @@ +/* Test of POSIX compatible vfprintf() function. + Copyright (C) 2007-2011 Free Software Foundation, Inc. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +/* Written by Bruno Haible <bruno@clisp.org>, 2007. */ + +#include <config.h> + +#include <stdio.h> + +#include "signature.h" +SIGNATURE_CHECK (vprintf, int, (char const *, va_list)); + +#include <stdarg.h> +#include <stddef.h> +#include <stdint.h> +#include <string.h> + +#include "macros.h" + +#include "test-printf-posix.h" + +static int +my_printf (const char *format, ...) +{ + va_list args; + int ret; + + va_start (args, format); + ret = vprintf (format, args); + va_end (args); + return ret; +} + +int +main (int argc, char *argv[]) +{ + test_function (my_printf); + return 0; +} diff --git a/gl/tests/test-vprintf-posix.sh b/gl/tests/test-vprintf-posix.sh new file mode 100755 index 0000000000..968a8b2a8d --- /dev/null +++ b/gl/tests/test-vprintf-posix.sh @@ -0,0 +1,16 @@ +#!/bin/sh + +tmpfiles="" +trap 'rm -fr $tmpfiles' 1 2 3 15 + +tmpfiles="$tmpfiles t-vprintf-posix.tmp t-vprintf-posix.out" +./test-vprintf-posix${EXEEXT} > t-vprintf-posix.tmp || exit 1 +LC_ALL=C tr -d '\r' < t-vprintf-posix.tmp > t-vprintf-posix.out || exit 1 + +: ${DIFF=diff} +${DIFF} "${srcdir}/test-printf-posix.output" t-vprintf-posix.out +result=$? + +rm -fr $tmpfiles + +exit $result diff --git a/gl/tests/unsetenv.c b/gl/tests/unsetenv.c new file mode 100644 index 0000000000..16b50d15e3 --- /dev/null +++ b/gl/tests/unsetenv.c @@ -0,0 +1,127 @@ +/* Copyright (C) 1992, 1995-2002, 2005-2011 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + This program 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 3 of the License, or + (at your option) any later version. + + 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, see <http://www.gnu.org/licenses/>. */ + +#include <config.h> + +/* Don't use __attribute__ __nonnull__ in this compilation unit. Otherwise gcc + optimizes away the name == NULL test below. */ +#define _GL_ARG_NONNULL(params) + +/* Specification. */ +#include <stdlib.h> + +#include <errno.h> +#if !_LIBC +# define __set_errno(ev) ((errno) = (ev)) +#endif + +#include <string.h> +#include <unistd.h> + +#if !_LIBC +# define __environ environ +#endif + +#if _LIBC +/* This lock protects against simultaneous modifications of `environ'. */ +# include <bits/libc-lock.h> +__libc_lock_define_initialized (static, envlock) +# define LOCK __libc_lock_lock (envlock) +# define UNLOCK __libc_lock_unlock (envlock) +#else +# define LOCK +# define UNLOCK +#endif + +/* In the GNU C library we must keep the namespace clean. */ +#ifdef _LIBC +# define unsetenv __unsetenv +#endif + +#if _LIBC || !HAVE_UNSETENV + +int +unsetenv (const char *name) +{ + size_t len; + char **ep; + + if (name == NULL || *name == '\0' || strchr (name, '=') != NULL) + { + __set_errno (EINVAL); + return -1; + } + + len = strlen (name); + + LOCK; + + ep = __environ; + while (*ep != NULL) + if (!strncmp (*ep, name, len) && (*ep)[len] == '=') + { + /* Found it. Remove this pointer by moving later ones back. */ + char **dp = ep; + + do + dp[0] = dp[1]; + while (*dp++); + /* Continue the loop in case NAME appears again. */ + } + else + ++ep; + + UNLOCK; + + return 0; +} + +#ifdef _LIBC +# undef unsetenv +weak_alias (__unsetenv, unsetenv) +#endif + +#else /* HAVE_UNSETENV */ + +# undef unsetenv +# if !HAVE_DECL_UNSETENV +# if VOID_UNSETENV +extern void unsetenv (const char *); +# else +extern int unsetenv (const char *); +# endif +# endif + +/* Call the underlying unsetenv, in case there is hidden bookkeeping + that needs updating beyond just modifying environ. */ +int +rpl_unsetenv (const char *name) +{ + int result = 0; + if (!name || !*name || strchr (name, '=')) + { + errno = EINVAL; + return -1; + } + while (getenv (name)) +# if !VOID_UNSETENV + result = +# endif + unsetenv (name); + return result; +} + +#endif /* HAVE_UNSETENV */ |