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