summaryrefslogtreecommitdiffstats
path: root/lib/error.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/error.c')
-rw-r--r--lib/error.c389
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
53void 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. */
69void (*error_print_progname) (
70#if __STDC__ - 0
71 void
72#endif
73 );
74
75/* This variable is incremented each time `error' is called. */
76unsigned 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. */
87extern void __error (int status, int errnum, const char *message, ...)
88 __attribute__ ((__format__ (__printf__, 3, 4)));
89extern 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
107char *strerror_r ();
108# endif
109
110/* The calling program should define program_name and set it to the
111 name of the executing program. */
112extern 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
122char *strerror ();
123# endif
124# else
125static char *
126private_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
140static void
141print_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
176static void
177error_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 */
249void
250#if defined VA_START && __STDC__
251error (int status, int errnum, const char *message, ...)
252#else
253error (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. */
302int error_one_per_line;
303
304void
305#if defined VA_START && __STDC__
306error_at_line (int status, int errnum, const char *file_name,
307 unsigned int line_number, const char *message, ...)
308#else
309error_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
387weak_alias (__error, error)
388weak_alias (__error_at_line, error_at_line)
389#endif