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 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);
238 #if defined(HAVE_VSNPRINTF) || defined(_LIBC)
241 n = vsnprintf (partial_message + partial_message_size_used,
242 partial_message_size - partial_message_size_used,
245 if (n < partial_message_size - partial_message_size_used)
247 partial_message_size_used += n;
251 partial_message_size += 2048;
252 partial_message = REALLOC (partial_message, partial_message_size);
255 vsprintf (partial_message + partial_message_size_used, message, args);
256 partial_message_size_used += strlen(partial_message+partial_message_size_used);
258 /* Attempt to catch memory overwrites... */
259 if (partial_message_size_used >= partial_message_size)
261 partial_message_size_used = 0;
262 report (stderr, GT_("partial error message buffer overflow"));
270 n = snprintf (partial_message + partial_message_size_used,
271 partial_message_size - partial_message_size_used,
272 message, a1, a2, a3, a4, a5, a6, a7, a8);
274 if (n < partial_message_size - partial_message_size_used)
276 partial_message_size_used += n;
280 partial_message_size += 2048;
281 partial_message = REALLOC (partial_message, partial_message_size);
284 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
286 /* Attempt to catch memory overwrites... */
287 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
289 partial_message_size_used = 0;
290 report (stderr, GT_("partial error message buffer overflow"));
295 if (use_stderr && partial_message_size_used != 0)
297 partial_message_size_used = 0;
298 fputs(partial_message, errfp);
302 /* Complete a report message by appending MESSAGE, which is a printf-style
303 format string with optional args, to the existing report message (which may
304 be empty.) The completed report message is then printed (and reset to
310 report_complete (FILE *errfp, const char *message, ...)
312 report_complete (FILE *errfp, message, va_alist)
322 /* Make an initial guess for the size of any single message fragment. */
323 if (partial_message_size == 0)
325 partial_message_size_used = 0;
326 partial_message_size = 2048;
327 partial_message = MALLOC (partial_message_size);
330 if (partial_message_size - partial_message_size_used < 1024)
332 partial_message_size += 2048;
333 partial_message = REALLOC (partial_message, partial_message_size);
336 #if defined(VA_START)
337 VA_START (args, message);
338 #if defined(HAVE_VSNPRINTF) || defined(_LIBC)
341 n = vsnprintf (partial_message + partial_message_size_used,
342 partial_message_size - partial_message_size_used,
345 if (n < partial_message_size - partial_message_size_used)
347 partial_message_size_used += n;
351 partial_message_size += 2048;
352 partial_message = REALLOC (partial_message, partial_message_size);
355 vsprintf (partial_message + partial_message_size_used, message, args);
356 partial_message_size_used += strlen(partial_message+partial_message_size_used);
358 /* Attempt to catch memory overwrites... */
359 if (partial_message_size_used >= partial_message_size)
361 partial_message_size_used = 0;
362 report (stderr, GT_("partial error message buffer overflow"));
370 n = snprintf (partial_message + partial_message_size_used,
371 partial_message_size - partial_message_size_used,
372 message, a1, a2, a3, a4, a5, a6, a7, a8);
374 if (n < partial_message_size - partial_message_size_used)
376 partial_message_size_used += n;
380 partial_message_size += 2048;
381 partial_message = REALLOC (partial_message, partial_message_size);
384 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
386 /* Attempt to catch memory overwrites... */
387 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
389 partial_message_size_used = 0;
390 report (stderr, GT_("partial error message buffer overflow"));
395 /* Finally... print it. */
396 partial_message_size_used = 0;
400 fputs(partial_message, errfp);
403 ++report_message_count;
406 report(errfp, "%s", partial_message);
409 /* Sometimes we want to have at most one error per line. This
410 variable controls whether this mode is selected or not. */
411 static int error_one_per_line;
415 report_at_line (FILE *errfp, int errnum, const char *file_name,
416 unsigned int line_number, const char *message, ...)
418 report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
420 const char *file_name;
421 unsigned int line_number;
430 if (error_one_per_line)
432 static const char *old_file_name;
433 static unsigned int old_line_number;
435 if (old_line_number == line_number &&
436 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
437 /* Simply return and print nothing. */
440 old_file_name = file_name;
441 old_line_number = line_number;
444 if (report_print_progname)
445 (*report_print_progname) ();
449 if ( *message == '\n' )
451 fputc( '\n', errfp );
454 fprintf (errfp, "%s:", program_name);
457 if (file_name != NULL)
458 fprintf (errfp, "%s:%u: ", file_name, line_number);
461 VA_START (args, message);
462 # if defined(HAVE_VPRINTF) || defined(_LIBC)
463 vfprintf (errfp, message, args);
465 _doprnt (message, args, errfp);
469 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
472 ++report_message_count;
474 fprintf (errfp, ": %s", strerror (errnum));