X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Ferror.c;h=9bb3e558cb8bc197bced81d4b8278e21c047b8cf;hb=fdbc2d4ba69ef24b623b87cb6fd2114215e7b52b;hp=7e61f150707c9f27f8e098d477f5fd45f2bf2cbe;hpb=43e78b970f396160a887c9da94531569faeda8a0;p=gnulib.git diff --git a/lib/error.c b/lib/error.c index 7e61f1507..9bb3e558c 100644 --- a/lib/error.c +++ b/lib/error.c @@ -1,5 +1,6 @@ -/* error.c -- error handler for noninteractive utilities - Copyright (C) 1990, 1991, 1992 Free Software Foundation, Inc. +/* Error handler for noninteractive utilities + Copyright (C) 1990-1998, 2000-2002, 2003, 2004 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 @@ -11,95 +12,295 @@ 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + 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. */ -/* Written by David MacKenzie. */ +/* Written by David MacKenzie . */ -#include +#ifdef HAVE_CONFIG_H +# include +#endif -#ifdef HAVE_VPRINTF +#include "error.h" -#if __STDC__ #include -#define VA_START(args, lastarg) va_start(args, lastarg) -#else /* !__STDC__ */ -#include -#define VA_START(args, lastarg) va_start(args) -#endif /* !__STDC__ */ +#include +#include +#include -#else /* !HAVE_VPRINTF */ +#ifdef _LIBC +# include +#else +# include "gettext.h" +#endif -#ifdef HAVE_DOPRNT -#define va_alist args -#define va_dcl int args; -#else /* !HAVE_DOPRNT */ -#define va_alist a1, a2, a3, a4, a5, a6, a7, a8 -#define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8; -#endif /* !HAVE_DOPRNT */ +#ifdef _LIBC +# include +# define mbsrtowcs __mbsrtowcs +#endif -#endif /* !HAVE_VPRINTF */ +#if USE_UNLOCKED_IO +# include "unlocked-io.h" +#endif -#ifdef STDC_HEADERS -#include -#include -#else /* !STDC_HEADERS */ -void exit (); -#endif /* !STDC_HEADERS */ - -#ifndef HAVE_STRERROR -static char * -private_strerror (errnum) - int errnum; +#ifndef _ +# define _(String) String +#endif + +/* If NULL, error will flush stdout, then print on stderr the program + name, a colon and a space. Otherwise, error will call this + function without parameters instead. */ +void (*error_print_progname) (void); + +/* This variable is incremented each time `error' is called. */ +unsigned int error_message_count; + +#ifdef _LIBC +/* In the GNU C library, there is a predefined variable for this. */ + +# define program_name program_invocation_name +# include +# include + +/* 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, + ...) + __attribute__ ((__format__ (__printf__, 5, 6)));; +# define error __error +# define error_at_line __error_at_line + +# include +# define fflush(s) INTUSE(_IO_fflush) (s) +# undef putc +# define putc(c, fp) INTUSE(_IO_putc) (c, fp) + +# include + +#else /* not _LIBC */ + +# if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P +# ifndef HAVE_DECL_STRERROR_R +"this configure-time declaration test was not run" +# endif +char *strerror_r (); +# 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 +#endif /* not _LIBC */ + +static void +print_errno_message (int errnum) +{ + char const *s = NULL; + +#if defined HAVE_STRERROR_R || _LIBC + char errbuf[1024]; +# if STRERROR_R_CHAR_P || _LIBC + s = __strerror_r (errnum, errbuf, sizeof errbuf); +# else + if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0) + s = errbuf; +# endif +#endif + +#if !_LIBC + if (! s && ! (s = strerror (errnum))) + s = _("Unknown system error"); +#endif + +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + { + __fwprintf (stderr, L": %s", s); + return; + } +#endif + + fprintf (stderr, ": %s", s); +} + +static void +error_tail (int status, int errnum, const char *message, va_list args) { - extern char *sys_errlist[]; - extern int sys_nerr; +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + { +# define ALLOCA_LIMIT 2000 + size_t len = strlen (message) + 1; + const wchar_t *wmessage = L"out of memory"; + wchar_t *wbuf = (len < ALLOCA_LIMIT + ? 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; + } + + __vfwprintf (stderr, wmessage, args); + if (! (len < ALLOCA_LIMIT)) + free (wbuf); + } + else +#endif + vfprintf (stderr, message, args); + va_end (args); - if (errnum > 0 && errnum <= sys_nerr) - return sys_errlist[errnum]; - return "Unknown system error"; + ++error_message_count; + if (errnum) + print_errno_message (errnum); +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + putwc (L'\n', stderr); + else +#endif + putc ('\n', stderr); + fflush (stderr); + if (status) + exit (status); } -#define strerror private_strerror -#endif /* !HAVE_STRERROR */ + /* Print the program name and error message MESSAGE, which is a printf-style format string with optional args. If ERRNUM is nonzero, print its corresponding system error message. Exit with status STATUS if it is nonzero. */ -/* VARARGS */ void -#if defined (HAVE_VPRINTF) && __STDC__ -error (int status, int errnum, char *message, ...) -#else /* !HAVE_VPRINTF or !__STDC__ */ -error (status, errnum, message, va_alist) - int status; - int errnum; - char *message; - va_dcl -#endif /* !HAVE_VPRINTF or !__STDC__ */ +error (int status, int errnum, const char *message, ...) { - extern char *program_name; -#ifdef HAVE_VPRINTF va_list args; -#endif /* HAVE_VPRINTF */ - fprintf (stderr, "%s: ", program_name); -#ifdef HAVE_VPRINTF - VA_START (args, message); - vfprintf (stderr, message, args); - va_end (args); -#else /* !HAVE_VPRINTF */ -#ifdef HAVE_DOPRNT - _doprnt (message, &args, stderr); -#else /* !HAVE_DOPRNT */ - fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8); -#endif /* !HAVE_DOPRNT */ -#endif /* !HAVE_VPRINTF */ - if (errnum) - fprintf (stderr, ": %s", strerror (errnum)); - putc ('\n', stderr); - fflush (stderr); - if (status) - exit (status); +#if defined _LIBC && defined __libc_ptf_call + /* We do not want this call to be cut short by a thread + cancellation. Therefore disable cancellation for now. */ + int state = PTHREAD_CANCEL_ENABLE; + __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), + 0); +#endif + + fflush (stdout); +#ifdef _LIBC + _IO_flockfile (stderr); +#endif + if (error_print_progname) + (*error_print_progname) (); + else + { +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s: ", program_name); + else +#endif + fprintf (stderr, "%s: ", program_name); + } + + va_start (args, message); + error_tail (status, errnum, message, args); + +#ifdef _LIBC + _IO_funlockfile (stderr); +# ifdef __libc_ptf_call + __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0); +# endif +#endif } + +/* Sometimes we want to have at most one error per line. This + variable controls whether this mode is selected or not. */ +int error_one_per_line; + +void +error_at_line (int status, int errnum, const char *file_name, + unsigned int line_number, const char *message, ...) +{ + va_list args; + + if (error_one_per_line) + { + static const char *old_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; + + old_file_name = file_name; + old_line_number = line_number; + } + +#if defined _LIBC && defined __libc_ptf_call + /* We do not want this call to be cut short by a thread + cancellation. Therefore disable cancellation for now. */ + int state = PTHREAD_CANCEL_ENABLE; + __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state), + 0); +#endif + + fflush (stdout); +#ifdef _LIBC + _IO_flockfile (stderr); +#endif + if (error_print_progname) + (*error_print_progname) (); + else + { +#if _LIBC + if (_IO_fwide (stderr, 0) > 0) + __fwprintf (stderr, L"%s: ", program_name); + else +#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 +#endif + fprintf (stderr, "%s:%d: ", file_name, line_number); + } + + va_start (args, message); + error_tail (status, errnum, message, args); + +#ifdef _LIBC + _IO_funlockfile (stderr); +# ifdef __libc_ptf_call + __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0); +# endif +#endif +} + +#ifdef _LIBC +/* Make the weak alias. */ +# undef error +# undef error_at_line +weak_alias (__error, error) +weak_alias (__error_at_line, error_at_line) +#endif