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 HAVE_VPRINTF || HAVE_DOPRNT || _LIBC || 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 /* The calling program should define program_name and set it to the
70 name of the executing program. */
71 extern char *program_name;
73 # if !HAVE_STRERROR && !defined(strerror)
74 char *strerror (int errnum)
76 extern char *sys_errlist[];
79 if (errnum > 0 && errnum <= sys_nerr)
80 return sys_errlist[errnum];
81 return GT_("Unknown system error");
83 # endif /* HAVE_STRERROR */
86 /* Print the program name and error message MESSAGE, which is a printf-style
87 format string with optional args.
88 If ERRNUM is nonzero, print its corresponding system error message. */
93 report (FILE *errfp, const char *message, ...)
95 report (FILE *errfp, message, va_alist)
104 /* If a partially built message exists, print it now so it's not lost. */
105 if (partial_message_size_used != 0)
107 partial_message_size_used = 0;
108 report (errfp, GT_("%s (log message incomplete)"), partial_message);
111 #if defined(HAVE_SYSLOG)
117 VA_START (args, message);
119 priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
122 vsyslog (priority, message, args);
125 char *a1 = va_arg(args, char *);
126 char *a2 = va_arg(args, char *);
127 char *a3 = va_arg(args, char *);
128 char *a4 = va_arg(args, char *);
129 char *a5 = va_arg(args, char *);
130 char *a6 = va_arg(args, char *);
131 char *a7 = va_arg(args, char *);
132 char *a8 = va_arg(args, char *);
133 syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
144 if (report_print_progname)
145 (*report_print_progname) ();
149 if ( *message == '\n' )
151 fputc( '\n', errfp );
154 fprintf (errfp, "%s: ", program_name);
158 VA_START (args, message);
159 # if HAVE_VPRINTF || _LIBC
160 vfprintf (errfp, message, args);
162 _doprnt (message, args, errfp);
166 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
170 ++report_message_count;
174 * Calling report_init(1) causes report_build and report_complete to write
175 * to errfp without buffering. This is needed for the ticker dots to
178 void report_init(int mode)
182 case 0: /* errfp, buffered */
188 case 1: /* errfp, unbuffered */
194 case -1: /* syslogd */
198 #endif /* HAVE_SYSLOG */
202 /* Build an report message by appending MESSAGE, which is a printf-style
203 format string with optional args, to the existing report message (which may
204 be empty.) The completed report message is finally printed (and reset to
205 empty) by calling report_complete().
206 If an intervening call to report() occurs when a partially constructed
207 message exists, then, in an attempt to keep the messages in their proper
208 sequence, the partial message will be printed as-is (with a trailing
209 newline) before report() prints its message. */
214 report_build (FILE *errfp, const char *message, ...)
216 report_build (FILE *errfp, message, va_alist)
226 /* Make an initial guess for the size of any single message fragment. */
227 if (partial_message_size == 0)
229 partial_message_size_used = 0;
230 partial_message_size = 2048;
231 partial_message = MALLOC (partial_message_size);
234 if (partial_message_size - partial_message_size_used < 1024)
236 partial_message_size += 2048;
237 partial_message = REALLOC (partial_message, partial_message_size);
240 #if defined(VA_START)
241 VA_START (args, message);
242 #if HAVE_VSNPRINTF || _LIBC
245 n = vsnprintf (partial_message + partial_message_size_used,
246 partial_message_size - partial_message_size_used,
249 if (n < partial_message_size - partial_message_size_used)
251 partial_message_size_used += n;
255 partial_message_size += 2048;
256 partial_message = REALLOC (partial_message, partial_message_size);
259 vsprintf (partial_message + partial_message_size_used, message, args);
260 partial_message_size_used += strlen(partial_message+partial_message_size_used);
262 /* Attempt to catch memory overwrites... */
263 if (partial_message_size_used >= partial_message_size)
265 partial_message_size_used = 0;
266 report (stderr, GT_("partial error message buffer overflow"));
274 n = snprintf (partial_message + partial_message_size_used,
275 partial_message_size - partial_message_size_used,
276 message, a1, a2, a3, a4, a5, a6, a7, a8);
278 if (n < partial_message_size - partial_message_size_used)
280 partial_message_size_used += n;
284 partial_message_size += 2048;
285 partial_message = REALLOC (partial_message, partial_message_size);
288 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
290 /* Attempt to catch memory overwrites... */
291 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
293 partial_message_size_used = 0;
294 report (stderr, GT_("partial error message buffer overflow"));
299 if (use_stderr && partial_message_size_used != 0)
301 partial_message_size_used = 0;
302 fputs(partial_message, errfp);
306 /* Complete a report message by appending MESSAGE, which is a printf-style
307 format string with optional args, to the existing report message (which may
308 be empty.) The completed report message is then printed (and reset to
314 report_complete (FILE *errfp, const char *message, ...)
316 report_complete (FILE *errfp, message, va_alist)
326 /* Make an initial guess for the size of any single message fragment. */
327 if (partial_message_size == 0)
329 partial_message_size_used = 0;
330 partial_message_size = 2048;
331 partial_message = MALLOC (partial_message_size);
334 if (partial_message_size - partial_message_size_used < 1024)
336 partial_message_size += 2048;
337 partial_message = REALLOC (partial_message, partial_message_size);
340 #if defined(VA_START)
341 VA_START (args, message);
342 #if HAVE_VSNPRINTF || _LIBC
345 n = vsnprintf (partial_message + partial_message_size_used,
346 partial_message_size - partial_message_size_used,
349 if (n < partial_message_size - partial_message_size_used)
351 partial_message_size_used += n;
355 partial_message_size += 2048;
356 partial_message = REALLOC (partial_message, partial_message_size);
359 vsprintf (partial_message + partial_message_size_used, message, args);
360 partial_message_size_used += strlen(partial_message+partial_message_size_used);
362 /* Attempt to catch memory overwrites... */
363 if (partial_message_size_used >= partial_message_size)
365 partial_message_size_used = 0;
366 report (stderr, GT_("partial error message buffer overflow"));
374 n = snprintf (partial_message + partial_message_size_used,
375 partial_message_size - partial_message_size_used,
376 message, a1, a2, a3, a4, a5, a6, a7, a8);
378 if (n < partial_message_size - partial_message_size_used)
380 partial_message_size_used += n;
384 partial_message_size += 2048;
385 partial_message = REALLOC (partial_message, partial_message_size);
388 sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
390 /* Attempt to catch memory overwrites... */
391 if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
393 partial_message_size_used = 0;
394 report (stderr, GT_("partial error message buffer overflow"));
399 /* Finally... print it. */
400 partial_message_size_used = 0;
404 fputs(partial_message, errfp);
407 ++report_message_count;
410 report(errfp, "%s", partial_message);
413 /* Sometimes we want to have at most one error per line. This
414 variable controls whether this mode is selected or not. */
415 int error_one_per_line;
419 report_at_line (FILE *errfp, int errnum, const char *file_name,
420 unsigned int line_number, const char *message, ...)
422 report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
424 const char *file_name;
425 unsigned int line_number;
434 if (error_one_per_line)
436 static const char *old_file_name;
437 static unsigned int old_line_number;
439 if (old_line_number == line_number &&
440 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
441 /* Simply return and print nothing. */
444 old_file_name = file_name;
445 old_line_number = line_number;
448 if (report_print_progname)
449 (*report_print_progname) ();
453 if ( *message == '\n' )
455 fputc( '\n', errfp );
458 fprintf (errfp, "%s:", program_name);
461 if (file_name != NULL)
462 fprintf (errfp, "%s:%d: ", file_name, line_number);
465 VA_START (args, message);
466 # if HAVE_VPRINTF || _LIBC
467 vfprintf (errfp, message, args);
469 _doprnt (message, args, errfp);
473 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
476 ++report_message_count;
478 fprintf (errfp, ": %s", strerror (errnum));