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 /* Used by report_build() and report_complete() to accumulate partial messages.
43 static unsigned int partial_message_size = 0;
44 static unsigned int partial_message_size_used = 0;
45 static char *partial_message;
46 static unsigned unbuffered;
47 static unsigned int use_syslog;
50 /* In the GNU C library, there is a predefined variable for this. */
52 # define program_name program_invocation_name
57 # if !HAVE_STRERROR && !defined(strerror)
58 char *strerror (int errnum)
60 extern char *sys_errlist[];
63 if (errnum > 0 && errnum <= sys_nerr)
64 return sys_errlist[errnum];
65 return GT_("Unknown system error");
67 # endif /* HAVE_STRERROR */
70 /* Print the program name and error message MESSAGE, which is a printf-style
71 format string with optional args. */
75 report (FILE *errfp, const char *message, ...)
77 report (FILE *errfp, message, va_alist)
86 /* If a partially built message exists, print it now so it's not lost. */
87 if (partial_message_size_used != 0)
89 partial_message_size_used = 0;
90 report (errfp, GT_("%s (log message incomplete)\n"), partial_message);
93 #if defined(HAVE_SYSLOG)
99 VA_START (args, message);
101 priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
104 vsyslog (priority, message, args);
107 char *a1 = va_arg(args, char *);
108 char *a2 = va_arg(args, char *);
109 char *a3 = va_arg(args, char *);
110 char *a4 = va_arg(args, char *);
111 char *a5 = va_arg(args, char *);
112 char *a6 = va_arg(args, char *);
113 char *a7 = va_arg(args, char *);
114 char *a8 = va_arg(args, char *);
115 syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
123 else /* i. e. not using syslog */
127 if ( *message == '\n' )
129 fputc( '\n', errfp );
132 fprintf (errfp, "%s: ", program_name);
135 VA_START (args, message);
136 # if defined(HAVE_VPRINTF) || defined(_LIBC)
137 vfprintf (errfp, message, args);
139 _doprnt (message, args, errfp);
143 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
150 * Calling report_init(1) causes report_build and report_complete to write
151 * to errfp without buffering. This is needed for the ticker dots to
154 void report_init(int mode)
158 case 0: /* errfp, buffered */
164 case 1: /* errfp, unbuffered */
170 case -1: /* syslogd */
174 #endif /* HAVE_SYSLOG */
178 /* Build an report message by appending MESSAGE, which is a printf-style
179 format string with optional args, to the existing report message (which may
180 be empty.) The completed report message is finally printed (and reset to
181 empty) by calling report_complete().
182 If an intervening call to report() occurs when a partially constructed
183 message exists, then, in an attempt to keep the messages in their proper
184 sequence, the partial message will be printed as-is (with a trailing
185 newline) before report() prints its message. */
188 static void rep_ensuresize(void) {
189 /* Make an initial guess for the size of any single message fragment. */
190 if (partial_message_size == 0)
192 partial_message_size_used = 0;
193 partial_message_size = 2048;
194 partial_message = (char *)MALLOC (partial_message_size);
197 if (partial_message_size - partial_message_size_used < 1024)
199 partial_message_size += 2048;
200 partial_message = (char *)REALLOC (partial_message, partial_message_size);
206 report_build (FILE *errfp, const char *message, ...)
208 report_build (FILE *errfp, message, va_alist)
220 #if defined(VA_START)
224 * args has to be initialized before every call of vsnprintf(),
225 * because vsnprintf() invokes va_arg macro and thus args is
226 * undefined after the call.
228 VA_START(args, message);
229 n = vsnprintf (partial_message + partial_message_size_used, partial_message_size - partial_message_size_used,
234 && (unsigned)n < partial_message_size - partial_message_size_used)
236 partial_message_size_used += n;
240 partial_message_size += 2048;
241 partial_message = (char *)REALLOC (partial_message, partial_message_size);
246 n = snprintf (partial_message + partial_message_size_used,
247 partial_message_size - partial_message_size_used,
248 message, a1, a2, a3, a4, a5, a6, a7, a8);
251 && (unsigned)n < partial_message_size - partial_message_size_used)
253 partial_message_size_used += n;
257 partial_message_size += 2048;
258 partial_message = REALLOC (partial_message, partial_message_size);
262 if (unbuffered && partial_message_size_used != 0)
264 partial_message_size_used = 0;
265 fputs(partial_message, errfp);
269 /* Complete a report message by appending MESSAGE, which is a printf-style
270 format string with optional args, to the existing report message (which may
271 be empty.) The completed report message is then printed (and reset to
277 report_complete (FILE *errfp, const char *message, ...)
279 report_complete (FILE *errfp, message, va_alist)
291 #if defined(VA_START)
294 VA_START(args, message);
295 n = vsnprintf (partial_message + partial_message_size_used,
296 partial_message_size - partial_message_size_used,
300 /* old glibc versions return -1 for truncation */
302 && (unsigned)n < partial_message_size - partial_message_size_used)
304 partial_message_size_used += n;
308 partial_message_size += 2048;
309 partial_message = (char *)REALLOC (partial_message, partial_message_size);
314 n = snprintf (partial_message + partial_message_size_used,
315 partial_message_size - partial_message_size_used,
316 message, a1, a2, a3, a4, a5, a6, a7, a8);
319 && (unsigned)n < partial_message_size - partial_message_size_used)
321 partial_message_size_used += n;
325 partial_message_size += 2048;
326 partial_message = REALLOC (partial_message, partial_message_size);
330 /* Finally... print it. */
331 partial_message_size_used = 0;
335 fputs(partial_message, errfp);
339 report(errfp, "%s", partial_message);
342 /* Sometimes we want to have at most one error per line. This
343 variable controls whether this mode is selected or not. */
344 static int error_one_per_line;
346 /* If errnum is nonzero, print its corresponding system error message. */
349 report_at_line (FILE *errfp, int errnum, const char *file_name,
350 unsigned int line_number, const char *message, ...)
352 report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
354 const char *file_name;
355 unsigned int line_number;
364 if (error_one_per_line)
366 static const char *old_file_name;
367 static unsigned int old_line_number;
369 if (old_line_number == line_number &&
370 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
371 /* Simply return and print nothing. */
374 old_file_name = file_name;
375 old_line_number = line_number;
379 if ( *message == '\n' )
381 fputc( '\n', errfp );
384 fprintf (errfp, "%s:", program_name);
386 if (file_name != NULL)
387 fprintf (errfp, "%s:%u: ", file_name, line_number);
390 VA_START (args, message);
391 # if defined(HAVE_VPRINTF) || defined(_LIBC)
392 vfprintf (errfp, message, args);
394 _doprnt (message, args, errfp);
398 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
402 fprintf (errfp, ": %s", strerror (errnum));