-/* error.c -- error handler for noninteractive utilities
- Copyright (C) 1990, 91, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
-
-This program is free software; you can redistribute it and/or modify
-it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
-any later version.
-
-This program is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License
-along with this program; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
-
-/* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
- * Heavily modified by Dave Bodenstab and ESR.
- * Bludgeoned into submission for SunOS 4.1.3 by
- * Chris Cheyney <cheyney@netcom.com>.
- * Now it works even when the return from vprintf is unreliable.
+/** \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 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
-#if defined(HAVE_ALLOCA_H)
-#include <alloca.h>
-#else
-#ifdef _AIX
- #pragma alloca
-#endif
-#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 "fetchmail.h"
-
-#ifndef _
-# define _(String) String
-#endif
+#define MALLOC(n) xmalloc(n)
+#define REALLOC(n,s) xrealloc(n,s)
-/* If NULL, error will flush stdout, then print on stderr the program
- name, a colon and a space. Otherwise, error will call this
- function without parameters instead. */
-void (*error_print_progname) (
-#if __STDC__ - 0
- void
-#endif
- );
-
-/* Used by error_build() and error_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 int partial_suppress_tag = 0;
-/* This variable is incremented each time `error' is called. */
-unsigned int error_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
-# ifndef strerror /* On some systems, strerror is a macro */
-char *strerror ();
-# endif
-# else
-static char *
-private_strerror (errnum)
- int errnum;
+# if !HAVE_STRERROR && !defined(strerror)
+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 _("Unknown system error");
+ if (errnum > 0 && errnum <= sys_nerr)
+ return sys_errlist[errnum];
+ return GT_("Unknown system error");
}
-# define strerror private_strerror
# 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.
- Exit with status STATUS if it is nonzero. */
+ format string with optional args. */
/* VARARGS */
-
void
#ifdef HAVE_STDARG_H
-error (int status, int errnum, const char *message, ...)
+report (FILE *errfp, const char *message, ...)
#else
-error (status, errnum, message, va_alist)
- int status;
- int errnum;
+report (FILE *errfp, message, va_alist)
const char *message;
va_dcl
#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;
- error (0, 0, "%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 = status? LOG_ALERT : errnum? LOG_ERR : LOG_INFO;
-
- if (errnum > 0)
- {
- char *msg = alloca (strlen (message) + 5);
+ priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
- strcpy (msg, message);
- strcat (msg, ": %m");
-
- errno = errnum;
#ifdef HAVE_VSYSLOG
- vsyslog (priority, msg, 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, msg, a1, a2, a3, a4, a5, a6, a7, a8);
- }
-#endif
+ {
+ 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);
}
- else
- {
-#ifdef HAVE_VSYSLOG
- 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);
- }
#endif
- }
#ifdef VA_START
- va_end(args);
+ va_end(args);
#endif
}
- else
+ else /* i. e. not using syslog */
#endif
{
- if (error_print_progname)
- (*error_print_progname) ();
- else
+ if ( *message == '\n' )
{
- fflush (stdout);
- if ( *message == '\n' )
- {
- fputc( '\n', stderr );
- ++message;
- }
- fprintf (stderr, "%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 (stderr, message, args);
+ VA_START (args, message);
+# if defined(HAVE_VPRINTF) || defined(_LIBC)
+ vfprintf (errfp, message, args);
# else
- _doprnt (message, args, stderr);
+ _doprnt (message, args, errfp);
# endif
- va_end (args);
+ va_end (args);
#else
- fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+ fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
#endif
-
- if (errnum && errnum != -1) {
- char *tmps = strerror(errnum);
- if (tmps) {
- fprintf (stderr, ": %s", tmps);
- }
- else {
- fprintf (stderr, ": Error %d", errnum);
- }
- }
- putc ('\n', stderr);
- fflush (stderr);
+ fflush (errfp);
}
- ++error_message_count;
- if (status)
- exit (status);
}
-\f
-/*
- * Calling error_init(TRUE) causes error_build and error_complete to write
- * to stderr 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 error_init(foreground)
-int foreground;
+void report_init(int mode /** 0: regular output, 1: unbuffered output, -1: syslog */)
{
- use_stderr = foreground;
+ switch(mode)
+ {
+ case 0: /* errfp, buffered */
+ default:
+ unbuffered = FALSE;
+ use_syslog = FALSE;
+ break;
+
+ case 1: /* errfp, unbuffered */
+ unbuffered = TRUE;
+ use_syslog = FALSE;
+ break;
+
+#ifdef HAVE_SYSLOG
+ case -1: /* syslogd */
+ unbuffered = FALSE;
+ use_syslog = TRUE;
+ break;
+#endif /* HAVE_SYSLOG */
+ }
}
-\f
-/* Build an error message by appending MESSAGE, which is a printf-style
- format string with optional args, to the existing error message (which may
- be empty.) The completed error message is finally printed (and reset to
- empty) by calling error_complete().
- If an intervening call to error() occurs when a partially constructed
+
+/* 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
+ empty) by calling report_complete().
+ If an intervening call to report() occurs when a partially constructed
message exists, then, in an attempt to keep the messages in their proper
sequence, the partial message will be printed as-is (with a trailing
- newline) before error() prints its message. */
+ 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
-error_build (const char *message, ...)
+report_build (FILE *errfp, const char *message, ...)
#else
-error_build (message, va_alist)
+report_build (FILE *errfp, message, va_alist)
const char *message;
va_dcl
#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 = xmalloc (partial_message_size);
- }
- else
- if (partial_message_size - partial_message_size_used < 1024)
- {
- partial_message_size += 2048;
- partial_message = xrealloc (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 = xrealloc (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;
- error (PS_UNDEFINED, 0, "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 = xrealloc (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;
- error (PS_UNDEFINED, 0, "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, stderr);
+ partial_message_size_used = 0;
+ report(errfp, "%s", partial_message);
+ partial_suppress_tag = 1;
}
}
-\f
-/* Complete an error message by appending MESSAGE, which is a printf-style
- format string with optional args, to the existing error message (which may
- be empty.) The completed error message is then printed (and reset to
+
+/* 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
-error_complete (int status, int errnum, const char *message, ...)
+report_complete (FILE *errfp, const char *message, ...)
#else
-error_complete (status, errnum, message, va_alist)
- int status;
- int errnum;
+report_complete (FILE *errfp, message, va_alist)
const char *message;
va_dcl
#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 = xmalloc (partial_message_size);
- }
- else
- if (partial_message_size - partial_message_size_used < 1024)
- {
- partial_message_size += 2048;
- partial_message = xrealloc (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 = xrealloc (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;
- error (PS_UNDEFINED, 0, "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 = xrealloc (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;
- error (PS_UNDEFINED, 0, "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, stderr);
-
- if (errnum)
- fprintf (stderr, ": %s", strerror (errnum));
-
- putc ('\n', stderr);
- fflush (stderr);
-
- ++error_message_count;
-
- if (status)
- exit(status);
+ fputs(partial_message, errfp);
+ fflush (errfp);
}
- else
- error (status, errnum, "%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
-error_at_line (int status, int errnum, const char *file_name,
+report_at_line (FILE *errfp, int errnum, const char *file_name,
unsigned int line_number, const char *message, ...)
#else
-error_at_line (status, errnum, file_name, line_number, message, va_alist)
- int status;
+report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
int errnum;
const char *file_name;
unsigned int line_number;
#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 (error_print_progname)
- (*error_print_progname) ();
- else
+ fflush (errfp);
+ if ( *message == '\n' )
{
- fflush (stdout);
- if ( *message == '\n' )
- {
- fputc( '\n', stderr );
- ++message;
- }
- fprintf (stderr, "%s:", program_name);
+ fputc( '\n', errfp );
+ ++message;
}
+ fprintf (errfp, "%s:", program_name);
- if (file_name != NULL)
- fprintf (stderr, "%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 (stderr, message, args);
+ VA_START (args, message);
+# if defined(HAVE_VPRINTF) || defined(_LIBC)
+ vfprintf (errfp, message, args);
# else
- _doprnt (message, args, stderr);
+ _doprnt (message, args, errfp);
# endif
- va_end (args);
+ va_end (args);
#else
- fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8);
+ fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
#endif
- ++error_message_count;
- if (errnum)
- fprintf (stderr, ": %s", strerror (errnum));
- putc ('\n', stderr);
- fflush (stderr);
- if (status)
- exit (status);
+ if (errnum)
+ fprintf (errfp, ": %s", strerror (errnum));
+ putc ('\n', errfp);
+ fflush (errfp);
}