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 = (char *)MALLOC (partial_message_size);
217 if (partial_message_size - partial_message_size_used < 1024)
219 partial_message_size += 2048;
220 partial_message = (char *)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)
244 * args has to be initialized before every call of vsnprintf(),
245 * because vsnprintf() invokes va_arg macro and thus args is
246 * undefined after the call.
248 VA_START(args, message);
249 n = vsnprintf (partial_message + partial_message_size_used, partial_message_size - partial_message_size_used,
254 && (unsigned)n < partial_message_size - partial_message_size_used)
256 partial_message_size_used += n;
260 partial_message_size += 2048;
261 partial_message = (char *)REALLOC (partial_message, partial_message_size);
266 n = snprintf (partial_message + partial_message_size_used,
267 partial_message_size - partial_message_size_used,
268 message, a1, a2, a3, a4, a5, a6, a7, a8);
271 && (unsigned)n < partial_message_size - partial_message_size_used)
273 partial_message_size_used += n;
277 partial_message_size += 2048;
278 partial_message = REALLOC (partial_message, partial_message_size);
282 if (use_stderr && partial_message_size_used != 0)
284 partial_message_size_used = 0;
285 fputs(partial_message, errfp);
289 /* Complete a report message by appending MESSAGE, which is a printf-style
290 format string with optional args, to the existing report message (which may
291 be empty.) The completed report message is then printed (and reset to
297 report_complete (FILE *errfp, const char *message, ...)
299 report_complete (FILE *errfp, message, va_alist)
311 #if defined(VA_START)
314 VA_START(args, message);
315 n = vsnprintf (partial_message + partial_message_size_used,
316 partial_message_size - partial_message_size_used,
320 /* old glibc versions return -1 for truncation */
322 && (unsigned)n < partial_message_size - partial_message_size_used)
324 partial_message_size_used += n;
328 partial_message_size += 2048;
329 partial_message = (char *)REALLOC (partial_message, partial_message_size);
334 n = snprintf (partial_message + partial_message_size_used,
335 partial_message_size - partial_message_size_used,
336 message, a1, a2, a3, a4, a5, a6, a7, a8);
339 && (unsigned)n < partial_message_size - partial_message_size_used)
341 partial_message_size_used += n;
345 partial_message_size += 2048;
346 partial_message = REALLOC (partial_message, partial_message_size);
350 /* Finally... print it. */
351 partial_message_size_used = 0;
355 fputs(partial_message, errfp);
358 ++report_message_count;
361 report(errfp, "%s", partial_message);
364 /* Sometimes we want to have at most one error per line. This
365 variable controls whether this mode is selected or not. */
366 static int error_one_per_line;
370 report_at_line (FILE *errfp, int errnum, const char *file_name,
371 unsigned int line_number, const char *message, ...)
373 report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
375 const char *file_name;
376 unsigned int line_number;
385 if (error_one_per_line)
387 static const char *old_file_name;
388 static unsigned int old_line_number;
390 if (old_line_number == line_number &&
391 (file_name == old_file_name || !strcmp (old_file_name, file_name)))
392 /* Simply return and print nothing. */
395 old_file_name = file_name;
396 old_line_number = line_number;
399 if (report_print_progname)
400 (*report_print_progname) ();
404 if ( *message == '\n' )
406 fputc( '\n', errfp );
409 fprintf (errfp, "%s:", program_name);
412 if (file_name != NULL)
413 fprintf (errfp, "%s:%u: ", file_name, line_number);
416 VA_START (args, message);
417 # if defined(HAVE_VPRINTF) || defined(_LIBC)
418 vfprintf (errfp, message, args);
420 _doprnt (message, args, errfp);
424 fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
427 ++report_message_count;
429 fprintf (errfp, ": %s", strerror (errnum));