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.
18 #if defined(HAVE_SYSLOG)
22 #include "fetchmail.h"
24 #if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC || HAVE_STDARG_H
27 # define VA_START(args, lastarg) va_start(args, lastarg)
30 # define VA_START(args, lastarg) va_start(args)
33 # define va_alist a1, a2, a3, a4, a5, a6, a7, a8
34 # define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
37 #define MALLOC(n) xmalloc(n)
38 #define REALLOC(n,s) xrealloc(n,s)
40 /* If NULL, report will flush stderr, then print on stderr the program
41 name, a colon and a space. Otherwise, report will call this
42 function without parameters instead. */
43 void (*report_print_progname) (
49 /* Used by report_build() and report_complete() to accumulate partial messages.
51 static unsigned int partial_message_size = 0;
52 static unsigned int partial_message_size_used = 0;
53 static char *partial_message;
54 static unsigned use_stderr;
55 static unsigned int use_syslog;
57 /* This variable is incremented each time `report' is called. */
58 static unsigned int report_message_count;
61 /* In the GNU C library, there is a predefined variable for this. */
63 # define program_name program_invocation_name
68 /* The calling program should define program_name and set it to the
69 name of the executing program. */
70 extern char *program_name;
72 # if !HAVE_STRERROR && !defined(strerror)
73 char *strerror (int errnum)
75 extern char *sys_errlist[];
78 if (errnum > 0 && errnum <= sys_nerr)
79 return sys_errlist[errnum];
80 return GT_("Unknown system error");
82 # endif /* HAVE_STRERROR */
85 /* Print the program name and error message MESSAGE, which is a printf-style
86 format string with optional args.
87 If ERRNUM is nonzero, print its corresponding system error message. */
92 report (FILE *errfp, const char *message, ...)
94 report (FILE *errfp, message, va_alist)
103 /* If a partially built message exists, print it now so it's not lost. */
104 if (partial_message_size_used != 0)
106 partial_message_size_used = 0;
107 report (errfp, 0, GT_("%s (log message incomplete)"), partial_message);
110 #if defined(HAVE_SYSLOG)
116 VA_START (args, message);
118 priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
121 vsyslog (priority, message, args);
124 char *a1 = va_arg(args, char *);
125 char *a2 = va_arg(args, char *);
126 char *a3 = va_arg(args, char *);
127 char *a4 = va_arg(args, char *);
128 char *a5 = va_arg(args, char *);
129 char *a6 = va_arg(args, char *);
130 char *a7 = va_arg(args, char *);
131 char *a8 = va_arg(args, char *);
132 syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
143 if (report_print_progname)
144 (*report_print_progname) ();
148 if ( *message == '\n' )
150 fputc( '\n', errfp );
153 fprintf (errfp, "%s: ", program_name);
157 VA_START (args, message);
158 # if HAVE_VPRINTF || _LIBC
159 vfprintf (errfp, message, args);
161 _doprnt (message, args, errfp);
165 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
169 ++report_message_count;
173 * Calling report_init(1) causes report_build and report_complete to write
174 * to errfp without buffering. This is needed for the ticker dots to
177 void report_init(int mode)
181 case 0: /* errfp, buffered */
187 case 1: /* errfp, unbuffered */
193 case -1: /* syslogd */
197 #endif /* HAVE_SYSLOG */
201 /* Build an report message by appending MESSAGE, which is a printf-style
202 format string with optional args, to the existing report message (which may
203 be empty.) The completed report message is finally printed (and reset to
204 empty) by calling report_complete().
205 If an intervening call to report() occurs when a partially constructed
206 message exists, then, in an attempt to keep the messages in their proper
207 sequence, the partial message will be printed as-is (with a trailing
208 newline) before report() prints its message. */
213 report_build (FILE *errfp, const char *message, ...)
215 report_build (FILE *errfp, message, va_alist)
225 /* Make an initial guess for the size of any single message fragment. */
226 if (partial_message_size == 0)
228 partial_message_size_used = 0;
229 partial_message_size = 2048;
230 partial_message = MALLOC (partial_message_size);
233 if (partial_message_size - partial_message_size_used < 1024)
235 partial_message_size += 2048;
236 partial_message = REALLOC (partial_message, partial_message_size);
239 #if defined(VA_START)
240 VA_START (args, message);
241 #if HAVE_VSNPRINTF || _LIBC
244 n = vsnprintf (partial_message + partial_message_size_used,
245 partial_message_size - partial_message_size_used,
248 if (n < partial_message_size - partial_message_size_used)
250 partial_message_size_used += n;
254 partial_message_size += 2048;
255 partial_message = REALLOC (partial_message, partial_message_size);
258 vsprintf (partial_message + partial_message_size_used, message, args);
259 partial_message_size_used += strlen(partial_message+partial_message_size_used);
261 /* Attempt to catch memory overwrites... */
262 if (partial_message_size_used >= partial_message_size)
264 partial_message_size_used = 0;
265 report (stderr, GT_("partial error message buffer overflow"));
273 n = snprintf (partial_message + partial_message_size_used,
274 partial_message_size - partial_message_size_used,
275 message, a1, a2, a3, a4, a5, a6, a7, a8);
277 if (n < partial_message_size - partial_message_size_used)
279 partial_message_size_used += n;
283 partial_message_size += 2048;
284 partial_message = REALLOC (partial_message, partial_message_size);
287 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
289 /* Attempt to catch memory overwrites... */
290 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
292 partial_message_size_used = 0;
293 report (stderr, GT_("partial error message buffer overflow"));
298 if (use_stderr && partial_message_size_used != 0)
300 partial_message_size_used = 0;
301 fputs(partial_message, errfp);
305 /* Complete a report message by appending MESSAGE, which is a printf-style
306 format string with optional args, to the existing report message (which may
307 be empty.) The completed report message is then printed (and reset to
313 report_complete (FILE *errfp, const char *message, ...)
315 report_complete (FILE *errfp, message, va_alist)
325 /* Make an initial guess for the size of any single message fragment. */
326 if (partial_message_size == 0)
328 partial_message_size_used = 0;
329 partial_message_size = 2048;
330 partial_message = MALLOC (partial_message_size);
333 if (partial_message_size - partial_message_size_used < 1024)
335 partial_message_size += 2048;
336 partial_message = REALLOC (partial_message, partial_message_size);
339 #if defined(VA_START)
340 VA_START (args, message);
341 #if HAVE_VSNPRINTF || _LIBC
344 n = vsnprintf (partial_message + partial_message_size_used,
345 partial_message_size - partial_message_size_used,
348 if (n < partial_message_size - partial_message_size_used)
350 partial_message_size_used += n;
354 partial_message_size += 2048;
355 partial_message = REALLOC (partial_message, partial_message_size);
358 vsprintf (partial_message + partial_message_size_used, message, args);
359 partial_message_size_used += strlen(partial_message+partial_message_size_used);
361 /* Attempt to catch memory overwrites... */
362 if (partial_message_size_used >= partial_message_size)
364 partial_message_size_used = 0;
365 report (stderr, GT_("partial error message buffer overflow"));
373 n = snprintf (partial_message + partial_message_size_used,
374 partial_message_size - partial_message_size_used,
375 message, a1, a2, a3, a4, a5, a6, a7, a8);
377 if (n < partial_message_size - partial_message_size_used)
379 partial_message_size_used += n;
383 partial_message_size += 2048;
384 partial_message = REALLOC (partial_message, partial_message_size);
387 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
389 /* Attempt to catch memory overwrites... */
390 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
392 partial_message_size_used = 0;
393 report (stderr, GT_("partial error message buffer overflow"));
398 /* Finally... print it. */
399 partial_message_size_used = 0;
403 fputs(partial_message, errfp);
406 ++report_message_count;
409 report(errfp, "%s", partial_message);
412 /* Sometimes we want to have at most one error per line. This
413 variable controls whether this mode is selected or not. */
414 int error_one_per_line;
418 report_at_line (FILE *errfp, int errnum, const char *file_name,
419 unsigned int line_number, const char *message, ...)
421 report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
423 const char *file_name;
424 unsigned int line_number;
433 if (error_one_per_line)
435 static const char *old_file_name;
436 static unsigned int old_line_number;
438 if (old_line_number == line_number &&
439 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
440 /* Simply return and print nothing. */
443 old_file_name = file_name;
444 old_line_number = line_number;
447 if (report_print_progname)
448 (*report_print_progname) ();
452 if ( *message == '\n' )
454 fputc( '\n', errfp );
457 fprintf (errfp, "%s:", program_name);
460 if (file_name != NULL)
461 fprintf (errfp, "%s:%d: ", file_name, line_number);
464 VA_START (args, message);
465 # if HAVE_VPRINTF || _LIBC
466 vfprintf (errfp, message, args);
468 _doprnt (message, args, errfp);
472 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
475 ++report_message_count;
477 fprintf (errfp, ": %s", strerror (errnum));