]> Pileus Git - ~andy/fetchmail/blob - report.c
Internationalization support via GNU gettext().
[~andy/fetchmail] / report.c
1 /* error.c -- error handler for noninteractive utilities
2    Copyright (C) 1990, 91, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
17
18 /* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
19  * Heavily modified by Dave Bodenstab and ESR.
20  * Bludgeoned into submission for SunOS 4.1.3 by
21  *     Chris Cheyney <cheyney@netcom.com>.
22  * Now it works even when the return from vprintf is unreliable.
23  *
24  * i18n by Arnaldo Carvalho de Melo <acme@conectiva.com.br> 7-Nov-1998
25  */
26
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <stdio.h>
32 #include <errno.h>
33 #if defined(HAVE_SYSLOG)
34 #include <syslog.h>
35 #endif
36
37 #if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC || HAVE_STDARG_H
38 # if HAVE_STDARG_H
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
54 void exit ();
55 #endif
56
57 #include "i18n.h"
58
59 #include "fetchmail.h"
60 #define MALLOC(n)       xmalloc(n)      
61 #define REALLOC(n,s)    xrealloc(n,s)   
62
63 /* If NULL, error will flush stdout, then print on stderr the program
64    name, a colon and a space.  Otherwise, error will call this
65    function without parameters instead.  */
66 void (*error_print_progname) (
67 #if __STDC__ - 0
68                               void
69 #endif
70                               );
71
72 /* Used by error_build() and error_complete() to accumulate partial messages.  */
73 static unsigned int partial_message_size = 0;
74 static unsigned int partial_message_size_used = 0;
75 static char *partial_message;
76 static unsigned use_stderr;
77 static unsigned int use_syslog;
78
79 /* This variable is incremented each time `error' is called.  */
80 unsigned int error_message_count;
81
82
83 #ifdef _LIBC
84 /* In the GNU C library, there is a predefined variable for this.  */
85
86 # define program_name program_invocation_name
87 # include <errno.h>
88
89 #else
90
91 /* The calling program should define program_name and set it to the
92    name of the executing program.  */
93 extern char *program_name;
94
95 # if HAVE_STRERROR
96 #  ifndef strerror              /* On some systems, strerror is a macro */
97 char *strerror ();
98 #  endif
99 # else
100 static char *
101 private_strerror (errnum)
102      int errnum;
103 {
104   extern char *sys_errlist[];
105   extern int sys_nerr;
106
107   if (errnum > 0 && errnum <= sys_nerr)
108     return sys_errlist[errnum];
109   return _("Unknown system error");
110 }
111 #  define strerror private_strerror
112 # endif /* HAVE_STRERROR */
113 #endif  /* _LIBC */
114
115 /* Print the program name and error message MESSAGE, which is a printf-style
116    format string with optional args.
117    If ERRNUM is nonzero, print its corresponding system error message.
118    Exit with status STATUS if it is nonzero.  */
119 /* VARARGS */
120
121 void
122 #ifdef HAVE_STDARG_H
123 error (int status, int errnum, const char *message, ...)
124 #else
125 error (status, errnum, message, va_alist)
126      int status;
127      int errnum;
128      const char *message;
129      va_dcl
130 #endif
131 {
132 #ifdef VA_START
133   va_list args;
134 #endif
135
136   /* If a partially built message exists, print it now so it's not lost.  */
137   if (partial_message_size_used != 0)
138     {
139       partial_message_size_used = 0;
140       error (0, 0, _("%s (log message incomplete)"), partial_message);
141     }
142
143 #if defined(HAVE_SYSLOG)
144   if (use_syslog)
145     {
146       int priority;
147
148 #ifdef VA_START
149       VA_START (args, message);
150 #endif
151       priority = status? LOG_ALERT : errnum? LOG_ERR : LOG_INFO;
152
153       if (errnum > 0)
154         {
155           char *msg;
156           
157           xalloca(msg, char *, strlen (message) + 5);
158
159           strcpy (msg, message);
160           strcat (msg, ": %m");
161
162           errno = errnum;
163 #ifdef HAVE_VSYSLOG
164           vsyslog (priority, msg, args);
165 #else
166           {
167           char *a1 = va_arg(args, char *);
168           char *a2 = va_arg(args, char *);
169           char *a3 = va_arg(args, char *);
170           char *a4 = va_arg(args, char *);
171           char *a5 = va_arg(args, char *);
172           char *a6 = va_arg(args, char *);
173           char *a7 = va_arg(args, char *);
174           char *a8 = va_arg(args, char *);
175           syslog (priority, msg, a1, a2, a3, a4, a5, a6, a7, a8);
176           }
177 #endif
178         }
179       else
180         {
181 #ifdef HAVE_VSYSLOG
182           vsyslog (priority, message, args);
183 #else
184           {
185           char *a1 = va_arg(args, char *);
186           char *a2 = va_arg(args, char *);
187           char *a3 = va_arg(args, char *);
188           char *a4 = va_arg(args, char *);
189           char *a5 = va_arg(args, char *);
190           char *a6 = va_arg(args, char *);
191           char *a7 = va_arg(args, char *);
192           char *a8 = va_arg(args, char *);
193           syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
194           }
195 #endif
196         }
197
198 #ifdef VA_START
199       va_end(args);
200 #endif
201     }
202   else
203 #endif
204     {
205       if (error_print_progname)
206         (*error_print_progname) ();
207       else
208         {
209           fflush (stdout);
210           if ( *message == '\n' )
211             {
212               fputc( '\n', stderr );
213               ++message;
214             }
215           fprintf (stderr, "%s: ", program_name);
216         }
217
218 #ifdef VA_START
219       VA_START (args, message);
220 # if HAVE_VPRINTF || _LIBC
221       vfprintf (stderr, message, args);
222 # else
223       _doprnt (message, args, stderr);
224 # endif
225       va_end (args);
226 #else
227       fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
228 #endif
229
230       if (errnum && errnum != -1) {
231         char *tmps = strerror(errnum);
232         if (tmps) {
233           fprintf (stderr, ": %s", tmps);
234         }
235         else {
236           fprintf (stderr, _(": Error %d"), errnum);
237         }
238       }
239       putc ('\n', stderr);
240       fflush (stderr);
241     }
242   ++error_message_count;
243   if (status)
244     exit (status);
245 }
246 \f
247 /*
248  * Calling error_init(1) causes error_build and error_complete to write
249  * to stderr without buffering.  This is needed for the ticker dots to
250  * work correctly.
251  */
252 void error_init(int mode)
253 {
254     switch(mode)
255     {
256     case 0:                     /* stderr, buffered */
257     default:
258         use_stderr = FALSE;
259         use_syslog = FALSE;
260         break;
261
262     case 1:                     /* stderr, unbuffered */
263         use_stderr = TRUE;
264         use_syslog = FALSE;
265         break;
266
267 #ifdef HAVE_SYSLOG
268     case -1:                    /* syslogd */
269         use_stderr = FALSE;
270         use_syslog = TRUE;
271         break;
272 #endif /* HAVE_SYSLOG */
273     }
274 }
275 \f
276 /* Build an error message by appending MESSAGE, which is a printf-style
277    format string with optional args, to the existing error message (which may
278    be empty.)  The completed error message is finally printed (and reset to
279    empty) by calling error_complete().
280    If an intervening call to error() occurs when a partially constructed
281    message exists, then, in an attempt to keep the messages in their proper
282    sequence, the partial message will be printed as-is (with a trailing 
283    newline) before error() prints its message. */
284 /* VARARGS */
285
286 void
287 #ifdef HAVE_STDARG_H
288 error_build (const char *message, ...)
289 #else
290 error_build (message, va_alist)
291      const char *message;
292      va_dcl
293 #endif
294 {
295 #ifdef VA_START
296   va_list args;
297   int n;
298 #endif
299
300   /* Make an initial guess for the size of any single message fragment.  */
301   if (partial_message_size == 0)
302     {
303       partial_message_size_used = 0;
304       partial_message_size = 2048;
305       partial_message = MALLOC (partial_message_size);
306     }
307   else
308     if (partial_message_size - partial_message_size_used < 1024)
309       {
310         partial_message_size += 2048;
311         partial_message = REALLOC (partial_message, partial_message_size);
312       }
313
314 #if defined(VA_START)
315   VA_START (args, message);
316 #if HAVE_VSNPRINTF || _LIBC
317   for ( ; ; )
318     {
319       n = vsnprintf (partial_message + partial_message_size_used,
320                      partial_message_size - partial_message_size_used,
321                      message, args);
322
323       if (n < partial_message_size - partial_message_size_used)
324         {
325           partial_message_size_used += n;
326           break;
327         }
328
329       partial_message_size += 2048;
330       partial_message = REALLOC (partial_message, partial_message_size);
331     }
332 #else
333   vsprintf (partial_message + partial_message_size_used, message, args);
334   partial_message_size_used += strlen(partial_message+partial_message_size_used);
335
336   /* Attempt to catch memory overwrites... */
337   if (partial_message_size_used >= partial_message_size)
338     {
339       partial_message_size_used = 0;
340       error (PS_UNDEFINED, 0, _("partial error message buffer overflow"));
341     }
342 #endif
343   va_end (args);
344 #else
345 #if HAVE_SNPRINTF
346   for ( ; ; )
347     {
348       n = snprintf (partial_message + partial_message_size_used,
349                     partial_message_size - partial_message_size_used,
350                     message, a1, a2, a3, a4, a5, a6, a7, a8);
351
352       if (n < partial_message_size - partial_message_size_used)
353         {
354           partial_message_size_used += n;
355           break;
356         }
357
358       partial_message_size += 2048;
359       partial_message = REALLOC (partial_message, partial_message_size);
360     }
361 #else
362   sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
363
364   /* Attempt to catch memory overwrites... */
365   if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
366     {
367       partial_message_size_used = 0;
368       error (PS_UNDEFINED, 0, _("partial error message buffer overflow"));
369     }
370 #endif
371 #endif
372
373   if (use_stderr && partial_message_size_used != 0)
374     {
375       partial_message_size_used = 0;
376       fputs(partial_message, stderr);
377     }
378 }
379 \f
380 /* Complete an error message by appending MESSAGE, which is a printf-style
381    format string with optional args, to the existing error message (which may
382    be empty.)  The completed error message is then printed (and reset to
383    empty.) */
384 /* VARARGS */
385
386 void
387 #ifdef HAVE_STDARG_H
388 error_complete (int status, int errnum, const char *message, ...)
389 #else
390 error_complete (status, errnum, message, va_alist)
391      int status;
392      int errnum;
393      const char *message;
394      va_dcl
395 #endif
396 {
397 #ifdef VA_START
398   va_list args;
399   int n;
400 #endif
401
402   /* Make an initial guess for the size of any single message fragment.  */
403   if (partial_message_size == 0)
404     {
405       partial_message_size_used = 0;
406       partial_message_size = 2048;
407       partial_message = MALLOC (partial_message_size);
408     }
409   else
410     if (partial_message_size - partial_message_size_used < 1024)
411       {
412         partial_message_size += 2048;
413         partial_message = REALLOC (partial_message, partial_message_size);
414       }
415
416 #if defined(VA_START)
417   VA_START (args, message);
418 #if HAVE_VSNPRINTF || _LIBC
419   for ( ; ; )
420     {
421       n = vsnprintf (partial_message + partial_message_size_used,
422                      partial_message_size - partial_message_size_used,
423                      message, args);
424
425       if (n < partial_message_size - partial_message_size_used)
426         {
427           partial_message_size_used += n;
428           break;
429         }
430
431       partial_message_size += 2048;
432       partial_message = REALLOC (partial_message, partial_message_size);
433     }
434 #else
435   vsprintf (partial_message + partial_message_size_used, message, args);
436   partial_message_size_used += strlen(partial_message+partial_message_size_used);
437
438   /* Attempt to catch memory overwrites... */
439   if (partial_message_size_used >= partial_message_size)
440     {
441       partial_message_size_used = 0;
442       error (PS_UNDEFINED, 0, _("partial error message buffer overflow"));
443     }
444 #endif
445   va_end (args);
446 #else
447 #if HAVE_SNPRINTF
448   for ( ; ; )
449     {
450       n = snprintf (partial_message + partial_message_size_used,
451                     partial_message_size - partial_message_size_used,
452                     message, a1, a2, a3, a4, a5, a6, a7, a8);
453
454       if (n < partial_message_size - partial_message_size_used)
455         {
456           partial_message_size_used += n;
457           break;
458         }
459
460       partial_message_size += 2048;
461       partial_message = REALLOC (partial_message, partial_message_size);
462     }
463 #else
464   sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
465
466   /* Attempt to catch memory overwrites... */
467   if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
468     {
469       partial_message_size_used = 0;
470       error (PS_UNDEFINED, 0, _("partial error message buffer overflow"));
471     }
472 #endif
473 #endif
474
475   /* Finally... print it.  */
476   partial_message_size_used = 0;
477
478   if (use_stderr)
479     {
480       fputs(partial_message, stderr);
481
482       if (errnum)
483         fprintf (stderr, ": %s", strerror (errnum));
484
485       putc ('\n', stderr);
486       fflush (stderr);
487
488       ++error_message_count;
489
490       if (status)
491           exit(status);
492     }
493   else
494     error (status, errnum, "%s", partial_message);
495 }
496 \f
497 /* Sometimes we want to have at most one error per line.  This
498    variable controls whether this mode is selected or not.  */
499 int error_one_per_line;
500
501 void
502 #ifdef HAVE_STDARG_H
503 error_at_line (int status, int errnum, const char *file_name,
504                unsigned int line_number, const char *message, ...)
505 #else
506 error_at_line (status, errnum, file_name, line_number, message, va_alist)
507      int status;
508      int errnum;
509      const char *file_name;
510      unsigned int line_number;
511      const char *message;
512      va_dcl
513 #endif
514 {
515 #ifdef VA_START
516   va_list args;
517 #endif
518
519   if (error_one_per_line)
520     {
521       static const char *old_file_name;
522       static unsigned int old_line_number;
523
524       if (old_line_number == line_number &&
525           (file_name == old_file_name || !strcmp (old_file_name, file_name)))
526         /* Simply return and print nothing.  */
527         return;
528
529       old_file_name = file_name;
530       old_line_number = line_number;
531     }
532
533   if (error_print_progname)
534     (*error_print_progname) ();
535   else
536     {
537       fflush (stdout);
538       if ( *message == '\n' )
539         {
540           fputc( '\n', stderr );
541           ++message;
542         }
543       fprintf (stderr, "%s:", program_name);
544     }
545
546   if (file_name != NULL)
547     fprintf (stderr, "%s:%d: ", file_name, line_number);
548
549 #ifdef VA_START
550   VA_START (args, message);
551 # if HAVE_VPRINTF || _LIBC
552   vfprintf (stderr, message, args);
553 # else
554   _doprnt (message, args, stderr);
555 # endif
556   va_end (args);
557 #else
558   fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
559 #endif
560
561   ++error_message_count;
562   if (errnum)
563     fprintf (stderr, ": %s", strerror (errnum));
564   putc ('\n', stderr);
565   fflush (stderr);
566   if (status)
567     exit (status);
568 }