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.
21 #include "fetchmail.h"
25 #define MALLOC(n) xmalloc(n)
26 #define REALLOC(n,s) xrealloc(n,s)
28 /* Used by report_build() and report_complete() to accumulate partial messages.
30 static unsigned int partial_message_size = 0;
31 static unsigned int partial_message_size_used = 0;
32 static char *partial_message;
33 static int partial_suppress_tag = 0;
35 static unsigned unbuffered;
36 static unsigned int use_syslog;
38 /* Print the program name and error message MESSAGE, which is a printf-style
39 format string with optional args. */
40 void report(FILE *errfp, const char *message, ...)
44 /* If a partially built message exists, print it now so it's not lost. */
45 if (partial_message_size_used != 0)
47 partial_message_size_used = 0;
48 report (errfp, GT_("%s (log message incomplete)\n"), partial_message);
55 va_start (args, message);
56 priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
59 vsyslog (priority, message, args);
62 char *a1 = va_arg(args, char *);
63 char *a2 = va_arg(args, char *);
64 char *a3 = va_arg(args, char *);
65 char *a4 = va_arg(args, char *);
66 char *a5 = va_arg(args, char *);
67 char *a6 = va_arg(args, char *);
68 char *a7 = va_arg(args, char *);
69 char *a8 = va_arg(args, char *);
70 syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
76 else /* i. e. not using syslog */
78 if ( *message == '\n' )
83 if (!partial_suppress_tag)
84 fprintf (errfp, "%s: ", program_name);
85 partial_suppress_tag = 0;
87 va_start (args, message);
88 vfprintf (errfp, message, args);
95 * Configure the report module. The output is set according to
98 void report_init(int mode /** 0: regular output, 1: unbuffered output, -1: syslog */)
102 case 0: /* errfp, buffered */
108 case 1: /* errfp, unbuffered */
113 case -1: /* syslogd */
120 /* Build an report message by appending MESSAGE, which is a printf-style
121 format string with optional args, to the existing report message (which may
122 be empty.) The completed report message is finally printed (and reset to
123 empty) by calling report_complete().
124 If an intervening call to report() occurs when a partially constructed
125 message exists, then, in an attempt to keep the messages in their proper
126 sequence, the partial message will be printed as-is (with a trailing
127 newline) before report() prints its message. */
130 static void rep_ensuresize(void) {
131 /* Make an initial guess for the size of any single message fragment. */
132 if (partial_message_size == 0)
134 partial_message_size_used = 0;
135 partial_message_size = 2048;
136 partial_message = (char *)MALLOC (partial_message_size);
139 if (partial_message_size - partial_message_size_used < 1024)
141 partial_message_size += 2048;
142 partial_message = (char *)REALLOC (partial_message, partial_message_size);
146 static void report_vbuild(const char *message, va_list args)
153 * args has to be initialized before every call of vsnprintf(),
154 * because vsnprintf() invokes va_arg macro and thus args is
155 * undefined after the call.
157 n = vsnprintf (partial_message + partial_message_size_used, partial_message_size - partial_message_size_used,
160 /* output error, f. i. EILSEQ */
164 && (unsigned)n < partial_message_size - partial_message_size_used)
166 partial_message_size_used += n;
170 partial_message_size += 2048;
171 partial_message = (char *)REALLOC (partial_message, partial_message_size);
175 void report_build (FILE *errfp, const char *message, ...)
181 va_start(args, message);
182 report_vbuild(message, args);
185 if (unbuffered && partial_message_size_used != 0)
187 partial_message_size_used = 0;
188 fputs(partial_message, errfp);
192 void report_flush(FILE *errfp)
194 if (partial_message_size_used != 0)
196 partial_message_size_used = 0;
197 report(errfp, "%s", partial_message);
198 partial_suppress_tag = 1;
202 /* Complete a 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 then printed (and reset to
207 void report_complete (FILE *errfp, const char *message, ...)
213 va_start(args, message);
214 report_vbuild(message, args);
217 /* Finally... print it. */
218 partial_message_size_used = 0;
222 fputs(partial_message, errfp);
226 report(errfp, "%s", partial_message);
229 /* Sometimes we want to have at most one error per line. This
230 variable controls whether this mode is selected or not. */
231 static int error_one_per_line;
233 /* If errnum is nonzero, print its corresponding system error message. */
234 void report_at_line (FILE *errfp, int errnum, const char *file_name,
235 unsigned int line_number, const char *message, ...)
239 if (error_one_per_line)
241 static const char *old_file_name;
242 static unsigned int old_line_number;
244 if (old_line_number == line_number &&
245 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
246 /* Simply return and print nothing. */
249 old_file_name = file_name;
250 old_line_number = line_number;
254 if ( *message == '\n' )
256 fputc( '\n', errfp );
259 fprintf (errfp, "%s:", program_name);
261 if (file_name != NULL)
262 fprintf (errfp, "%s:%u: ", file_name, line_number);
264 va_start (args, message);
265 vfprintf (errfp, message, args);
269 fprintf (errfp, ": %s", strerror (errnum));