1 /** \file 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"
27 #define MALLOC(n) xmalloc(n)
28 #define REALLOC(n,s) xrealloc(n,s)
30 /* Used by report_build() and report_complete() to accumulate partial messages.
32 static unsigned int partial_message_size = 0;
33 static unsigned int partial_message_size_used = 0;
34 static char *partial_message;
35 static int partial_suppress_tag = 0;
37 static unsigned unbuffered;
38 static unsigned int use_syslog;
40 /* Print the program name and error message MESSAGE, which is a printf-style
41 format string with optional args. */
42 void report(FILE *errfp, const char *message, ...)
46 /* If a partially built message exists, print it now so it's not lost. */
47 if (partial_message_size_used != 0)
49 partial_message_size_used = 0;
50 report (errfp, GT_("%s (log message incomplete)\n"), partial_message);
53 #if defined(HAVE_SYSLOG)
58 va_start (args, message);
59 priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
62 vsyslog (priority, message, args);
65 char *a1 = va_arg(args, char *);
66 char *a2 = va_arg(args, char *);
67 char *a3 = va_arg(args, char *);
68 char *a4 = va_arg(args, char *);
69 char *a5 = va_arg(args, char *);
70 char *a6 = va_arg(args, char *);
71 char *a7 = va_arg(args, char *);
72 char *a8 = va_arg(args, char *);
73 syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
79 else /* i. e. not using syslog */
82 if ( *message == '\n' )
87 if (!partial_suppress_tag)
88 fprintf (errfp, "%s: ", program_name);
89 partial_suppress_tag = 0;
91 va_start (args, message);
92 vfprintf (errfp, message, args);
99 * Configure the report module. The output is set according to
102 void report_init(int mode /** 0: regular output, 1: unbuffered output, -1: syslog */)
106 case 0: /* errfp, buffered */
112 case 1: /* errfp, unbuffered */
118 case -1: /* syslogd */
122 #endif /* HAVE_SYSLOG */
126 /* Build an report message by appending MESSAGE, which is a printf-style
127 format string with optional args, to the existing report message (which may
128 be empty.) The completed report message is finally printed (and reset to
129 empty) by calling report_complete().
130 If an intervening call to report() occurs when a partially constructed
131 message exists, then, in an attempt to keep the messages in their proper
132 sequence, the partial message will be printed as-is (with a trailing
133 newline) before report() prints its message. */
136 static void rep_ensuresize(void) {
137 /* Make an initial guess for the size of any single message fragment. */
138 if (partial_message_size == 0)
140 partial_message_size_used = 0;
141 partial_message_size = 2048;
142 partial_message = (char *)MALLOC (partial_message_size);
145 if (partial_message_size - partial_message_size_used < 1024)
147 partial_message_size += 2048;
148 partial_message = (char *)REALLOC (partial_message, partial_message_size);
153 static void report_vbuild(const char *message, va_list args)
160 * args has to be initialized before every call of vsnprintf(),
161 * because vsnprintf() invokes va_arg macro and thus args is
162 * undefined after the call.
164 n = vsnprintf (partial_message + partial_message_size_used, partial_message_size - partial_message_size_used,
167 /* output error, f. i. EILSEQ */
171 && (unsigned)n < partial_message_size - partial_message_size_used)
173 partial_message_size_used += n;
177 partial_message_size += 2048;
178 partial_message = (char *)REALLOC (partial_message, partial_message_size);
183 void report_build (FILE *errfp, const char *message, ...)
189 VA_START(args, message);
190 report_vbuild(message, args);
193 if (unbuffered && partial_message_size_used != 0)
195 partial_message_size_used = 0;
196 fputs(partial_message, errfp);
200 void report_flush(FILE *errfp)
202 if (partial_message_size_used != 0)
204 partial_message_size_used = 0;
205 report(errfp, "%s", partial_message);
206 partial_suppress_tag = 1;
210 /* Complete a report message by appending MESSAGE, which is a printf-style
211 format string with optional args, to the existing report message (which may
212 be empty.) The completed report message is then printed (and reset to
215 void report_complete (FILE *errfp, const char *message, ...)
221 VA_START(args, message);
222 report_vbuild(message, args);
225 /* Finally... print it. */
226 partial_message_size_used = 0;
230 fputs(partial_message, errfp);
234 report(errfp, "%s", partial_message);
237 /* Sometimes we want to have at most one error per line. This
238 variable controls whether this mode is selected or not. */
239 static int error_one_per_line;
241 /* If errnum is nonzero, print its corresponding system error message. */
242 void report_at_line (FILE *errfp, int errnum, const char *file_name,
243 unsigned int line_number, const char *message, ...)
247 if (error_one_per_line)
249 static const char *old_file_name;
250 static unsigned int old_line_number;
252 if (old_line_number == line_number &&
253 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
254 /* Simply return and print nothing. */
257 old_file_name = file_name;
258 old_line_number = line_number;
262 if ( *message == '\n' )
264 fputc( '\n', errfp );
267 fprintf (errfp, "%s:", program_name);
269 if (file_name != NULL)
270 fprintf (errfp, "%s:%u: ", file_name, line_number);
272 va_start (args, message);
273 vfprintf (errfp, message, args);
277 fprintf (errfp, ": %s", strerror (errnum));