error.c revision 1.1.1.1
1/*	$NetBSD: error.c,v 1.1.1.1 2016/01/13 03:15:30 christos Exp $	*/
2
3/* Error handler for noninteractive utilities
4   Copyright (C) 1990-1998, 2000, 2001 Free Software Foundation, Inc.
5   This file is part of the GNU C Library.  Its master source is NOT part of
6   the C library, however.  The master source lives in /gd/gnu/lib.
7
8   This program is free software; you can redistribute it and/or modify
9   it under the terms of the GNU General Public License as published by
10   the Free Software Foundation; either version 2, or (at your option)
11   any later version.
12
13   This program is distributed in the hope that it will be useful,
14   but WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16   GNU General Public License for more details.
17
18   You should have received a copy of the GNU General Public License
19   along with this program; if not, write to the Free Software Foundation,
20   Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
21
22/* Written by David MacKenzie <djm@gnu.ai.mit.edu>.  */
23
24#ifdef HAVE_CONFIG_H
25# include <config.h>
26#endif
27
28#include <stdio.h>
29#if HAVE_LIBINTL_H
30# include <libintl.h>
31#endif
32#ifdef _LIBC
33# include <wchar.h>
34# define mbsrtowcs __mbsrtowcs
35#endif
36
37#if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC
38# if __STDC__
39#  include <stdarg.h>
40#  define VA_START(args, lastarg) va_start(args, lastarg)
41# else
42#  include <varargs.h>
43#  define VA_START(args, lastarg) va_start(args)
44# endif
45#else
46# define va_alist a1, a2, a3, a4, a5, a6, a7, a8
47# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
48#endif
49
50#if STDC_HEADERS || _LIBC
51# include <stdlib.h>
52# include <string.h>
53#else
54void exit ();
55#endif
56
57#include "error.h"
58#include "unlocked-io.h"
59
60#ifndef _
61# define _(String) String
62#endif
63
64/* If NULL, error will flush stdout, then print on stderr the program
65   name, a colon and a space.  Otherwise, error will call this
66   function without parameters instead.  */
67void (*error_print_progname) (
68#if __STDC__ - 0
69			      void
70#endif
71			      );
72
73/* This variable is incremented each time `error' is called.  */
74unsigned int error_message_count;
75
76#ifdef _LIBC
77/* In the GNU C library, there is a predefined variable for this.  */
78
79# define program_name program_invocation_name
80# include <errno.h>
81
82/* In GNU libc we want do not want to use the common name `error' directly.
83   Instead make it a weak alias.  */
84extern void __error (int status, int errnum, const char *message, ...)
85     __attribute__ ((__format__ (__printf__, 3, 4)));
86extern void __error_at_line (int status, int errnum, const char *file_name,
87			     unsigned int line_number, const char *message,
88			     ...)
89     __attribute__ ((__format__ (__printf__, 5, 6)));;
90# define error __error
91# define error_at_line __error_at_line
92
93# ifdef USE_IN_LIBIO
94#  include <libio/iolibio.h>
95#  define fflush(s) _IO_fflush (s)
96# endif
97
98#else /* not _LIBC */
99
100# if !HAVE_DECL_STRERROR_R && STRERROR_R_CHAR_P
101#  ifndef HAVE_DECL_STRERROR_R
102"this configure-time declaration test was not run"
103#  endif
104char *strerror_r ();
105# endif
106
107/* The calling program should define program_name and set it to the
108   name of the executing program.  */
109extern char *program_name;
110
111# if HAVE_STRERROR_R || defined strerror_r
112#  define __strerror_r strerror_r
113# else
114#  if HAVE_STRERROR
115#   ifndef HAVE_DECL_STRERROR
116"this configure-time declaration test was not run"
117#   endif
118#   if !HAVE_DECL_STRERROR
119char *strerror ();
120#   endif
121#  else
122static char *
123private_strerror (int errnum)
124{
125  extern char *sys_errlist[];
126  extern int sys_nerr;
127
128  if (errnum > 0 && errnum <= sys_nerr)
129    return _(sys_errlist[errnum]);
130  return _("Unknown system error");
131}
132#   define strerror private_strerror
133#  endif /* HAVE_STRERROR */
134# endif	/* HAVE_STRERROR_R || defined strerror_r */
135#endif	/* not _LIBC */
136
137static void
138print_errno_message (int errnum)
139{
140  char const *s;
141
142#if defined HAVE_STRERROR_R || _LIBC
143  char errbuf[1024];
144# if STRERROR_R_CHAR_P || _LIBC
145  s = __strerror_r (errnum, errbuf, sizeof errbuf);
146# else
147  if (__strerror_r (errnum, errbuf, sizeof errbuf) == 0)
148    s = errbuf;
149  else
150    s = 0;
151# endif
152#else
153  s = strerror (errnum);
154#endif
155
156#if !_LIBC
157  if (! s)
158    s = _("Unknown system error");
159#endif
160
161#if _LIBC && USE_IN_LIBIO
162  if (_IO_fwide (stderr, 0) > 0)
163    {
164      __fwprintf (stderr, L": %s", s);
165      return;
166    }
167#endif
168
169  fprintf (stderr, ": %s", s);
170}
171
172#ifdef VA_START
173static void
174error_tail (int status, int errnum, const char *message, va_list args)
175{
176# if HAVE_VPRINTF || _LIBC
177#  if _LIBC && USE_IN_LIBIO
178  if (_IO_fwide (stderr, 0) > 0)
179    {
180#   define ALLOCA_LIMIT	2000
181      size_t len = strlen (message) + 1;
182      wchar_t *wmessage = NULL;
183      mbstate_t st;
184      size_t res;
185      const char *tmp;
186
187      do
188	{
189	  if (len < ALLOCA_LIMIT)
190	    wmessage = (wchar_t *) alloca (len * sizeof (wchar_t));
191	  else
192	    {
193	      if (wmessage != NULL && len / 2 < ALLOCA_LIMIT)
194		wmessage = NULL;
195
196	      wmessage = (wchar_t *) realloc (wmessage,
197					      len * sizeof (wchar_t));
198
199	      if (wmessage == NULL)
200		{
201		  fputws_unlocked (L"out of memory\n", stderr);
202		  return;
203		}
204	    }
205
206	  memset (&st, '\0', sizeof (st));
207	  tmp =message;
208	}
209      while ((res = mbsrtowcs (wmessage, &tmp, len, &st)) == len);
210
211      if (res == (size_t) -1)
212	/* The string cannot be converted.  */
213	wmessage = (wchar_t *) L"???";
214
215      __vfwprintf (stderr, wmessage, args);
216    }
217  else
218#  endif
219    vfprintf (stderr, message, args);
220# else
221  _doprnt (message, args, stderr);
222# endif
223  va_end (args);
224
225  ++error_message_count;
226  if (errnum)
227    print_errno_message (errnum);
228# if _LIBC && USE_IN_LIBIO
229  if (_IO_fwide (stderr, 0) > 0)
230    putwc (L'\n', stderr);
231  else
232# endif
233    putc ('\n', stderr);
234  fflush (stderr);
235  if (status)
236    exit (status);
237}
238#endif
239
240
241/* Print the program name and error message MESSAGE, which is a printf-style
242   format string with optional args.
243   If ERRNUM is nonzero, print its corresponding system error message.
244   Exit with status STATUS if it is nonzero.  */
245/* VARARGS */
246void
247#if defined VA_START && __STDC__
248error (int status, int errnum, const char *message, ...)
249#else
250error (status, errnum, message, va_alist)
251     int status;
252     int errnum;
253     char *message;
254     va_dcl
255#endif
256{
257#ifdef VA_START
258  va_list args;
259#endif
260
261  fflush (stdout);
262#ifdef _LIBC
263# ifdef USE_IN_LIBIO
264  _IO_flockfile (stderr);
265# else
266  __flockfile (stderr);
267# endif
268#endif
269  if (error_print_progname)
270    (*error_print_progname) ();
271  else
272    {
273#if _LIBC && USE_IN_LIBIO
274      if (_IO_fwide (stderr, 0) > 0)
275	__fwprintf (stderr, L"%s: ", program_name);
276      else
277#endif
278	fprintf (stderr, "%s: ", program_name);
279    }
280
281#ifdef VA_START
282  VA_START (args, message);
283  error_tail (status, errnum, message, args);
284#else
285  fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
286
287  ++error_message_count;
288  if (errnum)
289    print_errno_message (errnum);
290  putc ('\n', stderr);
291  fflush (stderr);
292  if (status)
293    exit (status);
294#endif
295
296#ifdef _LIBC
297# ifdef USE_IN_LIBIO
298  _IO_funlockfile (stderr);
299# else
300  __funlockfile (stderr);
301# endif
302#endif
303}
304
305/* Sometimes we want to have at most one error per line.  This
306   variable controls whether this mode is selected or not.  */
307int error_one_per_line;
308
309void
310#if defined VA_START && __STDC__
311error_at_line (int status, int errnum, const char *file_name,
312	       unsigned int line_number, const char *message, ...)
313#else
314error_at_line (status, errnum, file_name, line_number, message, va_alist)
315     int status;
316     int errnum;
317     const char *file_name;
318     unsigned int line_number;
319     char *message;
320     va_dcl
321#endif
322{
323#ifdef VA_START
324  va_list args;
325#endif
326
327  if (error_one_per_line)
328    {
329      static const char *old_file_name;
330      static unsigned int old_line_number;
331
332      if (old_line_number == line_number
333	  && (file_name == old_file_name
334	      || strcmp (old_file_name, file_name) == 0))
335	/* Simply return and print nothing.  */
336	return;
337
338      old_file_name = file_name;
339      old_line_number = line_number;
340    }
341
342  fflush (stdout);
343#ifdef _LIBC
344# ifdef USE_IN_LIBIO
345  _IO_flockfile (stderr);
346# else
347  __flockfile (stderr);
348# endif
349#endif
350  if (error_print_progname)
351    (*error_print_progname) ();
352  else
353    {
354#if _LIBC && USE_IN_LIBIO
355      if (_IO_fwide (stderr, 0) > 0)
356	__fwprintf (stderr, L"%s: ", program_name);
357      else
358#endif
359	fprintf (stderr, "%s:", program_name);
360    }
361
362  if (file_name != NULL)
363    {
364#if _LIBC && USE_IN_LIBIO
365      if (_IO_fwide (stderr, 0) > 0)
366	__fwprintf (stderr, L"%s:%d: ", file_name, line_number);
367      else
368#endif
369	fprintf (stderr, "%s:%d: ", file_name, line_number);
370    }
371
372#ifdef VA_START
373  VA_START (args, message);
374  error_tail (status, errnum, message, args);
375#else
376  fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
377
378  ++error_message_count;
379  if (errnum)
380    print_errno_message (errnum);
381  putc ('\n', stderr);
382  fflush (stderr);
383  if (status)
384    exit (status);
385#endif
386
387#ifdef _LIBC
388# ifdef USE_IN_LIBIO
389  _IO_funlockfile (stderr);
390# else
391  __funlockfile (stderr);
392# endif
393#endif
394}
395
396#ifdef _LIBC
397/* Make the weak alias.  */
398# undef error
399# undef error_at_line
400weak_alias (__error, error)
401weak_alias (__error_at_line, error_at_line)
402#endif
403