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 reseedesigned 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 #if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC || HAVE_STDARG_H
26 # define VA_START(args, lastarg) va_start(args, lastarg)
29 # define VA_START(args, lastarg) va_start(args)
32 # define va_alist a1, a2, a3, a4, a5, a6, a7, a8
33 # define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
36 #if STDC_HEADERS || _LIBC
45 #include "fetchmail.h"
46 #define MALLOC(n) xmalloc(n)
47 #define REALLOC(n,s) xrealloc(n,s)
49 /* If NULL, report will flush stderr, then print on stderr the program
50 name, a colon and a space. Otherwise, report will call this
51 function without parameters instead. */
52 void (*report_print_progname) (
58 /* Used by report_build() and report_complete() to accumulate partial messages. */
59 static unsigned int partial_message_size = 0;
60 static unsigned int partial_message_size_used = 0;
61 static char *partial_message;
62 static unsigned use_stderr;
63 static unsigned int use_syslog;
65 /* This variable is incremented each time `report' is called. */
66 unsigned int report_message_count;
69 /* In the GNU C library, there is a predefined variable for this. */
71 # define program_name program_invocation_name
76 /* The calling program should define program_name and set it to the
77 name of the executing program. */
78 extern char *program_name;
80 # if !HAVE_STRERROR && !defined(strerror)
81 char *strerror (int errnum)
83 extern char *sys_errlist[];
86 if (errnum > 0 && errnum <= sys_nerr)
87 return sys_errlist[errnum];
88 return GT_("Unknown system error");
90 # endif /* HAVE_STRERROR */
93 /* Print the program name and error message MESSAGE, which is a printf-style
94 format string with optional args.
95 If ERRNUM is nonzero, print its corresponding system error message. */
100 report (FILE *errfp, const char *message, ...)
102 report (FILE *errfp, message, va_alist)
111 /* If a partially built message exists, print it now so it's not lost. */
112 if (partial_message_size_used != 0)
114 partial_message_size_used = 0;
115 report (errfp, 0, GT_("%s (log message incomplete)"), partial_message);
118 #if defined(HAVE_SYSLOG)
124 VA_START (args, message);
126 priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
129 vsyslog (priority, message, args);
132 char *a1 = va_arg(args, char *);
133 char *a2 = va_arg(args, char *);
134 char *a3 = va_arg(args, char *);
135 char *a4 = va_arg(args, char *);
136 char *a5 = va_arg(args, char *);
137 char *a6 = va_arg(args, char *);
138 char *a7 = va_arg(args, char *);
139 char *a8 = va_arg(args, char *);
140 syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
151 if (report_print_progname)
152 (*report_print_progname) ();
156 if ( *message == '\n' )
158 fputc( '\n', errfp );
161 fprintf (errfp, "%s: ", program_name);
165 VA_START (args, message);
166 # if HAVE_VPRINTF || _LIBC
167 vfprintf (errfp, message, args);
169 _doprnt (message, args, errfp);
173 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
177 ++report_message_count;
181 * Calling report_init(1) causes error_build and error_complete to write
182 * to errfp without buffering. This is needed for the ticker dots to
185 void report_init(int mode)
189 case 0: /* errfp, buffered */
195 case 1: /* errfp, unbuffered */
201 case -1: /* syslogd */
205 #endif /* HAVE_SYSLOG */
209 /* Build an report message by appending MESSAGE, which is a printf-style
210 format string with optional args, to the existing report message (which may
211 be empty.) The completed report message is finally printed (and reset to
212 empty) by calling report_complete().
213 If an intervening call to report() occurs when a partially constructed
214 message exists, then, in an attempt to keep the messages in their proper
215 sequence, the partial message will be printed as-is (with a trailing
216 newline) before report() prints its message. */
221 report_build (FILE *errfp, const char *message, ...)
223 report_build (FILE *errfp, message, va_alist)
233 /* Make an initial guess for the size of any single message fragment. */
234 if (partial_message_size == 0)
236 partial_message_size_used = 0;
237 partial_message_size = 2048;
238 partial_message = MALLOC (partial_message_size);
241 if (partial_message_size - partial_message_size_used < 1024)
243 partial_message_size += 2048;
244 partial_message = REALLOC (partial_message, partial_message_size);
247 #if defined(VA_START)
248 VA_START (args, message);
249 #if HAVE_VSNPRINTF || _LIBC
252 n = vsnprintf (partial_message + partial_message_size_used,
253 partial_message_size - partial_message_size_used,
256 if (n < partial_message_size - partial_message_size_used)
258 partial_message_size_used += n;
262 partial_message_size += 2048;
263 partial_message = REALLOC (partial_message, partial_message_size);
266 vsprintf (partial_message + partial_message_size_used, message, args);
267 partial_message_size_used += strlen(partial_message+partial_message_size_used);
269 /* Attempt to catch memory overwrites... */
270 if (partial_message_size_used >= partial_message_size)
272 partial_message_size_used = 0;
273 report (stderr, GT_("partial error message buffer overflow"));
281 n = snprintf (partial_message + partial_message_size_used,
282 partial_message_size - partial_message_size_used,
283 message, a1, a2, a3, a4, a5, a6, a7, a8);
285 if (n < partial_message_size - partial_message_size_used)
287 partial_message_size_used += n;
291 partial_message_size += 2048;
292 partial_message = REALLOC (partial_message, partial_message_size);
295 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
297 /* Attempt to catch memory overwrites... */
298 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
300 partial_message_size_used = 0;
301 report (stderr, GT_("partial error message buffer overflow"));
306 if (use_stderr && partial_message_size_used != 0)
308 partial_message_size_used = 0;
309 fputs(partial_message, errfp);
313 /* Complete an report message by appending MESSAGE, which is a printf-style
314 format string with optional args, to the existing report message (which may
315 be empty.) The completed report message is then printed (and reset to
321 report_complete (FILE *errfp, const char *message, ...)
323 report_complete (FILE *errfp, message, va_alist)
333 /* Make an initial guess for the size of any single message fragment. */
334 if (partial_message_size == 0)
336 partial_message_size_used = 0;
337 partial_message_size = 2048;
338 partial_message = MALLOC (partial_message_size);
341 if (partial_message_size - partial_message_size_used < 1024)
343 partial_message_size += 2048;
344 partial_message = REALLOC (partial_message, partial_message_size);
347 #if defined(VA_START)
348 VA_START (args, message);
349 #if HAVE_VSNPRINTF || _LIBC
352 n = vsnprintf (partial_message + partial_message_size_used,
353 partial_message_size - partial_message_size_used,
356 if (n < partial_message_size - partial_message_size_used)
358 partial_message_size_used += n;
362 partial_message_size += 2048;
363 partial_message = REALLOC (partial_message, partial_message_size);
366 vsprintf (partial_message + partial_message_size_used, message, args);
367 partial_message_size_used += strlen(partial_message+partial_message_size_used);
369 /* Attempt to catch memory overwrites... */
370 if (partial_message_size_used >= partial_message_size)
372 partial_message_size_used = 0;
373 report (stderr, GT_("partial error message buffer overflow"));
381 n = snprintf (partial_message + partial_message_size_used,
382 partial_message_size - partial_message_size_used,
383 message, a1, a2, a3, a4, a5, a6, a7, a8);
385 if (n < partial_message_size - partial_message_size_used)
387 partial_message_size_used += n;
391 partial_message_size += 2048;
392 partial_message = REALLOC (partial_message, partial_message_size);
395 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
397 /* Attempt to catch memory overwrites... */
398 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
400 partial_message_size_used = 0;
401 report (stderr, GT_("partial error message buffer overflow"));
406 /* Finally... print it. */
407 partial_message_size_used = 0;
411 fputs(partial_message, errfp);
414 ++report_message_count;
417 report(errfp, "%s", partial_message);
420 /* Sometimes we want to have at most one error per line. This
421 variable controls whether this mode is selected or not. */
422 int error_one_per_line;
426 report_at_line (FILE *errfp, int errnum, const char *file_name,
427 unsigned int line_number, const char *message, ...)
429 report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
431 const char *file_name;
432 unsigned int line_number;
441 if (error_one_per_line)
443 static const char *old_file_name;
444 static unsigned int old_line_number;
446 if (old_line_number == line_number &&
447 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
448 /* Simply return and print nothing. */
451 old_file_name = file_name;
452 old_line_number = line_number;
455 if (report_print_progname)
456 (*report_print_progname) ();
460 if ( *message == '\n' )
462 fputc( '\n', errfp );
465 fprintf (errfp, "%s:", program_name);
468 if (file_name != NULL)
469 fprintf (errfp, "%s:%d: ", file_name, line_number);
472 VA_START (args, message);
473 # if HAVE_VPRINTF || _LIBC
474 vfprintf (errfp, message, args);
476 _doprnt (message, args, errfp);
480 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
483 ++report_message_count;
485 fprintf (errfp, ": %s", strerror (errnum));