-/* report.c -- report function for noninteractive utilities
+/** \file report.c report function for noninteractive utilities
*
* For license terms, see the file COPYING in this directory.
*
* This code is distantly descended from the error.c module written by
* David MacKenzie <djm@gnu.ai.mit.edu>. It was redesigned and
- * rewritten by Dave Bodenstab, then reseedesigned again by ESR, then
+ * rewritten by Dave Bodenstab, then redesigned again by ESR, then
* bludgeoned into submission for SunOS 4.1.3 by Chris Cheyney
* <cheyney@netcom.com>. It works even when the return from
* vprintf(3) is unreliable.
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
-
#include <stdio.h>
#include <errno.h>
+#include <string.h>
#if defined(HAVE_SYSLOG)
#include <syslog.h>
#endif
+#include "i18n.h"
+#include "fetchmail.h"
-#if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC || HAVE_STDARG_H
+#if defined(HAVE_VPRINTF) || defined(HAVE_DOPRNT) || defined(_LIBC) || defined(HAVE_STDARG_H)
# if HAVE_STDARG_H
# include <stdarg.h>
# define VA_START(args, lastarg) va_start(args, lastarg)
# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
#endif
-#if STDC_HEADERS || _LIBC
-# include <stdlib.h>
-# include <string.h>
-#else
-void exit ();
-#endif
-
-#include "i18n.h"
-
-#include "fetchmail.h"
#define MALLOC(n) xmalloc(n)
#define REALLOC(n,s) xrealloc(n,s)
-/* If NULL, report will flush stderr, then print on stderr the program
- name, a colon and a space. Otherwise, report will call this
- function without parameters instead. */
-void (*report_print_progname) (
-#if __STDC__ - 0
- void
-#endif
- );
-
-/* Used by report_build() and report_complete() to accumulate partial messages. */
+/* Used by report_build() and report_complete() to accumulate partial messages.
+ */
static unsigned int partial_message_size = 0;
static unsigned int partial_message_size_used = 0;
static char *partial_message;
-static unsigned use_stderr;
-static unsigned int use_syslog;
+static int partial_suppress_tag = 0;
-/* This variable is incremented each time `report' is called. */
-unsigned int report_message_count;
+static unsigned unbuffered;
+static unsigned int use_syslog;
#ifdef _LIBC
/* In the GNU C library, there is a predefined variable for this. */
#else
-/* The calling program should define program_name and set it to the
- name of the executing program. */
-extern char *program_name;
-
# if !HAVE_STRERROR && !defined(strerror)
-char *strerror (errnum)
- int errnum;
+char *strerror (int errnum)
{
- extern char *sys_errlist[];
- extern int sys_nerr;
+ extern char *sys_errlist[];
+ extern int sys_nerr;
- if (errnum > 0 && errnum <= sys_nerr)
- return sys_errlist[errnum];
- return GT_("Unknown system error");
+ if (errnum > 0 && errnum <= sys_nerr)
+ return sys_errlist[errnum];
+ return GT_("Unknown system error");
}
# endif /* HAVE_STRERROR */
#endif /* _LIBC */
/* Print the program name and error message MESSAGE, which is a printf-style
- format string with optional args.
- If ERRNUM is nonzero, print its corresponding system error message. */
+ format string with optional args. */
/* VARARGS */
-
void
#ifdef HAVE_STDARG_H
report (FILE *errfp, const char *message, ...)
#endif
{
#ifdef VA_START
- va_list args;
+ va_list args;
#endif
- /* If a partially built message exists, print it now so it's not lost. */
- if (partial_message_size_used != 0)
+ /* If a partially built message exists, print it now so it's not lost. */
+ if (partial_message_size_used != 0)
{
- partial_message_size_used = 0;
- report (errfp, 0, GT_("%s (log message incomplete)"), partial_message);
+ partial_message_size_used = 0;
+ report (errfp, GT_("%s (log message incomplete)\n"), partial_message);
}
#if defined(HAVE_SYSLOG)
- if (use_syslog)
+ if (use_syslog)
{
- int priority;
+ int priority;
#ifdef VA_START
- VA_START (args, message);
+ VA_START (args, message);
#endif
- priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
+ priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
#ifdef HAVE_VSYSLOG
- vsyslog (priority, message, args);
+ vsyslog (priority, message, args);
#else
- {
- char *a1 = va_arg(args, char *);
- char *a2 = va_arg(args, char *);
- char *a3 = va_arg(args, char *);
- char *a4 = va_arg(args, char *);
- char *a5 = va_arg(args, char *);
- char *a6 = va_arg(args, char *);
- char *a7 = va_arg(args, char *);
- char *a8 = va_arg(args, char *);
- syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
- }
+ {
+ char *a1 = va_arg(args, char *);
+ char *a2 = va_arg(args, char *);
+ char *a3 = va_arg(args, char *);
+ char *a4 = va_arg(args, char *);
+ char *a5 = va_arg(args, char *);
+ char *a6 = va_arg(args, char *);
+ char *a7 = va_arg(args, char *);
+ char *a8 = va_arg(args, char *);
+ syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
+ }
#endif
#ifdef VA_START
- va_end(args);
+ va_end(args);
#endif
}
- else
+ else /* i. e. not using syslog */
#endif
{
- if (report_print_progname)
- (*report_print_progname) ();
- else
+ if ( *message == '\n' )
{
- fflush (errfp);
- if ( *message == '\n' )
- {
- fputc( '\n', errfp );
- ++message;
- }
- fprintf (errfp, "%s: ", program_name);
+ fputc( '\n', errfp );
+ ++message;
}
+ if (!partial_suppress_tag)
+ fprintf (errfp, "%s: ", program_name);
+ partial_suppress_tag = 0;
#ifdef VA_START
- VA_START (args, message);
-# if HAVE_VPRINTF || _LIBC
- vfprintf (errfp, message, args);
+ VA_START (args, message);
+# if defined(HAVE_VPRINTF) || defined(_LIBC)
+ vfprintf (errfp, message, args);
# else
- _doprnt (message, args, errfp);
+ _doprnt (message, args, errfp);
# endif
- va_end (args);
+ va_end (args);
#else
- fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
+ fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
#endif
- fflush (errfp);
+ fflush (errfp);
}
- ++report_message_count;
}
-\f
-/*
- * Calling report_init(1) causes error_build and error_complete to write
- * to errfp without buffering. This is needed for the ticker dots to
- * work correctly.
+
+/**
+ * Configure the report module. The output is set according to
+ * \a mode.
*/
-void report_init(int mode)
+void report_init(int mode /** 0: regular output, 1: unbuffered output, -1: syslog */)
{
switch(mode)
{
case 0: /* errfp, buffered */
default:
- use_stderr = FALSE;
+ unbuffered = FALSE;
use_syslog = FALSE;
break;
case 1: /* errfp, unbuffered */
- use_stderr = TRUE;
+ unbuffered = TRUE;
use_syslog = FALSE;
break;
#ifdef HAVE_SYSLOG
case -1: /* syslogd */
- use_stderr = FALSE;
+ unbuffered = FALSE;
use_syslog = TRUE;
break;
#endif /* HAVE_SYSLOG */
}
}
-\f
+
/* Build an report message by appending MESSAGE, which is a printf-style
format string with optional args, to the existing report message (which may
be empty.) The completed report message is finally printed (and reset to
newline) before report() prints its message. */
/* VARARGS */
+static void rep_ensuresize(void) {
+ /* Make an initial guess for the size of any single message fragment. */
+ if (partial_message_size == 0)
+ {
+ partial_message_size_used = 0;
+ partial_message_size = 2048;
+ partial_message = (char *)MALLOC (partial_message_size);
+ }
+ else
+ if (partial_message_size - partial_message_size_used < 1024)
+ {
+ partial_message_size += 2048;
+ partial_message = (char *)REALLOC (partial_message, partial_message_size);
+ }
+}
+
+#ifdef HAVE_STDARG_H
+static void report_vbuild(const char *message, va_list args)
+{
+ int n;
+
+ for ( ; ; )
+ {
+ /*
+ * args has to be initialized before every call of vsnprintf(),
+ * because vsnprintf() invokes va_arg macro and thus args is
+ * undefined after the call.
+ */
+ n = vsnprintf (partial_message + partial_message_size_used, partial_message_size - partial_message_size_used,
+ message, args);
+
+ /* output error, f. i. EILSEQ */
+ if (n < 0) break;
+
+ if (n >= 0
+ && (unsigned)n < partial_message_size - partial_message_size_used)
+ {
+ partial_message_size_used += n;
+ break;
+ }
+
+ partial_message_size += 2048;
+ partial_message = (char *)REALLOC (partial_message, partial_message_size);
+ }
+}
+#endif
+
void
#ifdef HAVE_STDARG_H
report_build (FILE *errfp, const char *message, ...)
#endif
{
#ifdef VA_START
- va_list args;
- int n;
+ va_list args;
+#else
+ int n;
#endif
- /* Make an initial guess for the size of any single message fragment. */
- if (partial_message_size == 0)
- {
- partial_message_size_used = 0;
- partial_message_size = 2048;
- partial_message = MALLOC (partial_message_size);
- }
- else
- if (partial_message_size - partial_message_size_used < 1024)
- {
- partial_message_size += 2048;
- partial_message = REALLOC (partial_message, partial_message_size);
- }
+ rep_ensuresize();
#if defined(VA_START)
- VA_START (args, message);
-#if HAVE_VSNPRINTF || _LIBC
- for ( ; ; )
- {
- n = vsnprintf (partial_message + partial_message_size_used,
- partial_message_size - partial_message_size_used,
- message, args);
-
- if (n < partial_message_size - partial_message_size_used)
- {
- partial_message_size_used += n;
- break;
- }
-
- partial_message_size += 2048;
- partial_message = REALLOC (partial_message, partial_message_size);
- }
+ VA_START(args, message);
+ report_vbuild(message, args);
+ va_end(args);
#else
- vsprintf (partial_message + partial_message_size_used, message, args);
- partial_message_size_used += strlen(partial_message+partial_message_size_used);
-
- /* Attempt to catch memory overwrites... */
- if (partial_message_size_used >= partial_message_size)
+ for ( ; ; )
{
- partial_message_size_used = 0;
- report (stderr, GT_("partial error message buffer overflow"));
- }
-#endif
- va_end (args);
-#else
-#if HAVE_SNPRINTF
- for ( ; ; )
- {
- n = snprintf (partial_message + partial_message_size_used,
- partial_message_size - partial_message_size_used,
- message, a1, a2, a3, a4, a5, a6, a7, a8);
+ n = snprintf (partial_message + partial_message_size_used,
+ partial_message_size - partial_message_size_used,
+ message, a1, a2, a3, a4, a5, a6, a7, a8);
+
+ /* output error, f. i. EILSEQ */
+ if (n < 0) break;
- if (n < partial_message_size - partial_message_size_used)
+ if (n >= 0
+ && (unsigned)n < partial_message_size - partial_message_size_used)
{
- partial_message_size_used += n;
- break;
+ partial_message_size_used += n;
+ break;
}
- partial_message_size += 2048;
- partial_message = REALLOC (partial_message, partial_message_size);
+ partial_message_size += 2048;
+ partial_message = REALLOC (partial_message, partial_message_size);
}
-#else
- sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
+#endif
- /* Attempt to catch memory overwrites... */
- if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
+ if (unbuffered && partial_message_size_used != 0)
{
- partial_message_size_used = 0;
- report (stderr, GT_("partial error message buffer overflow"));
+ partial_message_size_used = 0;
+ fputs(partial_message, errfp);
}
-#endif
-#endif
+}
- if (use_stderr && partial_message_size_used != 0)
+void report_flush(FILE *errfp)
+{
+ if (partial_message_size_used != 0)
{
- partial_message_size_used = 0;
- fputs(partial_message, errfp);
+ partial_message_size_used = 0;
+ report(errfp, "%s", partial_message);
+ partial_suppress_tag = 1;
}
}
-\f
-/* Complete an report message by appending MESSAGE, which is a printf-style
+
+/* Complete a report message by appending MESSAGE, which is a printf-style
format string with optional args, to the existing report message (which may
be empty.) The completed report message is then printed (and reset to
empty.) */
/* VARARGS */
-
void
#ifdef HAVE_STDARG_H
report_complete (FILE *errfp, const char *message, ...)
#endif
{
#ifdef VA_START
- va_list args;
- int n;
+ va_list args;
#endif
- /* Make an initial guess for the size of any single message fragment. */
- if (partial_message_size == 0)
- {
- partial_message_size_used = 0;
- partial_message_size = 2048;
- partial_message = MALLOC (partial_message_size);
- }
- else
- if (partial_message_size - partial_message_size_used < 1024)
- {
- partial_message_size += 2048;
- partial_message = REALLOC (partial_message, partial_message_size);
- }
+ rep_ensuresize();
#if defined(VA_START)
- VA_START (args, message);
-#if HAVE_VSNPRINTF || _LIBC
- for ( ; ; )
- {
- n = vsnprintf (partial_message + partial_message_size_used,
- partial_message_size - partial_message_size_used,
- message, args);
-
- if (n < partial_message_size - partial_message_size_used)
- {
- partial_message_size_used += n;
- break;
- }
-
- partial_message_size += 2048;
- partial_message = REALLOC (partial_message, partial_message_size);
- }
-#else
- vsprintf (partial_message + partial_message_size_used, message, args);
- partial_message_size_used += strlen(partial_message+partial_message_size_used);
-
- /* Attempt to catch memory overwrites... */
- if (partial_message_size_used >= partial_message_size)
- {
- partial_message_size_used = 0;
- report (stderr, GT_("partial error message buffer overflow"));
- }
-#endif
- va_end (args);
-#else
-#if HAVE_SNPRINTF
- for ( ; ; )
- {
- n = snprintf (partial_message + partial_message_size_used,
- partial_message_size - partial_message_size_used,
- message, a1, a2, a3, a4, a5, a6, a7, a8);
-
- if (n < partial_message_size - partial_message_size_used)
- {
- partial_message_size_used += n;
- break;
- }
-
- partial_message_size += 2048;
- partial_message = REALLOC (partial_message, partial_message_size);
- }
+ VA_START(args, message);
+ report_vbuild(message, args);
+ va_end(args);
#else
- sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
-
- /* Attempt to catch memory overwrites... */
- if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
- {
- partial_message_size_used = 0;
- report (stderr, GT_("partial error message buffer overflow"));
- }
-#endif
+ report_build(errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
#endif
- /* Finally... print it. */
- partial_message_size_used = 0;
+ /* Finally... print it. */
+ partial_message_size_used = 0;
- if (use_stderr)
+ if (unbuffered)
{
- fputs(partial_message, errfp);
- fflush (errfp);
-
- ++report_message_count;
+ fputs(partial_message, errfp);
+ fflush (errfp);
}
- else
- report(errfp, "%s", partial_message);
+ else
+ report(errfp, "%s", partial_message);
}
-\f
+
/* Sometimes we want to have at most one error per line. This
variable controls whether this mode is selected or not. */
-int error_one_per_line;
+static int error_one_per_line;
+/* If errnum is nonzero, print its corresponding system error message. */
void
#ifdef HAVE_STDARG_H
report_at_line (FILE *errfp, int errnum, const char *file_name,
#endif
{
#ifdef VA_START
- va_list args;
+ va_list args;
#endif
- if (error_one_per_line)
+ if (error_one_per_line)
{
- static const char *old_file_name;
- static unsigned int old_line_number;
+ static const char *old_file_name;
+ static unsigned int old_line_number;
- if (old_line_number == line_number &&
- (file_name == old_file_name || !strcmp (old_file_name, file_name)))
- /* Simply return and print nothing. */
- return;
+ if (old_line_number == line_number &&
+ (file_name == old_file_name || !strcmp (old_file_name, file_name)))
+ /* Simply return and print nothing. */
+ return;
- old_file_name = file_name;
- old_line_number = line_number;
+ old_file_name = file_name;
+ old_line_number = line_number;
}
- if (report_print_progname)
- (*report_print_progname) ();
- else
+ fflush (errfp);
+ if ( *message == '\n' )
{
- fflush (errfp);
- if ( *message == '\n' )
- {
- fputc( '\n', errfp );
- ++message;
- }
- fprintf (errfp, "%s:", program_name);
+ fputc( '\n', errfp );
+ ++message;
}
+ fprintf (errfp, "%s:", program_name);
- if (file_name != NULL)
- fprintf (errfp, "%s:%d: ", file_name, line_number);
+ if (file_name != NULL)
+ fprintf (errfp, "%s:%u: ", file_name, line_number);
#ifdef VA_START
- VA_START (args, message);
-# if HAVE_VPRINTF || _LIBC
- vfprintf (errfp, message, args);
+ VA_START (args, message);
+# if defined(HAVE_VPRINTF) || defined(_LIBC)
+ vfprintf (errfp, message, args);
# else
- _doprnt (message, args, errfp);
+ _doprnt (message, args, errfp);
# endif
- va_end (args);
+ va_end (args);
#else
- fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
+ fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
#endif
- ++report_message_count;
- if (errnum)
- fprintf (errfp, ": %s", strerror (errnum));
- putc ('\n', errfp);
- fflush (errfp);
+ if (errnum)
+ fprintf (errfp, ": %s", strerror (errnum));
+ putc ('\n', errfp);
+ fflush (errfp);
}