X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Ferror.c;h=31109df3b5fcf5ba6f7bec6d00d63d5bea87b489;hb=1276a2c5f24c0c932426aca9c899fa524d2443f2;hp=16228c413ebcd9ea62e895588911391f7ccac11a;hpb=30a788ee9d00940a28fb8b78da232cd5ade3c505;p=gnulib.git diff --git a/lib/error.c b/lib/error.c index 16228c413..31109df3b 100644 --- a/lib/error.c +++ b/lib/error.c @@ -1,24 +1,23 @@ /* Error handler for noninteractive utilities - Copyright (C) 1990-1998, 2000-2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1990-1998, 2000-2007, 2009-2014 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 + 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 2, or (at your option) - any later version. + 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, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ /* Written by David MacKenzie . */ -#ifdef HAVE_CONFIG_H +#if !_LIBC # include #endif @@ -29,18 +28,20 @@ #include #include -#ifdef _LIBC -# include -#else +#if !_LIBC && ENABLE_NLS # include "gettext.h" +# define _(msgid) gettext (msgid) #endif #ifdef _LIBC +# include +# include +# include # include # define mbsrtowcs __mbsrtowcs #endif -#if !_LIBC +#if USE_UNLOCKED_IO # include "unlocked-io.h" #endif @@ -53,7 +54,7 @@ function without parameters instead. */ void (*error_print_progname) (void); -/* This variable is incremented each time `error' is called. */ +/* This variable is incremented each time 'error' is called. */ unsigned int error_message_count; #ifdef _LIBC @@ -61,15 +62,16 @@ unsigned int error_message_count; # define program_name program_invocation_name # include +# include # include -/* In GNU libc we want do not want to use the common name `error' directly. +/* In GNU libc we want do not want to use the common name 'error' directly. Instead make it a weak alias. */ extern void __error (int status, int errnum, const char *message, ...) __attribute__ ((__format__ (__printf__, 3, 4))); extern void __error_at_line (int status, int errnum, const char *file_name, - unsigned int line_number, const char *message, - ...) + unsigned int line_number, const char *message, + ...) __attribute__ ((__format__ (__printf__, 5, 6)));; # define error __error # define error_at_line __error_at_line @@ -83,25 +85,84 @@ extern void __error_at_line (int status, int errnum, const char *file_name, #else /* not _LIBC */ -# if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P +# include +# include + +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ +/* Get declarations of the native Windows API functions. */ +# define WIN32_LEAN_AND_MEAN +# include +/* Get _get_osfhandle. */ +# include "msvc-nothrow.h" +# endif + +/* The gnulib override of fcntl is not needed in this file. */ +# undef fcntl + +# if !HAVE_DECL_STRERROR_R # ifndef HAVE_DECL_STRERROR_R "this configure-time declaration test was not run" # endif +# if STRERROR_R_CHAR_P char *strerror_r (); +# else +int strerror_r (); +# endif # endif -#ifndef SIZE_MAX -# define SIZE_MAX ((size_t) -1) -#endif - /* The calling program should define program_name and set it to the name of the executing program. */ extern char *program_name; # if HAVE_STRERROR_R || defined strerror_r # define __strerror_r strerror_r +# endif /* HAVE_STRERROR_R || defined strerror_r */ +#endif /* not _LIBC */ + +#if !_LIBC +/* Return non-zero if FD is open. */ +static int +is_open (int fd) +{ +# if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ + /* On native Windows: The initial state of unassigned standard file + descriptors is that they are open but point to an INVALID_HANDLE_VALUE. + There is no fcntl, and the gnulib replacement fcntl does not support + F_GETFL. */ + 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 +} +#endif + +static void +flush_stdout (void) +{ +#if !_LIBC + int stdout_fd; + +# if GNULIB_FREOPEN_SAFER + /* Use of gnulib's freopen-safer module normally ensures that + fileno (stdout) == 1 + whenever stdout is open. */ + stdout_fd = STDOUT_FILENO; +# else + /* POSIX states that fileno (stdout) after fclose is unspecified. But in + practice it is not a problem, because stdout is statically allocated and + the fd of a FILE stream is stored as a field in its allocated memory. */ + stdout_fd = fileno (stdout); # endif -#endif /* not _LIBC */ + /* POSIX states that fflush (stdout) after fclose is unspecified; it + is safe in glibc, but not on all other platforms. fflush (NULL) + is always defined, but too draconian. */ + if (0 <= stdout_fd && is_open (stdout_fd)) +#endif + fflush (stdout); +} static void print_errno_message (int errnum) @@ -128,17 +189,13 @@ print_errno_message (int errnum) #endif #if _LIBC - if (_IO_fwide (stderr, 0) > 0) - { - __fwprintf (stderr, L": %s", s); - return; - } -#endif - + __fxprintf (NULL, ": %s", s); +#else fprintf (stderr, ": %s", s); +#endif } -static void +static void _GL_ATTRIBUTE_FORMAT_PRINTF (3, 0) _GL_ARG_NONNULL ((3)) error_tail (int status, int errnum, const char *message, va_list args) { #if _LIBC @@ -146,26 +203,65 @@ error_tail (int status, int errnum, const char *message, va_list args) { # define ALLOCA_LIMIT 2000 size_t len = strlen (message) + 1; - const wchar_t *wmessage = L"out of memory"; - wchar_t *wbuf = (len < ALLOCA_LIMIT - ? (void *) alloca (len * sizeof *wbuf) - : len <= SIZE_MAX / sizeof *wbuf - ? malloc (len * sizeof *wbuf) - : NULL); - - if (wbuf) - { - size_t res; - mbstate_t st; - const char *tmp = message; - memset (&st, '\0', sizeof (st)); - res = mbsrtowcs (wbuf, &tmp, len, &st); - wmessage = res == (size_t) -1 ? L"???" : wbuf; - } + wchar_t *wmessage = NULL; + mbstate_t st; + size_t res; + const char *tmp; + bool use_malloc = false; + + while (1) + { + if (__libc_use_alloca (len * sizeof (wchar_t))) + wmessage = (wchar_t *) alloca (len * sizeof (wchar_t)); + else + { + if (!use_malloc) + wmessage = NULL; + + wchar_t *p = (wchar_t *) realloc (wmessage, + len * sizeof (wchar_t)); + if (p == NULL) + { + free (wmessage); + fputws_unlocked (L"out of memory\n", stderr); + return; + } + wmessage = p; + use_malloc = true; + } + + memset (&st, '\0', sizeof (st)); + tmp = message; + + res = mbsrtowcs (wmessage, &tmp, len, &st); + if (res != len) + break; + + if (__builtin_expect (len >= SIZE_MAX / 2, 0)) + { + /* This really should not happen if everything is fine. */ + res = (size_t) -1; + break; + } + + len *= 2; + } + + if (res == (size_t) -1) + { + /* The string cannot be converted. */ + if (use_malloc) + { + free (wmessage); + use_malloc = false; + } + wmessage = (wchar_t *) L"???"; + } __vfwprintf (stderr, wmessage, args); - if (! (len < ALLOCA_LIMIT)) - free (wbuf); + + if (use_malloc) + free (wmessage); } else #endif @@ -176,11 +272,10 @@ error_tail (int status, int errnum, const char *message, va_list args) if (errnum) print_errno_message (errnum); #if _LIBC - if (_IO_fwide (stderr, 0) > 0) - putwc (L'\n', stderr); - else + __fxprintf (NULL, "\n"); +#else + putc ('\n', stderr); #endif - putc ('\n', stderr); fflush (stderr); if (status) exit (status); @@ -201,10 +296,10 @@ error (int status, int errnum, const char *message, ...) cancellation. Therefore disable cancellation for now. */ int state = PTHREAD_CANCEL_ENABLE; __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), - 0); + 0); #endif - fflush (stdout); + flush_stdout (); #ifdef _LIBC _IO_flockfile (stderr); #endif @@ -213,11 +308,10 @@ error (int status, int errnum, const char *message, ...) else { #if _LIBC - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s: ", program_name); - else + __fxprintf (NULL, "%s: ", program_name); +#else + fprintf (stderr, "%s: ", program_name); #endif - fprintf (stderr, "%s: ", program_name); } va_start (args, message); @@ -237,7 +331,7 @@ int error_one_per_line; void error_at_line (int status, int errnum, const char *file_name, - unsigned int line_number, const char *message, ...) + unsigned int line_number, const char *message, ...) { va_list args; @@ -247,10 +341,10 @@ error_at_line (int status, int errnum, const char *file_name, static unsigned int old_line_number; if (old_line_number == line_number - && (file_name == old_file_name - || strcmp (old_file_name, file_name) == 0)) - /* Simply return and print nothing. */ - return; + && (file_name == old_file_name + || strcmp (old_file_name, file_name) == 0)) + /* Simply return and print nothing. */ + return; old_file_name = file_name; old_line_number = line_number; @@ -261,10 +355,10 @@ error_at_line (int status, int errnum, const char *file_name, cancellation. Therefore disable cancellation for now. */ int state = PTHREAD_CANCEL_ENABLE; __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), - 0); + 0); #endif - fflush (stdout); + flush_stdout (); #ifdef _LIBC _IO_flockfile (stderr); #endif @@ -273,22 +367,19 @@ error_at_line (int status, int errnum, const char *file_name, else { #if _LIBC - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s: ", program_name); - else + __fxprintf (NULL, "%s:", program_name); +#else + fprintf (stderr, "%s:", program_name); #endif - fprintf (stderr, "%s:", program_name); } - if (file_name != NULL) - { #if _LIBC - if (_IO_fwide (stderr, 0) > 0) - __fwprintf (stderr, L"%s:%d: ", file_name, line_number); - else + __fxprintf (NULL, file_name != NULL ? "%s:%d: " : " ", + file_name, line_number); +#else + fprintf (stderr, file_name != NULL ? "%s:%d: " : " ", + file_name, line_number); #endif - fprintf (stderr, "%s:%d: ", file_name, line_number); - } va_start (args, message); error_tail (status, errnum, message, args);