-/* 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.
#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 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.
*/
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. */
-static 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 (int errnum)
{
#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, ...)
if (partial_message_size_used != 0)
{
partial_message_size_used = 0;
- report (errfp, 0, GT_("%s (log message incomplete)"), partial_message);
+ report (errfp, GT_("%s (log message incomplete)\n"), partial_message);
}
#if defined(HAVE_SYSLOG)
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
+# if defined(HAVE_VPRINTF) || defined(_LIBC)
vfprintf (errfp, message, args);
# else
_doprnt (message, args, errfp);
#endif
fflush (errfp);
}
- ++report_message_count;
}
-\f
-/*
- * Calling report_init(1) causes report_build and report_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 */
-void
-#ifdef HAVE_STDARG_H
-report_build (FILE *errfp, const char *message, ...)
-#else
-report_build (FILE *errfp, message, va_alist)
- const char *message;
- va_dcl
-#endif
-{
-#ifdef VA_START
- va_list args;
- int n;
-#endif
-
+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 = MALLOC (partial_message_size);
+ partial_message = (char *)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);
+ 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;
-#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,
+ /*
+ * 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);
- if (n < partial_message_size - partial_message_size_used)
+ /* 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 = REALLOC (partial_message, partial_message_size);
+ partial_message = (char *)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);
+}
+#endif
- /* 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"));
- }
+void
+#ifdef HAVE_STDARG_H
+report_build (FILE *errfp, const char *message, ...)
+#else
+report_build (FILE *errfp, message, va_alist)
+ const char *message;
+ va_dcl
#endif
- va_end (args);
+{
+#ifdef VA_START
+ va_list args;
+#else
+ int n;
+#endif
+
+ rep_ensuresize();
+
+#if defined(VA_START)
+ VA_START(args, message);
+ report_vbuild(message, args);
+ 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)
+ /* 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 = 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"));
+ 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);
+ report(errfp, "%s", partial_message);
+ partial_suppress_tag = 1;
}
}
-\f
+
/* 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, ...)
{
#ifdef VA_START
va_list args;
- 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);
- }
-#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);
+ VA_START(args, message);
+ report_vbuild(message, args);
+ 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);
- }
-#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;
- if (use_stderr)
+ if (unbuffered)
{
fputs(partial_message, errfp);
fflush (errfp);
-
- ++report_message_count;
}
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,
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);
+ fprintf (errfp, "%s:%u: ", file_name, line_number);
#ifdef VA_START
VA_START (args, message);
-# if HAVE_VPRINTF || _LIBC
+# if defined(HAVE_VPRINTF) || defined(_LIBC)
vfprintf (errfp, message, args);
# else
_doprnt (message, args, errfp);
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);