xref: /freebsd/contrib/diff/lib/error.c (revision 18fd37a72c3a7549d2d4f6c6ea00bdcd2bdaca01)
118fd37a7SXin LI /* Error handler for noninteractive utilities
218fd37a7SXin LI    Copyright (C) 1990-1998, 2000-2002, 2003 Free Software Foundation, Inc.
318fd37a7SXin LI    This file is part of the GNU C Library.
418fd37a7SXin LI 
518fd37a7SXin LI    This program is free software; you can redistribute it and/or modify
618fd37a7SXin LI    it under the terms of the GNU General Public License as published by
718fd37a7SXin LI    the Free Software Foundation; either version 2, or (at your option)
818fd37a7SXin LI    any later version.
918fd37a7SXin LI 
1018fd37a7SXin LI    This program is distributed in the hope that it will be useful,
1118fd37a7SXin LI    but WITHOUT ANY WARRANTY; without even the implied warranty of
1218fd37a7SXin LI    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
1318fd37a7SXin LI    GNU General Public License for more details.
1418fd37a7SXin LI 
1518fd37a7SXin LI    You should have received a copy of the GNU General Public License along
1618fd37a7SXin LI    with this program; if not, write to the Free Software Foundation,
1718fd37a7SXin LI    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
1818fd37a7SXin LI 
1918fd37a7SXin LI /* Written by David MacKenzie <djm@gnu.ai.mit.edu>.  */
2018fd37a7SXin LI 
2118fd37a7SXin LI #ifdef HAVE_CONFIG_H
2218fd37a7SXin LI # include <config.h>
2318fd37a7SXin LI #endif
2418fd37a7SXin LI 
2518fd37a7SXin LI #include "error.h"
2618fd37a7SXin LI 
2718fd37a7SXin LI #include <stdarg.h>
2818fd37a7SXin LI #include <stdio.h>
2918fd37a7SXin LI #include <stdlib.h>
3018fd37a7SXin LI #include <string.h>
3118fd37a7SXin LI 
3218fd37a7SXin LI #ifdef _LIBC
3318fd37a7SXin LI # include <libintl.h>
3418fd37a7SXin LI #else
3518fd37a7SXin LI # include "gettext.h"
3618fd37a7SXin LI #endif
3718fd37a7SXin LI 
3818fd37a7SXin LI #ifdef _LIBC
3918fd37a7SXin LI # include <wchar.h>
4018fd37a7SXin LI # define mbsrtowcs __mbsrtowcs
4118fd37a7SXin LI #endif
4218fd37a7SXin LI 
4318fd37a7SXin LI #if !_LIBC
4418fd37a7SXin LI # include "unlocked-io.h"
4518fd37a7SXin LI #endif
4618fd37a7SXin LI 
4718fd37a7SXin LI #ifndef _
4818fd37a7SXin LI # define _(String) String
4918fd37a7SXin LI #endif
5018fd37a7SXin LI 
5118fd37a7SXin LI /* If NULL, error will flush stdout, then print on stderr the program
5218fd37a7SXin LI    name, a colon and a space.  Otherwise, error will call this
5318fd37a7SXin LI    function without parameters instead.  */
5418fd37a7SXin LI void (*error_print_progname) (void);
5518fd37a7SXin LI 
5618fd37a7SXin LI /* This variable is incremented each time `error' is called.  */
5718fd37a7SXin LI unsigned int error_message_count;
5818fd37a7SXin LI 
5918fd37a7SXin LI #ifdef _LIBC
6018fd37a7SXin LI /* In the GNU C library, there is a predefined variable for this.  */
6118fd37a7SXin LI 
6218fd37a7SXin LI # define program_name program_invocation_name
6318fd37a7SXin LI # include <errno.h>
6418fd37a7SXin LI # include <libio/libioP.h>
6518fd37a7SXin LI 
6618fd37a7SXin LI /* In GNU libc we want do not want to use the common name `error' directly.
6718fd37a7SXin LI    Instead make it a weak alias.  */
6818fd37a7SXin LI extern void __error (int status, int errnum, const char *message, ...)
6918fd37a7SXin LI      __attribute__ ((__format__ (__printf__, 3, 4)));
7018fd37a7SXin LI extern void __error_at_line (int status, int errnum, const char *file_name,
7118fd37a7SXin LI 			     unsigned int line_number, const char *message,
7218fd37a7SXin LI 			     ...)
7318fd37a7SXin LI      __attribute__ ((__format__ (__printf__, 5, 6)));;
7418fd37a7SXin LI # define error __error
7518fd37a7SXin LI # define error_at_line __error_at_line
7618fd37a7SXin LI 
7718fd37a7SXin LI # include <libio/iolibio.h>
7818fd37a7SXin LI # define fflush(s) INTUSE(_IO_fflush) (s)
7918fd37a7SXin LI # undef putc
8018fd37a7SXin LI # define putc(c, fp) INTUSE(_IO_putc) (c, fp)
8118fd37a7SXin LI 
8218fd37a7SXin LI # include <bits/libc-lock.h>
8318fd37a7SXin LI 
8418fd37a7SXin LI #else /* not _LIBC */
8518fd37a7SXin LI 
8618fd37a7SXin LI # if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P
8718fd37a7SXin LI #  ifndef HAVE_DECL_STRERROR_R
8818fd37a7SXin LI "this configure-time declaration test was not run"
8918fd37a7SXin LI #  endif
9018fd37a7SXin LI char *strerror_r ();
9118fd37a7SXin LI # endif
9218fd37a7SXin LI 
9318fd37a7SXin LI # ifndef SIZE_MAX
9418fd37a7SXin LI #  define SIZE_MAX ((size_t) -1)
9518fd37a7SXin LI # endif
9618fd37a7SXin LI 
9718fd37a7SXin LI /* The calling program should define program_name and set it to the
9818fd37a7SXin LI    name of the executing program.  */
9918fd37a7SXin LI extern char *program_name;
10018fd37a7SXin LI 
10118fd37a7SXin LI # if HAVE_STRERROR_R || defined strerror_r
10218fd37a7SXin LI #  define __strerror_r strerror_r
10318fd37a7SXin LI # endif
10418fd37a7SXin LI #endif	/* not _LIBC */
10518fd37a7SXin LI 
10618fd37a7SXin LI static void
print_errno_message(int errnum)10718fd37a7SXin LI print_errno_message (int errnum)
10818fd37a7SXin LI {
10918fd37a7SXin LI   char const *s;
11018fd37a7SXin LI 
11118fd37a7SXin LI #if defined HAVE_STRERROR_R || _LIBC
11218fd37a7SXin LI   char errbuf[1024];
11318fd37a7SXin LI # if STRERROR_R_CHAR_P || _LIBC
11418fd37a7SXin LI   s = __strerror_r (errnum, errbuf, sizeof errbuf);
11518fd37a7SXin LI # else
11618fd37a7SXin LI   if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0)
11718fd37a7SXin LI     s = errbuf;
11818fd37a7SXin LI   else
11918fd37a7SXin LI     s = 0;
12018fd37a7SXin LI # endif
12118fd37a7SXin LI #else
12218fd37a7SXin LI   s = strerror (errnum);
12318fd37a7SXin LI #endif
12418fd37a7SXin LI 
12518fd37a7SXin LI #if !_LIBC
12618fd37a7SXin LI   if (! s)
12718fd37a7SXin LI     s = _("Unknown system error");
12818fd37a7SXin LI #endif
12918fd37a7SXin LI 
13018fd37a7SXin LI #if _LIBC
13118fd37a7SXin LI   if (_IO_fwide (stderr, 0) > 0)
13218fd37a7SXin LI     {
13318fd37a7SXin LI       __fwprintf (stderr, L": %s", s);
13418fd37a7SXin LI       return;
13518fd37a7SXin LI     }
13618fd37a7SXin LI #endif
13718fd37a7SXin LI 
13818fd37a7SXin LI   fprintf (stderr, ": %s", s);
13918fd37a7SXin LI }
14018fd37a7SXin LI 
14118fd37a7SXin LI static void
error_tail(int status,int errnum,const char * message,va_list args)14218fd37a7SXin LI error_tail (int status, int errnum, const char *message, va_list args)
14318fd37a7SXin LI {
14418fd37a7SXin LI #if _LIBC
14518fd37a7SXin LI   if (_IO_fwide (stderr, 0) > 0)
14618fd37a7SXin LI     {
14718fd37a7SXin LI # define ALLOCA_LIMIT 2000
14818fd37a7SXin LI       size_t len = strlen (message) + 1;
14918fd37a7SXin LI       const wchar_t *wmessage = L"out of memory";
15018fd37a7SXin LI       wchar_t *wbuf = (len < ALLOCA_LIMIT
15118fd37a7SXin LI 		       ? alloca (len * sizeof *wbuf)
15218fd37a7SXin LI 		       : len <= SIZE_MAX / sizeof *wbuf
15318fd37a7SXin LI 		       ? malloc (len * sizeof *wbuf)
15418fd37a7SXin LI 		       : NULL);
15518fd37a7SXin LI 
15618fd37a7SXin LI       if (wbuf)
15718fd37a7SXin LI 	{
15818fd37a7SXin LI 	  size_t res;
15918fd37a7SXin LI 	  mbstate_t st;
16018fd37a7SXin LI 	  const char *tmp = message;
16118fd37a7SXin LI 	  memset (&st, '\0', sizeof (st));
16218fd37a7SXin LI 	  res = mbsrtowcs (wbuf, &tmp, len, &st);
16318fd37a7SXin LI 	  wmessage = res == (size_t) -1 ? L"???" : wbuf;
16418fd37a7SXin LI 	}
16518fd37a7SXin LI 
16618fd37a7SXin LI       __vfwprintf (stderr, wmessage, args);
16718fd37a7SXin LI       if (! (len < ALLOCA_LIMIT))
16818fd37a7SXin LI 	free (wbuf);
16918fd37a7SXin LI     }
17018fd37a7SXin LI   else
17118fd37a7SXin LI #endif
17218fd37a7SXin LI     vfprintf (stderr, message, args);
17318fd37a7SXin LI   va_end (args);
17418fd37a7SXin LI 
17518fd37a7SXin LI   ++error_message_count;
17618fd37a7SXin LI   if (errnum)
17718fd37a7SXin LI     print_errno_message (errnum);
17818fd37a7SXin LI #if _LIBC
17918fd37a7SXin LI   if (_IO_fwide (stderr, 0) > 0)
18018fd37a7SXin LI     putwc (L'\n', stderr);
18118fd37a7SXin LI   else
18218fd37a7SXin LI #endif
18318fd37a7SXin LI     putc ('\n', stderr);
18418fd37a7SXin LI   fflush (stderr);
18518fd37a7SXin LI   if (status)
18618fd37a7SXin LI     exit (status);
18718fd37a7SXin LI }
18818fd37a7SXin LI 
18918fd37a7SXin LI 
19018fd37a7SXin LI /* Print the program name and error message MESSAGE, which is a printf-style
19118fd37a7SXin LI    format string with optional args.
19218fd37a7SXin LI    If ERRNUM is nonzero, print its corresponding system error message.
19318fd37a7SXin LI    Exit with status STATUS if it is nonzero.  */
19418fd37a7SXin LI void
error(int status,int errnum,const char * message,...)19518fd37a7SXin LI error (int status, int errnum, const char *message, ...)
19618fd37a7SXin LI {
19718fd37a7SXin LI   va_list args;
19818fd37a7SXin LI 
19918fd37a7SXin LI #if defined _LIBC && defined __libc_ptf_call
20018fd37a7SXin LI   /* We do not want this call to be cut short by a thread
20118fd37a7SXin LI      cancellation.  Therefore disable cancellation for now.  */
20218fd37a7SXin LI   int state = PTHREAD_CANCEL_ENABLE;
20318fd37a7SXin LI   __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
20418fd37a7SXin LI 		   0);
20518fd37a7SXin LI #endif
20618fd37a7SXin LI 
20718fd37a7SXin LI   fflush (stdout);
20818fd37a7SXin LI #ifdef _LIBC
20918fd37a7SXin LI   _IO_flockfile (stderr);
21018fd37a7SXin LI #endif
21118fd37a7SXin LI   if (error_print_progname)
21218fd37a7SXin LI     (*error_print_progname) ();
21318fd37a7SXin LI   else
21418fd37a7SXin LI     {
21518fd37a7SXin LI #if _LIBC
21618fd37a7SXin LI       if (_IO_fwide (stderr, 0) > 0)
21718fd37a7SXin LI 	__fwprintf (stderr, L"%s: ", program_name);
21818fd37a7SXin LI       else
21918fd37a7SXin LI #endif
22018fd37a7SXin LI 	fprintf (stderr, "%s: ", program_name);
22118fd37a7SXin LI     }
22218fd37a7SXin LI 
22318fd37a7SXin LI   va_start (args, message);
22418fd37a7SXin LI   error_tail (status, errnum, message, args);
22518fd37a7SXin LI 
22618fd37a7SXin LI #ifdef _LIBC
22718fd37a7SXin LI   _IO_funlockfile (stderr);
22818fd37a7SXin LI # ifdef __libc_ptf_call
22918fd37a7SXin LI   __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
23018fd37a7SXin LI # endif
23118fd37a7SXin LI #endif
23218fd37a7SXin LI }
23318fd37a7SXin LI 
23418fd37a7SXin LI /* Sometimes we want to have at most one error per line.  This
23518fd37a7SXin LI    variable controls whether this mode is selected or not.  */
23618fd37a7SXin LI int error_one_per_line;
23718fd37a7SXin LI 
23818fd37a7SXin LI void
error_at_line(int status,int errnum,const char * file_name,unsigned int line_number,const char * message,...)23918fd37a7SXin LI error_at_line (int status, int errnum, const char *file_name,
24018fd37a7SXin LI 	       unsigned int line_number, const char *message, ...)
24118fd37a7SXin LI {
24218fd37a7SXin LI   va_list args;
24318fd37a7SXin LI 
24418fd37a7SXin LI   if (error_one_per_line)
24518fd37a7SXin LI     {
24618fd37a7SXin LI       static const char *old_file_name;
24718fd37a7SXin LI       static unsigned int old_line_number;
24818fd37a7SXin LI 
24918fd37a7SXin LI       if (old_line_number == line_number
25018fd37a7SXin LI 	  && (file_name == old_file_name
25118fd37a7SXin LI 	      || strcmp (old_file_name, file_name) == 0))
25218fd37a7SXin LI 	/* Simply return and print nothing.  */
25318fd37a7SXin LI 	return;
25418fd37a7SXin LI 
25518fd37a7SXin LI       old_file_name = file_name;
25618fd37a7SXin LI       old_line_number = line_number;
25718fd37a7SXin LI     }
25818fd37a7SXin LI 
25918fd37a7SXin LI #if defined _LIBC && defined __libc_ptf_call
26018fd37a7SXin LI   /* We do not want this call to be cut short by a thread
26118fd37a7SXin LI      cancellation.  Therefore disable cancellation for now.  */
26218fd37a7SXin LI   int state = PTHREAD_CANCEL_ENABLE;
26318fd37a7SXin LI   __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
26418fd37a7SXin LI 		   0);
26518fd37a7SXin LI #endif
26618fd37a7SXin LI 
26718fd37a7SXin LI   fflush (stdout);
26818fd37a7SXin LI #ifdef _LIBC
26918fd37a7SXin LI   _IO_flockfile (stderr);
27018fd37a7SXin LI #endif
27118fd37a7SXin LI   if (error_print_progname)
27218fd37a7SXin LI     (*error_print_progname) ();
27318fd37a7SXin LI   else
27418fd37a7SXin LI     {
27518fd37a7SXin LI #if _LIBC
27618fd37a7SXin LI       if (_IO_fwide (stderr, 0) > 0)
27718fd37a7SXin LI 	__fwprintf (stderr, L"%s: ", program_name);
27818fd37a7SXin LI       else
27918fd37a7SXin LI #endif
28018fd37a7SXin LI 	fprintf (stderr, "%s:", program_name);
28118fd37a7SXin LI     }
28218fd37a7SXin LI 
28318fd37a7SXin LI   if (file_name != NULL)
28418fd37a7SXin LI     {
28518fd37a7SXin LI #if _LIBC
28618fd37a7SXin LI       if (_IO_fwide (stderr, 0) > 0)
28718fd37a7SXin LI 	__fwprintf (stderr, L"%s:%d: ", file_name, line_number);
28818fd37a7SXin LI       else
28918fd37a7SXin LI #endif
29018fd37a7SXin LI 	fprintf (stderr, "%s:%d: ", file_name, line_number);
29118fd37a7SXin LI     }
29218fd37a7SXin LI 
29318fd37a7SXin LI   va_start (args, message);
29418fd37a7SXin LI   error_tail (status, errnum, message, args);
29518fd37a7SXin LI 
29618fd37a7SXin LI #ifdef _LIBC
29718fd37a7SXin LI   _IO_funlockfile (stderr);
29818fd37a7SXin LI # ifdef __libc_ptf_call
29918fd37a7SXin LI   __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
30018fd37a7SXin LI # endif
30118fd37a7SXin LI #endif
30218fd37a7SXin LI }
30318fd37a7SXin LI 
30418fd37a7SXin LI #ifdef _LIBC
30518fd37a7SXin LI /* Make the weak alias.  */
30618fd37a7SXin LI # undef error
30718fd37a7SXin LI # undef error_at_line
30818fd37a7SXin LI weak_alias (__error, error)
30918fd37a7SXin LI weak_alias (__error_at_line, error_at_line)
31018fd37a7SXin LI #endif
311