1 /* report.c -- report function for noninteractive utilities
3 * For license terms, see the file COPYING in this directory.
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.
19 #if defined(HAVE_SYSLOG)
23 #include "fetchmail.h"
25 #if defined(HAVE_VPRINTF) || defined(HAVE_DOPRNT) || defined(_LIBC) || defined(HAVE_STDARG_H)
28 # define VA_START(args, lastarg) va_start(args, lastarg)
31 # define VA_START(args, lastarg) va_start(args)
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;
38 #define MALLOC(n) xmalloc(n)
39 #define REALLOC(n,s) xrealloc(n,s)
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) (
50 /* Used by report_build() and report_complete() to accumulate partial messages.
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;
58 /* This variable is incremented each time `report' is called. */
59 static unsigned int report_message_count;
62 /* In the GNU C library, there is a predefined variable for this. */
64 # define program_name program_invocation_name
69 # if !HAVE_STRERROR && !defined(strerror)
70 char *strerror (int errnum)
72 extern char *sys_errlist[];
75 if (errnum > 0 && errnum <= sys_nerr)
76 return sys_errlist[errnum];
77 return GT_("Unknown system error");
79 # endif /* HAVE_STRERROR */
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. */
89 report (FILE *errfp, const char *message, ...)
91 report (FILE *errfp, message, va_alist)
100 /* If a partially built message exists, print it now so it's not lost. */
101 if (partial_message_size_used != 0)
103 partial_message_size_used = 0;
104 report (errfp, GT_("%s (log message incomplete)"), partial_message);
107 #if defined(HAVE_SYSLOG)
113 VA_START (args, message);
115 priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
118 vsyslog (priority, message, args);
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);
140 if (report_print_progname)
141 (*report_print_progname) ();
145 if ( *message == '\n' )
147 fputc( '\n', errfp );
150 fprintf (errfp, "%s: ", program_name);
154 VA_START (args, message);
155 # if defined(HAVE_VPRINTF) || defined(_LIBC)
156 vfprintf (errfp, message, args);
158 _doprnt (message, args, errfp);
162 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
166 ++report_message_count;
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
174 void report_init(int mode)
178 case 0: /* errfp, buffered */
184 case 1: /* errfp, unbuffered */
190 case -1: /* syslogd */
194 #endif /* HAVE_SYSLOG */
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. */
210 report_build (FILE *errfp, const char *message, ...)
212 report_build (FILE *errfp, message, va_alist)
222 /* Make an initial guess for the size of any single message fragment. */
223 if (partial_message_size == 0)
225 partial_message_size_used = 0;
226 partial_message_size = 2048;
227 partial_message = MALLOC (partial_message_size);
230 if (partial_message_size - partial_message_size_used < 1024)
232 partial_message_size += 2048;
233 partial_message = REALLOC (partial_message, partial_message_size);
236 #if defined(VA_START)
237 VA_START (args, message);
240 n = vsnprintf (partial_message + partial_message_size_used,
241 partial_message_size - partial_message_size_used,
244 if (n < partial_message_size - partial_message_size_used)
246 partial_message_size_used += n;
250 partial_message_size += 2048;
251 partial_message = REALLOC (partial_message, partial_message_size);
257 n = snprintf (partial_message + partial_message_size_used,
258 partial_message_size - partial_message_size_used,
259 message, a1, a2, a3, a4, a5, a6, a7, a8);
261 if (n < partial_message_size - partial_message_size_used)
263 partial_message_size_used += n;
267 partial_message_size += 2048;
268 partial_message = REALLOC (partial_message, partial_message_size);
272 if (use_stderr && partial_message_size_used != 0)
274 partial_message_size_used = 0;
275 fputs(partial_message, errfp);
279 /* Complete a report message by appending MESSAGE, which is a printf-style
280 format string with optional args, to the existing report message (which may
281 be empty.) The completed report message is then printed (and reset to
287 report_complete (FILE *errfp, const char *message, ...)
289 report_complete (FILE *errfp, message, va_alist)
299 /* Make an initial guess for the size of any single message fragment. */
300 if (partial_message_size == 0)
302 partial_message_size_used = 0;
303 partial_message_size = 2048;
304 partial_message = MALLOC (partial_message_size);
307 if (partial_message_size - partial_message_size_used < 1024)
309 partial_message_size += 2048;
310 partial_message = REALLOC (partial_message, partial_message_size);
313 #if defined(VA_START)
314 VA_START (args, message);
317 n = vsnprintf (partial_message + partial_message_size_used,
318 partial_message_size - partial_message_size_used,
321 if (n < partial_message_size - partial_message_size_used)
323 partial_message_size_used += n;
327 partial_message_size += 2048;
328 partial_message = REALLOC (partial_message, partial_message_size);
334 n = snprintf (partial_message + partial_message_size_used,
335 partial_message_size - partial_message_size_used,
336 message, a1, a2, a3, a4, a5, a6, a7, a8);
338 if (n < partial_message_size - partial_message_size_used)
340 partial_message_size_used += n;
344 partial_message_size += 2048;
345 partial_message = REALLOC (partial_message, partial_message_size);
349 /* Finally... print it. */
350 partial_message_size_used = 0;
354 fputs(partial_message, errfp);
357 ++report_message_count;
360 report(errfp, "%s", partial_message);
363 /* Sometimes we want to have at most one error per line. This
364 variable controls whether this mode is selected or not. */
365 static int error_one_per_line;
369 report_at_line (FILE *errfp, int errnum, const char *file_name,
370 unsigned int line_number, const char *message, ...)
372 report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
374 const char *file_name;
375 unsigned int line_number;
384 if (error_one_per_line)
386 static const char *old_file_name;
387 static unsigned int old_line_number;
389 if (old_line_number == line_number &&
390 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
391 /* Simply return and print nothing. */
394 old_file_name = file_name;
395 old_line_number = line_number;
398 if (report_print_progname)
399 (*report_print_progname) ();
403 if ( *message == '\n' )
405 fputc( '\n', errfp );
408 fprintf (errfp, "%s:", program_name);
411 if (file_name != NULL)
412 fprintf (errfp, "%s:%u: ", file_name, line_number);
415 VA_START (args, message);
416 # if defined(HAVE_VPRINTF) || defined(_LIBC)
417 vfprintf (errfp, message, args);
419 _doprnt (message, args, errfp);
423 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
426 ++report_message_count;
428 fprintf (errfp, ": %s", strerror (errnum));