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, partial_message_size - partial_message_size_used,
248 && (unsigned)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);
266 && (unsigned)n < partial_message_size - partial_message_size_used)
268 partial_message_size_used += n;
272 partial_message_size += 2048;
273 partial_message = REALLOC (partial_message, partial_message_size);
277 if (use_stderr && partial_message_size_used != 0)
279 partial_message_size_used = 0;
280 fputs(partial_message, errfp);
284 /* Complete a report message by appending MESSAGE, which is a printf-style
285 format string with optional args, to the existing report message (which may
286 be empty.) The completed report message is then printed (and reset to
292 report_complete (FILE *errfp, const char *message, ...)
294 report_complete (FILE *errfp, message, va_alist)
306 #if defined(VA_START)
307 VA_START (args, message);
310 n = vsnprintf (partial_message + partial_message_size_used,
311 partial_message_size - partial_message_size_used,
314 /* old glibc versions return -1 for truncation */
316 && (unsigned)n < partial_message_size - partial_message_size_used)
318 partial_message_size_used += n;
322 partial_message_size += 2048;
323 partial_message = REALLOC (partial_message, partial_message_size);
329 n = snprintf (partial_message + partial_message_size_used,
330 partial_message_size - partial_message_size_used,
331 message, a1, a2, a3, a4, a5, a6, a7, a8);
334 && (unsigned)n < partial_message_size - partial_message_size_used)
336 partial_message_size_used += n;
340 partial_message_size += 2048;
341 partial_message = REALLOC (partial_message, partial_message_size);
345 /* Finally... print it. */
346 partial_message_size_used = 0;
350 fputs(partial_message, errfp);
353 ++report_message_count;
356 report(errfp, "%s", partial_message);
359 /* Sometimes we want to have at most one error per line. This
360 variable controls whether this mode is selected or not. */
361 static int error_one_per_line;
365 report_at_line (FILE *errfp, int errnum, const char *file_name,
366 unsigned int line_number, const char *message, ...)
368 report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
370 const char *file_name;
371 unsigned int line_number;
380 if (error_one_per_line)
382 static const char *old_file_name;
383 static unsigned int old_line_number;
385 if (old_line_number == line_number &&
386 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
387 /* Simply return and print nothing. */
390 old_file_name = file_name;
391 old_line_number = line_number;
394 if (report_print_progname)
395 (*report_print_progname) ();
399 if ( *message == '\n' )
401 fputc( '\n', errfp );
404 fprintf (errfp, "%s:", program_name);
407 if (file_name != NULL)
408 fprintf (errfp, "%s:%u: ", file_name, line_number);
411 VA_START (args, message);
412 # if defined(HAVE_VPRINTF) || defined(_LIBC)
413 vfprintf (errfp, message, args);
415 _doprnt (message, args, errfp);
419 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
422 ++report_message_count;
424 fprintf (errfp, ": %s", strerror (errnum));