xref: /freebsd-src/contrib/diff/lib/error.c (revision 18fd37a72c3a7549d2d4f6c6ea00bdcd2bdaca01)
1*18fd37a7SXin LI /* Error handler for noninteractive utilities
2*18fd37a7SXin LI    Copyright (C) 1990-1998, 2000-2002, 2003 Free Software Foundation, Inc.
3*18fd37a7SXin LI    This file is part of the GNU C Library.
4*18fd37a7SXin LI 
5*18fd37a7SXin LI    This program is free software; you can redistribute it and/or modify
6*18fd37a7SXin LI    it under the terms of the GNU General Public License as published by
7*18fd37a7SXin LI    the Free Software Foundation; either version 2, or (at your option)
8*18fd37a7SXin LI    any later version.
9*18fd37a7SXin LI 
10*18fd37a7SXin LI    This program is distributed in the hope that it will be useful,
11*18fd37a7SXin LI    but WITHOUT ANY WARRANTY; without even the implied warranty of
12*18fd37a7SXin LI    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13*18fd37a7SXin LI    GNU General Public License for more details.
14*18fd37a7SXin LI 
15*18fd37a7SXin LI    You should have received a copy of the GNU General Public License along
16*18fd37a7SXin LI    with this program; if not, write to the Free Software Foundation,
17*18fd37a7SXin LI    Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
18*18fd37a7SXin LI 
19*18fd37a7SXin LI /* Written by David MacKenzie <djm@gnu.ai.mit.edu>.  */
20*18fd37a7SXin LI 
21*18fd37a7SXin LI #ifdef HAVE_CONFIG_H
22*18fd37a7SXin LI # include <config.h>
23*18fd37a7SXin LI #endif
24*18fd37a7SXin LI 
25*18fd37a7SXin LI #include "error.h"
26*18fd37a7SXin LI 
27*18fd37a7SXin LI #include <stdarg.h>
28*18fd37a7SXin LI #include <stdio.h>
29*18fd37a7SXin LI #include <stdlib.h>
30*18fd37a7SXin LI #include <string.h>
31*18fd37a7SXin LI 
32*18fd37a7SXin LI #ifdef _LIBC
33*18fd37a7SXin LI # include <libintl.h>
34*18fd37a7SXin LI #else
35*18fd37a7SXin LI # include "gettext.h"
36*18fd37a7SXin LI #endif
37*18fd37a7SXin LI 
38*18fd37a7SXin LI #ifdef _LIBC
39*18fd37a7SXin LI # include <wchar.h>
40*18fd37a7SXin LI # define mbsrtowcs __mbsrtowcs
41*18fd37a7SXin LI #endif
42*18fd37a7SXin LI 
43*18fd37a7SXin LI #if !_LIBC
44*18fd37a7SXin LI # include "unlocked-io.h"
45*18fd37a7SXin LI #endif
46*18fd37a7SXin LI 
47*18fd37a7SXin LI #ifndef _
48*18fd37a7SXin LI # define _(String) String
49*18fd37a7SXin LI #endif
50*18fd37a7SXin LI 
51*18fd37a7SXin LI /* If NULL, error will flush stdout, then print on stderr the program
52*18fd37a7SXin LI    name, a colon and a space.  Otherwise, error will call this
53*18fd37a7SXin LI    function without parameters instead.  */
54*18fd37a7SXin LI void (*error_print_progname) (void);
55*18fd37a7SXin LI 
56*18fd37a7SXin LI /* This variable is incremented each time `error' is called.  */
57*18fd37a7SXin LI unsigned int error_message_count;
58*18fd37a7SXin LI 
59*18fd37a7SXin LI #ifdef _LIBC
60*18fd37a7SXin LI /* In the GNU C library, there is a predefined variable for this.  */
61*18fd37a7SXin LI 
62*18fd37a7SXin LI # define program_name program_invocation_name
63*18fd37a7SXin LI # include <errno.h>
64*18fd37a7SXin LI # include <libio/libioP.h>
65*18fd37a7SXin LI 
66*18fd37a7SXin LI /* In GNU libc we want do not want to use the common name `error' directly.
67*18fd37a7SXin LI    Instead make it a weak alias.  */
68*18fd37a7SXin LI extern void __error (int status, int errnum, const char *message, ...)
69*18fd37a7SXin LI      __attribute__ ((__format__ (__printf__, 3, 4)));
70*18fd37a7SXin LI extern void __error_at_line (int status, int errnum, const char *file_name,
71*18fd37a7SXin LI 			     unsigned int line_number, const char *message,
72*18fd37a7SXin LI 			     ...)
73*18fd37a7SXin LI      __attribute__ ((__format__ (__printf__, 5, 6)));;
74*18fd37a7SXin LI # define error __error
75*18fd37a7SXin LI # define error_at_line __error_at_line
76*18fd37a7SXin LI 
77*18fd37a7SXin LI # include <libio/iolibio.h>
78*18fd37a7SXin LI # define fflush(s) INTUSE(_IO_fflush) (s)
79*18fd37a7SXin LI # undef putc
80*18fd37a7SXin LI # define putc(c, fp) INTUSE(_IO_putc) (c, fp)
81*18fd37a7SXin LI 
82*18fd37a7SXin LI # include <bits/libc-lock.h>
83*18fd37a7SXin LI 
84*18fd37a7SXin LI #else /* not _LIBC */
85*18fd37a7SXin LI 
86*18fd37a7SXin LI # if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P
87*18fd37a7SXin LI #  ifndef HAVE_DECL_STRERROR_R
88*18fd37a7SXin LI "this configure-time declaration test was not run"
89*18fd37a7SXin LI #  endif
90*18fd37a7SXin LI char *strerror_r ();
91*18fd37a7SXin LI # endif
92*18fd37a7SXin LI 
93*18fd37a7SXin LI # ifndef SIZE_MAX
94*18fd37a7SXin LI #  define SIZE_MAX ((size_t) -1)
95*18fd37a7SXin LI # endif
96*18fd37a7SXin LI 
97*18fd37a7SXin LI /* The calling program should define program_name and set it to the
98*18fd37a7SXin LI    name of the executing program.  */
99*18fd37a7SXin LI extern char *program_name;
100*18fd37a7SXin LI 
101*18fd37a7SXin LI # if HAVE_STRERROR_R || defined strerror_r
102*18fd37a7SXin LI #  define __strerror_r strerror_r
103*18fd37a7SXin LI # endif
104*18fd37a7SXin LI #endif	/* not _LIBC */
105*18fd37a7SXin LI 
106*18fd37a7SXin LI static void
print_errno_message(int errnum)107*18fd37a7SXin LI print_errno_message (int errnum)
108*18fd37a7SXin LI {
109*18fd37a7SXin LI   char const *s;
110*18fd37a7SXin LI 
111*18fd37a7SXin LI #if defined HAVE_STRERROR_R || _LIBC
112*18fd37a7SXin LI   char errbuf[1024];
113*18fd37a7SXin LI # if STRERROR_R_CHAR_P || _LIBC
114*18fd37a7SXin LI   s = __strerror_r (errnum, errbuf, sizeof errbuf);
115*18fd37a7SXin LI # else
116*18fd37a7SXin LI   if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0)
117*18fd37a7SXin LI     s = errbuf;
118*18fd37a7SXin LI   else
119*18fd37a7SXin LI     s = 0;
120*18fd37a7SXin LI # endif
121*18fd37a7SXin LI #else
122*18fd37a7SXin LI   s = strerror (errnum);
123*18fd37a7SXin LI #endif
124*18fd37a7SXin LI 
125*18fd37a7SXin LI #if !_LIBC
126*18fd37a7SXin LI   if (! s)
127*18fd37a7SXin LI     s = _("Unknown system error");
128*18fd37a7SXin LI #endif
129*18fd37a7SXin LI 
130*18fd37a7SXin LI #if _LIBC
131*18fd37a7SXin LI   if (_IO_fwide (stderr, 0) > 0)
132*18fd37a7SXin LI     {
133*18fd37a7SXin LI       __fwprintf (stderr, L": %s", s);
134*18fd37a7SXin LI       return;
135*18fd37a7SXin LI     }
136*18fd37a7SXin LI #endif
137*18fd37a7SXin LI 
138*18fd37a7SXin LI   fprintf (stderr, ": %s", s);
139*18fd37a7SXin LI }
140*18fd37a7SXin LI 
141*18fd37a7SXin LI static void
error_tail(int status,int errnum,const char * message,va_list args)142*18fd37a7SXin LI error_tail (int status, int errnum, const char *message, va_list args)
143*18fd37a7SXin LI {
144*18fd37a7SXin LI #if _LIBC
145*18fd37a7SXin LI   if (_IO_fwide (stderr, 0) > 0)
146*18fd37a7SXin LI     {
147*18fd37a7SXin LI # define ALLOCA_LIMIT 2000
148*18fd37a7SXin LI       size_t len = strlen (message) + 1;
149*18fd37a7SXin LI       const wchar_t *wmessage = L"out of memory";
150*18fd37a7SXin LI       wchar_t *wbuf = (len < ALLOCA_LIMIT
151*18fd37a7SXin LI 		       ? alloca (len * sizeof *wbuf)
152*18fd37a7SXin LI 		       : len <= SIZE_MAX / sizeof *wbuf
153*18fd37a7SXin LI 		       ? malloc (len * sizeof *wbuf)
154*18fd37a7SXin LI 		       : NULL);
155*18fd37a7SXin LI 
156*18fd37a7SXin LI       if (wbuf)
157*18fd37a7SXin LI 	{
158*18fd37a7SXin LI 	  size_t res;
159*18fd37a7SXin LI 	  mbstate_t st;
160*18fd37a7SXin LI 	  const char *tmp = message;
161*18fd37a7SXin LI 	  memset (&st, '\0', sizeof (st));
162*18fd37a7SXin LI 	  res = mbsrtowcs (wbuf, &tmp, len, &st);
163*18fd37a7SXin LI 	  wmessage = res == (size_t) -1 ? L"???" : wbuf;
164*18fd37a7SXin LI 	}
165*18fd37a7SXin LI 
166*18fd37a7SXin LI       __vfwprintf (stderr, wmessage, args);
167*18fd37a7SXin LI       if (! (len < ALLOCA_LIMIT))
168*18fd37a7SXin LI 	free (wbuf);
169*18fd37a7SXin LI     }
170*18fd37a7SXin LI   else
171*18fd37a7SXin LI #endif
172*18fd37a7SXin LI     vfprintf (stderr, message, args);
173*18fd37a7SXin LI   va_end (args);
174*18fd37a7SXin LI 
175*18fd37a7SXin LI   ++error_message_count;
176*18fd37a7SXin LI   if (errnum)
177*18fd37a7SXin LI     print_errno_message (errnum);
178*18fd37a7SXin LI #if _LIBC
179*18fd37a7SXin LI   if (_IO_fwide (stderr, 0) > 0)
180*18fd37a7SXin LI     putwc (L'\n', stderr);
181*18fd37a7SXin LI   else
182*18fd37a7SXin LI #endif
183*18fd37a7SXin LI     putc ('\n', stderr);
184*18fd37a7SXin LI   fflush (stderr);
185*18fd37a7SXin LI   if (status)
186*18fd37a7SXin LI     exit (status);
187*18fd37a7SXin LI }
188*18fd37a7SXin LI 
189*18fd37a7SXin LI 
190*18fd37a7SXin LI /* Print the program name and error message MESSAGE, which is a printf-style
191*18fd37a7SXin LI    format string with optional args.
192*18fd37a7SXin LI    If ERRNUM is nonzero, print its corresponding system error message.
193*18fd37a7SXin LI    Exit with status STATUS if it is nonzero.  */
194*18fd37a7SXin LI void
error(int status,int errnum,const char * message,...)195*18fd37a7SXin LI error (int status, int errnum, const char *message, ...)
196*18fd37a7SXin LI {
197*18fd37a7SXin LI   va_list args;
198*18fd37a7SXin LI 
199*18fd37a7SXin LI #if defined _LIBC && defined __libc_ptf_call
200*18fd37a7SXin LI   /* We do not want this call to be cut short by a thread
201*18fd37a7SXin LI      cancellation.  Therefore disable cancellation for now.  */
202*18fd37a7SXin LI   int state = PTHREAD_CANCEL_ENABLE;
203*18fd37a7SXin LI   __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
204*18fd37a7SXin LI 		   0);
205*18fd37a7SXin LI #endif
206*18fd37a7SXin LI 
207*18fd37a7SXin LI   fflush (stdout);
208*18fd37a7SXin LI #ifdef _LIBC
209*18fd37a7SXin LI   _IO_flockfile (stderr);
210*18fd37a7SXin LI #endif
211*18fd37a7SXin LI   if (error_print_progname)
212*18fd37a7SXin LI     (*error_print_progname) ();
213*18fd37a7SXin LI   else
214*18fd37a7SXin LI     {
215*18fd37a7SXin LI #if _LIBC
216*18fd37a7SXin LI       if (_IO_fwide (stderr, 0) > 0)
217*18fd37a7SXin LI 	__fwprintf (stderr, L"%s: ", program_name);
218*18fd37a7SXin LI       else
219*18fd37a7SXin LI #endif
220*18fd37a7SXin LI 	fprintf (stderr, "%s: ", program_name);
221*18fd37a7SXin LI     }
222*18fd37a7SXin LI 
223*18fd37a7SXin LI   va_start (args, message);
224*18fd37a7SXin LI   error_tail (status, errnum, message, args);
225*18fd37a7SXin LI 
226*18fd37a7SXin LI #ifdef _LIBC
227*18fd37a7SXin LI   _IO_funlockfile (stderr);
228*18fd37a7SXin LI # ifdef __libc_ptf_call
229*18fd37a7SXin LI   __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
230*18fd37a7SXin LI # endif
231*18fd37a7SXin LI #endif
232*18fd37a7SXin LI }
233*18fd37a7SXin LI 
234*18fd37a7SXin LI /* Sometimes we want to have at most one error per line.  This
235*18fd37a7SXin LI    variable controls whether this mode is selected or not.  */
236*18fd37a7SXin LI int error_one_per_line;
237*18fd37a7SXin LI 
238*18fd37a7SXin LI void
error_at_line(int status,int errnum,const char * file_name,unsigned int line_number,const char * message,...)239*18fd37a7SXin LI error_at_line (int status, int errnum, const char *file_name,
240*18fd37a7SXin LI 	       unsigned int line_number, const char *message, ...)
241*18fd37a7SXin LI {
242*18fd37a7SXin LI   va_list args;
243*18fd37a7SXin LI 
244*18fd37a7SXin LI   if (error_one_per_line)
245*18fd37a7SXin LI     {
246*18fd37a7SXin LI       static const char *old_file_name;
247*18fd37a7SXin LI       static unsigned int old_line_number;
248*18fd37a7SXin LI 
249*18fd37a7SXin LI       if (old_line_number == line_number
250*18fd37a7SXin LI 	  && (file_name == old_file_name
251*18fd37a7SXin LI 	      || strcmp (old_file_name, file_name) == 0))
252*18fd37a7SXin LI 	/* Simply return and print nothing.  */
253*18fd37a7SXin LI 	return;
254*18fd37a7SXin LI 
255*18fd37a7SXin LI       old_file_name = file_name;
256*18fd37a7SXin LI       old_line_number = line_number;
257*18fd37a7SXin LI     }
258*18fd37a7SXin LI 
259*18fd37a7SXin LI #if defined _LIBC && defined __libc_ptf_call
260*18fd37a7SXin LI   /* We do not want this call to be cut short by a thread
261*18fd37a7SXin LI      cancellation.  Therefore disable cancellation for now.  */
262*18fd37a7SXin LI   int state = PTHREAD_CANCEL_ENABLE;
263*18fd37a7SXin LI   __libc_ptf_call (pthread_setcancelstate, (PTHREAD_CANCEL_DISABLE, &state),
264*18fd37a7SXin LI 		   0);
265*18fd37a7SXin LI #endif
266*18fd37a7SXin LI 
267*18fd37a7SXin LI   fflush (stdout);
268*18fd37a7SXin LI #ifdef _LIBC
269*18fd37a7SXin LI   _IO_flockfile (stderr);
270*18fd37a7SXin LI #endif
271*18fd37a7SXin LI   if (error_print_progname)
272*18fd37a7SXin LI     (*error_print_progname) ();
273*18fd37a7SXin LI   else
274*18fd37a7SXin LI     {
275*18fd37a7SXin LI #if _LIBC
276*18fd37a7SXin LI       if (_IO_fwide (stderr, 0) > 0)
277*18fd37a7SXin LI 	__fwprintf (stderr, L"%s: ", program_name);
278*18fd37a7SXin LI       else
279*18fd37a7SXin LI #endif
280*18fd37a7SXin LI 	fprintf (stderr, "%s:", program_name);
281*18fd37a7SXin LI     }
282*18fd37a7SXin LI 
283*18fd37a7SXin LI   if (file_name != NULL)
284*18fd37a7SXin LI     {
285*18fd37a7SXin LI #if _LIBC
286*18fd37a7SXin LI       if (_IO_fwide (stderr, 0) > 0)
287*18fd37a7SXin LI 	__fwprintf (stderr, L"%s:%d: ", file_name, line_number);
288*18fd37a7SXin LI       else
289*18fd37a7SXin LI #endif
290*18fd37a7SXin LI 	fprintf (stderr, "%s:%d: ", file_name, line_number);
291*18fd37a7SXin LI     }
292*18fd37a7SXin LI 
293*18fd37a7SXin LI   va_start (args, message);
294*18fd37a7SXin LI   error_tail (status, errnum, message, args);
295*18fd37a7SXin LI 
296*18fd37a7SXin LI #ifdef _LIBC
297*18fd37a7SXin LI   _IO_funlockfile (stderr);
298*18fd37a7SXin LI # ifdef __libc_ptf_call
299*18fd37a7SXin LI   __libc_ptf_call (pthread_setcancelstate, (state, NULL), 0);
300*18fd37a7SXin LI # endif
301*18fd37a7SXin LI #endif
302*18fd37a7SXin LI }
303*18fd37a7SXin LI 
304*18fd37a7SXin LI #ifdef _LIBC
305*18fd37a7SXin LI /* Make the weak alias.  */
306*18fd37a7SXin LI # undef error
307*18fd37a7SXin LI # undef error_at_line
308*18fd37a7SXin LI weak_alias (__error, error)
309*18fd37a7SXin LI weak_alias (__error_at_line, error_at_line)
310*18fd37a7SXin LI #endif
311