X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=report.c;h=5d9abb73a8332bb48d0fc13dc4afd54494869016;hb=d31db10231e9ed89f64fdf6e0fb7cae182aa377e;hp=1e6536467ce9ea887e432fa69802c3661f0812e7;hpb=26f66a929674173cdbf6e132a683cf6e31f9bfd5;p=~andy%2Ffetchmail diff --git a/report.c b/report.c index 1e653646..5d9abb73 100644 --- a/report.c +++ b/report.c @@ -1,42 +1,29 @@ -/* 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 . - * Heavily modified by Dave Bodenstab and ESR. - * Bludgeoned into submission for SunOS 4.1.3 by - * Chris Cheyney . - * 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 . 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 + * . It works even when the return from + * vprintf(3) is unreliable. */ #ifdef HAVE_CONFIG_H -# include +# include "config.h" #endif - #include #include +#include #if defined(HAVE_SYSLOG) #include #endif -#if defined(HAVE_ALLOCA_H) -#include -#endif +#include "i18n.h" +#include "fetchmail.h" -#if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC -# if __STDC__ +#if defined(HAVE_VPRINTF) || defined(HAVE_DOPRNT) || defined(_LIBC) || defined(HAVE_STDARG_H) +# if HAVE_STDARG_H # include # define VA_START(args, lastarg) va_start(args, lastarg) # else @@ -48,36 +35,18 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ # define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8; #endif -#if STDC_HEADERS || _LIBC -# include -# include -#else -void exit (); -#endif - -#include "fetchmail.h" +#define MALLOC(n) xmalloc(n) +#define REALLOC(n,s) xrealloc(n,s) -#ifndef _ -# define _(String) String -#endif - -/* 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. */ @@ -87,454 +56,345 @@ unsigned int error_message_count; #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 -#if defined(VA_START) && __STDC__ -error (int status, int errnum, const char *message, ...) +#ifdef HAVE_STDARG_H +report (FILE *errfp, const char *message, ...) #else -error (status, errnum, message, va_alist) - int status; - int errnum; - char *message; +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); - - strcpy (msg, message); - strcat (msg, ": %m"); + priority = (errfp == stderr) ? LOG_ERR : LOG_INFO; - 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) - fprintf (stderr, ": %s", strerror (errnum)); - putc ('\n', stderr); - fflush (stderr); + fflush (errfp); } - ++error_message_count; - if (status) - exit (status); } - -/* - * 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 */ + } } - -/* 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. + sequence, the partial message will be printed as-is (with a trailing + newline) before report() prints its message. */ /* VARARGS */ -void -#if defined(VA_START) && __STDC__ -error_build (const char *message, ...) -#else -error_build (message, va_alist) - char *message; - va_dcl -#endif -{ -#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) +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 = xmalloc (partial_message_size); + 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 = xrealloc (partial_message, partial_message_size); - } - -#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; + else + if (partial_message_size - partial_message_size_used < 1024) + { + partial_message_size += 2048; + partial_message = (char *)REALLOC (partial_message, partial_message_size); } +} - 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); +#ifdef HAVE_STDARG_H +static void report_vbuild(const char *message, va_list args) +{ + int n; - /* 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 ( ; ; ) + 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) + /* + * 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_used += n; + break; } - partial_message_size += 2048; - partial_message = xrealloc (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; - error (PS_UNDEFINED, 0, "partial error message buffer overflow"); - } -#endif -#endif - - if (use_stderr && partial_message_size_used != 0) - { - partial_message_size_used = 0; - fputs(partial_message, stderr); + partial_message_size += 2048; + partial_message = (char *)REALLOC (partial_message, partial_message_size); } } - -/* 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 - empty.) -/* VARARGS */ +#endif void -#if defined(VA_START) && __STDC__ -error_complete (int status, int errnum, const char *message, ...) +#ifdef HAVE_STDARG_H +report_build (FILE *errfp, const char *message, ...) #else -error_complete (status, errnum, message, va_alist) - int status; - int errnum; - char *message; +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 ( ; ; ) + VA_START(args, message); + report_vbuild(message, args); + va_end(args); +#else + for ( ; ; ) { - n = vsnprintf (partial_message + partial_message_size_used, - partial_message_size - partial_message_size_used, - message, args); + 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); - } -#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"); + partial_message_size += 2048; + partial_message = REALLOC (partial_message, partial_message_size); } #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); + if (unbuffered && partial_message_size_used != 0) + { + partial_message_size_used = 0; + fputs(partial_message, errfp); } -#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) +void report_flush(FILE *errfp) +{ + if (partial_message_size_used != 0) { - partial_message_size_used = 0; - error (PS_UNDEFINED, 0, "partial error message buffer overflow"); + partial_message_size_used = 0; + report(errfp, "%s", partial_message); + partial_suppress_tag = 1; } +} + +/* 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, ...) +#else +report_complete (FILE *errfp, message, va_alist) + const char *message; + va_dcl #endif +{ +#ifdef VA_START + va_list args; #endif - /* Finally... print it. */ - partial_message_size_used = 0; - - if (use_stderr) - { - fputs(partial_message, stderr); - - if (errnum) - fprintf (stderr, ": %s", strerror (errnum)); + rep_ensuresize(); - putc ('\n', stderr); - fflush (stderr); +#if defined(VA_START) + VA_START(args, message); + report_vbuild(message, args); + va_end(args); +#else + report_build(errfp, message, a1, a2, a3, a4, a5, a6, a7, a8); +#endif - ++error_message_count; + /* Finally... print it. */ + partial_message_size_used = 0; - if (status) - exit(status); + if (unbuffered) + { + fputs(partial_message, errfp); + fflush (errfp); } - else - error (status, errnum, "%s", partial_message); + else + report(errfp, "%s", partial_message); } - + /* 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 -#if defined(VA_START) && __STDC__ -error_at_line (int status, int errnum, const char *file_name, +#ifdef HAVE_STDARG_H +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; - char *message; + const char *message; va_dcl #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); }