]> Pileus Git - ~andy/fetchmail/blob - report.c
Remove dead USE_TCPIP_FOR_DNS code.
[~andy/fetchmail] / report.c
1 /* report.c -- report function for noninteractive utilities
2  *
3  * For license terms, see the file COPYING in this directory.
4  *
5  * This code is distantly descended from the error.c module written by
6  * David MacKenzie <djm@gnu.ai.mit.edu>.  It was redesigned and
7  * rewritten by Dave Bodenstab, then redesigned again by ESR, then
8  * bludgeoned into submission for SunOS 4.1.3 by Chris Cheyney
9  * <cheyney@netcom.com>.  It works even when the return from
10  * vprintf(3) is unreliable.
11  */
12
13 #ifdef HAVE_CONFIG_H
14 # include "config.h"
15 #endif
16 #include <stdio.h>
17 #include <errno.h>
18 #include <string.h>
19 #if defined(HAVE_SYSLOG)
20 #include <syslog.h>
21 #endif
22 #include "i18n.h"
23 #include "fetchmail.h"
24
25 #if defined(HAVE_VPRINTF) || defined(HAVE_DOPRNT) || defined(_LIBC) || defined(HAVE_STDARG_H)
26 # if HAVE_STDARG_H
27 #  include <stdarg.h>
28 #  define VA_START(args, lastarg) va_start(args, lastarg)
29 # else
30 #  include <varargs.h>
31 #  define VA_START(args, lastarg) va_start(args)
32 # endif
33 #else
34 # define va_alist a1, a2, a3, a4, a5, a6, a7, a8
35 # define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
36 #endif
37
38 #define MALLOC(n)       xmalloc(n)      
39 #define REALLOC(n,s)    xrealloc(n,s)   
40
41 /* If NULL, report will flush stderr, then print on stderr the program
42    name, a colon and a space.  Otherwise, report will call this
43    function without parameters instead.  */
44 static void (*report_print_progname) (
45 #if __STDC__ - 0
46                               void
47 #endif
48                               );
49
50 /* Used by report_build() and report_complete() to accumulate partial messages.
51  */
52 static unsigned int partial_message_size = 0;
53 static unsigned int partial_message_size_used = 0;
54 static char *partial_message;
55 static unsigned use_stderr;
56 static unsigned int use_syslog;
57
58 /* This variable is incremented each time `report' is called.  */
59 static unsigned int report_message_count;
60
61 #ifdef _LIBC
62 /* In the GNU C library, there is a predefined variable for this.  */
63
64 # define program_name program_invocation_name
65 # include <errno.h>
66
67 #else
68
69 # if !HAVE_STRERROR && !defined(strerror)
70 char *strerror (int errnum)
71 {
72     extern char *sys_errlist[];
73     extern int sys_nerr;
74
75     if (errnum > 0 && errnum <= sys_nerr)
76         return sys_errlist[errnum];
77     return GT_("Unknown system error");
78 }
79 # endif /* HAVE_STRERROR */
80 #endif  /* _LIBC */
81
82 /* Print the program name and error message MESSAGE, which is a printf-style
83    format string with optional args.
84    If ERRNUM is nonzero, print its corresponding system error message. */
85 /* VARARGS */
86
87 void
88 #ifdef HAVE_STDARG_H
89 report (FILE *errfp, const char *message, ...)
90 #else
91 report (FILE *errfp, message, va_alist)
92      const char *message;
93      va_dcl
94 #endif
95 {
96 #ifdef VA_START
97     va_list args;
98 #endif
99
100     /* If a partially built message exists, print it now so it's not lost.  */
101     if (partial_message_size_used != 0)
102     {
103         partial_message_size_used = 0;
104         report (errfp, GT_("%s (log message incomplete)"), partial_message);
105     }
106
107 #if defined(HAVE_SYSLOG)
108     if (use_syslog)
109     {
110         int priority;
111
112 #ifdef VA_START
113         VA_START (args, message);
114 #endif
115         priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
116
117 #ifdef HAVE_VSYSLOG
118         vsyslog (priority, message, args);
119 #else
120         {
121             char *a1 = va_arg(args, char *);
122             char *a2 = va_arg(args, char *);
123             char *a3 = va_arg(args, char *);
124             char *a4 = va_arg(args, char *);
125             char *a5 = va_arg(args, char *);
126             char *a6 = va_arg(args, char *);
127             char *a7 = va_arg(args, char *);
128             char *a8 = va_arg(args, char *);
129             syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
130         }
131 #endif
132
133 #ifdef VA_START
134         va_end(args);
135 #endif
136     }
137     else
138 #endif
139     {
140         if (report_print_progname)
141             (*report_print_progname) ();
142         else
143         {
144             fflush (errfp);
145             if ( *message == '\n' )
146             {
147                 fputc( '\n', errfp );
148                 ++message;
149             }
150             fprintf (errfp, "%s: ", program_name);
151         }
152
153 #ifdef VA_START
154         VA_START (args, message);
155 # if defined(HAVE_VPRINTF) || defined(_LIBC)
156         vfprintf (errfp, message, args);
157 # else
158         _doprnt (message, args, errfp);
159 # endif
160         va_end (args);
161 #else
162         fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
163 #endif
164         fflush (errfp);
165     }
166     ++report_message_count;
167 }
168 \f
169 /*
170  * Calling report_init(1) causes report_build and report_complete to write
171  * to errfp without buffering.  This is needed for the ticker dots to
172  * work correctly.
173  */
174 void report_init(int mode)
175 {
176     switch(mode)
177     {
178     case 0:                     /* errfp, buffered */
179     default:
180         use_stderr = FALSE;
181         use_syslog = FALSE;
182         break;
183
184     case 1:                     /* errfp, unbuffered */
185         use_stderr = TRUE;
186         use_syslog = FALSE;
187         break;
188
189 #ifdef HAVE_SYSLOG
190     case -1:                    /* syslogd */
191         use_stderr = FALSE;
192         use_syslog = TRUE;
193         break;
194 #endif /* HAVE_SYSLOG */
195     }
196 }
197 \f
198 /* Build an report message by appending MESSAGE, which is a printf-style
199    format string with optional args, to the existing report message (which may
200    be empty.)  The completed report message is finally printed (and reset to
201    empty) by calling report_complete().
202    If an intervening call to report() occurs when a partially constructed
203    message exists, then, in an attempt to keep the messages in their proper
204    sequence, the partial message will be printed as-is (with a trailing 
205    newline) before report() prints its message. */
206 /* VARARGS */
207
208 static void rep_ensuresize(void) {
209     /* Make an initial guess for the size of any single message fragment.  */
210     if (partial_message_size == 0)
211     {
212         partial_message_size_used = 0;
213         partial_message_size = 2048;
214         partial_message = MALLOC (partial_message_size);
215     }
216     else
217         if (partial_message_size - partial_message_size_used < 1024)
218         {
219             partial_message_size += 2048;
220             partial_message = REALLOC (partial_message, partial_message_size);
221         }
222 }
223
224 void
225 #ifdef HAVE_STDARG_H
226 report_build (FILE *errfp, const char *message, ...)
227 #else
228 report_build (FILE *errfp, message, va_alist)
229      const char *message;
230      va_dcl
231 #endif
232 {
233 #ifdef VA_START
234     va_list args;
235     int n;
236 #endif
237
238     rep_ensuresize();
239
240 #if defined(VA_START)
241     VA_START (args, message);
242     for ( ; ; )
243     {
244         n = vsnprintf (partial_message + partial_message_size_used, partial_message_size - partial_message_size_used,
245                        message, args);
246
247         if (n >= 0
248             && (unsigned)n < partial_message_size - partial_message_size_used)
249         {
250             partial_message_size_used += n;
251             break;
252         }
253
254         partial_message_size += 2048;
255         partial_message = REALLOC (partial_message, partial_message_size);
256     }
257     va_end (args);
258 #else
259     for ( ; ; )
260     {
261         n = snprintf (partial_message + partial_message_size_used,
262                       partial_message_size - partial_message_size_used,
263                       message, a1, a2, a3, a4, a5, a6, a7, a8);
264
265         if (n >= 0
266             && (unsigned)n < partial_message_size - partial_message_size_used)
267         {
268             partial_message_size_used += n;
269             break;
270         }
271
272         partial_message_size += 2048;
273         partial_message = REALLOC (partial_message, partial_message_size);
274     }
275 #endif
276
277     if (use_stderr && partial_message_size_used != 0)
278     {
279         partial_message_size_used = 0;
280         fputs(partial_message, errfp);
281     }
282 }
283 \f
284 /* Complete a report message by appending MESSAGE, which is a printf-style
285    format string with optional args, to the existing report message (which may
286    be empty.)  The completed report message is then printed (and reset to
287    empty.) */
288 /* VARARGS */
289
290 void
291 #ifdef HAVE_STDARG_H
292 report_complete (FILE *errfp, const char *message, ...)
293 #else
294 report_complete (FILE *errfp, message, va_alist)
295      const char *message;
296      va_dcl
297 #endif
298 {
299 #ifdef VA_START
300     va_list args;
301     int n;
302 #endif
303
304     rep_ensuresize();
305
306 #if defined(VA_START)
307     VA_START (args, message);
308     for ( ; ; )
309     {
310         n = vsnprintf (partial_message + partial_message_size_used,
311                        partial_message_size - partial_message_size_used,
312                        message, args);
313
314         /* old glibc versions return -1 for truncation */
315         if (n >= 0
316             && (unsigned)n < partial_message_size - partial_message_size_used)
317         {
318             partial_message_size_used += n;
319             break;
320         }
321
322         partial_message_size += 2048;
323         partial_message = REALLOC (partial_message, partial_message_size);
324     }
325     va_end (args);
326 #else
327     for ( ; ; )
328     {
329         n = snprintf (partial_message + partial_message_size_used,
330                       partial_message_size - partial_message_size_used,
331                       message, a1, a2, a3, a4, a5, a6, a7, a8);
332
333         if (n >= 0
334             && (unsigned)n < partial_message_size - partial_message_size_used)
335         {
336             partial_message_size_used += n;
337             break;
338         }
339
340         partial_message_size += 2048;
341         partial_message = REALLOC (partial_message, partial_message_size);
342     }
343 #endif
344
345     /* Finally... print it.  */
346     partial_message_size_used = 0;
347
348     if (use_stderr)
349     {
350         fputs(partial_message, errfp);
351         fflush (errfp);
352
353         ++report_message_count;
354     }
355     else
356         report(errfp, "%s", partial_message);
357 }
358 \f
359 /* Sometimes we want to have at most one error per line.  This
360    variable controls whether this mode is selected or not.  */
361 static int error_one_per_line;
362
363 void
364 #ifdef HAVE_STDARG_H
365 report_at_line (FILE *errfp, int errnum, const char *file_name,
366                unsigned int line_number, const char *message, ...)
367 #else
368 report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
369      int errnum;
370      const char *file_name;
371      unsigned int line_number;
372      const char *message;
373      va_dcl
374 #endif
375 {
376 #ifdef VA_START
377     va_list args;
378 #endif
379
380     if (error_one_per_line)
381     {
382         static const char *old_file_name;
383         static unsigned int old_line_number;
384
385         if (old_line_number == line_number &&
386             (file_name == old_file_name || !strcmp (old_file_name, file_name)))
387             /* Simply return and print nothing.  */
388             return;
389
390         old_file_name = file_name;
391         old_line_number = line_number;
392     }
393
394     if (report_print_progname)
395         (*report_print_progname) ();
396     else
397     {
398         fflush (errfp);
399         if ( *message == '\n' )
400         {
401             fputc( '\n', errfp );
402             ++message;
403         }
404         fprintf (errfp, "%s:", program_name);
405     }
406
407     if (file_name != NULL)
408         fprintf (errfp, "%s:%u: ", file_name, line_number);
409
410 #ifdef VA_START
411     VA_START (args, message);
412 # if defined(HAVE_VPRINTF) || defined(_LIBC)
413     vfprintf (errfp, message, args);
414 # else
415     _doprnt (message, args, errfp);
416 # endif
417     va_end (args);
418 #else
419     fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
420 #endif
421
422     ++report_message_count;
423     if (errnum)
424         fprintf (errfp, ": %s", strerror (errnum));
425     putc ('\n', errfp);
426     fflush (errfp);
427 }