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 use_stderr;
47 static unsigned int use_syslog;
49 /* This variable is incremented each time `report' is called. */
50 static unsigned int report_message_count;
53 /* In the GNU C library, there is a predefined variable for this. */
55 # define program_name program_invocation_name
60 # if !HAVE_STRERROR && !defined(strerror)
61 char *strerror (int errnum)
63 extern char *sys_errlist[];
66 if (errnum > 0 && errnum <= sys_nerr)
67 return sys_errlist[errnum];
68 return GT_("Unknown system error");
70 # endif /* HAVE_STRERROR */
73 /* Print the program name and error message MESSAGE, which is a printf-style
74 format string with optional args.
75 If ERRNUM is nonzero, print its corresponding system error message. */
80 report (FILE *errfp, const char *message, ...)
82 report (FILE *errfp, message, va_alist)
91 /* If a partially built message exists, print it now so it's not lost. */
92 if (partial_message_size_used != 0)
94 partial_message_size_used = 0;
95 report (errfp, GT_("%s (log message incomplete)"), partial_message);
98 #if defined(HAVE_SYSLOG)
104 VA_START (args, message);
106 priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
109 vsyslog (priority, message, args);
112 char *a1 = va_arg(args, char *);
113 char *a2 = va_arg(args, char *);
114 char *a3 = va_arg(args, char *);
115 char *a4 = va_arg(args, char *);
116 char *a5 = va_arg(args, char *);
117 char *a6 = va_arg(args, char *);
118 char *a7 = va_arg(args, char *);
119 char *a8 = va_arg(args, char *);
120 syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
132 if ( *message == '\n' )
134 fputc( '\n', errfp );
137 fprintf (errfp, "%s: ", program_name);
140 VA_START (args, message);
141 # if defined(HAVE_VPRINTF) || defined(_LIBC)
142 vfprintf (errfp, message, args);
144 _doprnt (message, args, errfp);
148 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
152 ++report_message_count;
156 * Calling report_init(1) causes report_build and report_complete to write
157 * to errfp without buffering. This is needed for the ticker dots to
160 void report_init(int mode)
164 case 0: /* errfp, buffered */
170 case 1: /* errfp, unbuffered */
176 case -1: /* syslogd */
180 #endif /* HAVE_SYSLOG */
184 /* Build an report message by appending MESSAGE, which is a printf-style
185 format string with optional args, to the existing report message (which may
186 be empty.) The completed report message is finally printed (and reset to
187 empty) by calling report_complete().
188 If an intervening call to report() occurs when a partially constructed
189 message exists, then, in an attempt to keep the messages in their proper
190 sequence, the partial message will be printed as-is (with a trailing
191 newline) before report() prints its message. */
194 static void rep_ensuresize(void) {
195 /* Make an initial guess for the size of any single message fragment. */
196 if (partial_message_size == 0)
198 partial_message_size_used = 0;
199 partial_message_size = 2048;
200 partial_message = (char *)MALLOC (partial_message_size);
203 if (partial_message_size - partial_message_size_used < 1024)
205 partial_message_size += 2048;
206 partial_message = (char *)REALLOC (partial_message, partial_message_size);
212 report_build (FILE *errfp, const char *message, ...)
214 report_build (FILE *errfp, message, va_alist)
226 #if defined(VA_START)
230 * args has to be initialized before every call of vsnprintf(),
231 * because vsnprintf() invokes va_arg macro and thus args is
232 * undefined after the call.
234 VA_START(args, message);
235 n = vsnprintf (partial_message + partial_message_size_used, partial_message_size - partial_message_size_used,
240 && (unsigned)n < partial_message_size - partial_message_size_used)
242 partial_message_size_used += n;
246 partial_message_size += 2048;
247 partial_message = (char *)REALLOC (partial_message, partial_message_size);
252 n = snprintf (partial_message + partial_message_size_used,
253 partial_message_size - partial_message_size_used,
254 message, a1, a2, a3, a4, a5, a6, a7, a8);
257 && (unsigned)n < partial_message_size - partial_message_size_used)
259 partial_message_size_used += n;
263 partial_message_size += 2048;
264 partial_message = REALLOC (partial_message, partial_message_size);
268 if (use_stderr && partial_message_size_used != 0)
270 partial_message_size_used = 0;
271 fputs(partial_message, errfp);
275 /* Complete a report message by appending MESSAGE, which is a printf-style
276 format string with optional args, to the existing report message (which may
277 be empty.) The completed report message is then printed (and reset to
283 report_complete (FILE *errfp, const char *message, ...)
285 report_complete (FILE *errfp, message, va_alist)
297 #if defined(VA_START)
300 VA_START(args, message);
301 n = vsnprintf (partial_message + partial_message_size_used,
302 partial_message_size - partial_message_size_used,
306 /* old glibc versions return -1 for truncation */
308 && (unsigned)n < partial_message_size - partial_message_size_used)
310 partial_message_size_used += n;
314 partial_message_size += 2048;
315 partial_message = (char *)REALLOC (partial_message, partial_message_size);
320 n = snprintf (partial_message + partial_message_size_used,
321 partial_message_size - partial_message_size_used,
322 message, a1, a2, a3, a4, a5, a6, a7, a8);
325 && (unsigned)n < partial_message_size - partial_message_size_used)
327 partial_message_size_used += n;
331 partial_message_size += 2048;
332 partial_message = REALLOC (partial_message, partial_message_size);
336 /* Finally... print it. */
337 partial_message_size_used = 0;
341 fputs(partial_message, errfp);
344 ++report_message_count;
347 report(errfp, "%s", partial_message);
350 /* Sometimes we want to have at most one error per line. This
351 variable controls whether this mode is selected or not. */
352 static int error_one_per_line;
356 report_at_line (FILE *errfp, int errnum, const char *file_name,
357 unsigned int line_number, const char *message, ...)
359 report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
361 const char *file_name;
362 unsigned int line_number;
371 if (error_one_per_line)
373 static const char *old_file_name;
374 static unsigned int old_line_number;
376 if (old_line_number == line_number &&
377 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
378 /* Simply return and print nothing. */
381 old_file_name = file_name;
382 old_line_number = line_number;
386 if ( *message == '\n' )
388 fputc( '\n', errfp );
391 fprintf (errfp, "%s:", program_name);
393 if (file_name != NULL)
394 fprintf (errfp, "%s:%u: ", file_name, line_number);
397 VA_START (args, message);
398 # if defined(HAVE_VPRINTF) || defined(_LIBC)
399 vfprintf (errfp, message, args);
401 _doprnt (message, args, errfp);
405 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
408 ++report_message_count;
410 fprintf (errfp, ": %s", strerror (errnum));