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