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 static 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. */
208 static void rep_ensuresize(void) {
209 /* Make an initial guess for the size of any single message fragment. */
210 if (partial_message_size == 0)
212 partial_message_size_used = 0;
213 partial_message_size = 2048;
214 partial_message = MALLOC (partial_message_size);
217 if (partial_message_size - partial_message_size_used < 1024)
219 partial_message_size += 2048;
220 partial_message = REALLOC (partial_message, partial_message_size);
226 report_build (FILE *errfp, const char *message, ...)
228 report_build (FILE *errfp, message, va_alist)
240 #if defined(VA_START)
241 VA_START (args, message);
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);
261 n = snprintf (partial_message + partial_message_size_used,
262 partial_message_size - partial_message_size_used,
263 message, a1, a2, a3, a4, a5, a6, a7, a8);
265 if (n < partial_message_size - partial_message_size_used)
267 partial_message_size_used += n;
271 partial_message_size += 2048;
272 partial_message = REALLOC (partial_message, partial_message_size);
276 if (use_stderr && partial_message_size_used != 0)
278 partial_message_size_used = 0;
279 fputs(partial_message, errfp);
283 /* Complete a report message by appending MESSAGE, which is a printf-style
284 format string with optional args, to the existing report message (which may
285 be empty.) The completed report message is then printed (and reset to
291 report_complete (FILE *errfp, const char *message, ...)
293 report_complete (FILE *errfp, message, va_alist)
305 #if defined(VA_START)
306 VA_START (args, message);
309 n = vsnprintf (partial_message + partial_message_size_used,
310 partial_message_size - partial_message_size_used,
313 if (n < partial_message_size - partial_message_size_used)
315 partial_message_size_used += n;
319 partial_message_size += 2048;
320 partial_message = REALLOC (partial_message, partial_message_size);
326 n = snprintf (partial_message + partial_message_size_used,
327 partial_message_size - partial_message_size_used,
328 message, a1, a2, a3, a4, a5, a6, a7, a8);
330 if (n < partial_message_size - partial_message_size_used)
332 partial_message_size_used += n;
336 partial_message_size += 2048;
337 partial_message = REALLOC (partial_message, partial_message_size);
341 /* Finally... print it. */
342 partial_message_size_used = 0;
346 fputs(partial_message, errfp);
349 ++report_message_count;
352 report(errfp, "%s", partial_message);
355 /* Sometimes we want to have at most one error per line. This
356 variable controls whether this mode is selected or not. */
357 static int error_one_per_line;
361 report_at_line (FILE *errfp, int errnum, const char *file_name,
362 unsigned int line_number, const char *message, ...)
364 report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
366 const char *file_name;
367 unsigned int line_number;
376 if (error_one_per_line)
378 static const char *old_file_name;
379 static unsigned int old_line_number;
381 if (old_line_number == line_number &&
382 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
383 /* Simply return and print nothing. */
386 old_file_name = file_name;
387 old_line_number = line_number;
390 if (report_print_progname)
391 (*report_print_progname) ();
395 if ( *message == '\n' )
397 fputc( '\n', errfp );
400 fprintf (errfp, "%s:", program_name);
403 if (file_name != NULL)
404 fprintf (errfp, "%s:%u: ", file_name, line_number);
407 VA_START (args, message);
408 # if defined(HAVE_VPRINTF) || defined(_LIBC)
409 vfprintf (errfp, message, args);
411 _doprnt (message, args, errfp);
415 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
418 ++report_message_count;
420 fprintf (errfp, ": %s", strerror (errnum));