error.c
上传用户:xxcykj
上传日期:2007-01-04
资源大小:727k
文件大小:13k
源码类别:

Email客户端

开发平台:

Unix_Linux

  1. /* error.c -- error handler for noninteractive utilities
  2.    Copyright (C) 1990, 91, 92, 93, 94, 95, 96 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
  14. /* Written by David MacKenzie <djm@gnu.ai.mit.edu>.
  15.  * Heavily modified by Dave Bodenstab and ESR.
  16.  * Bludgeoned into submission for SunOS 4.1.3 by
  17.  *     Chris Cheyney <cheyney@netcom.com>.
  18.  * Now it works even when the return from vprintf is unreliable.
  19.  */
  20. #ifdef HAVE_CONFIG_H
  21. # include "config.h"
  22. #endif
  23. #include <stdio.h>
  24. #include <errno.h>
  25. #if defined(HAVE_SYSLOG)
  26. #include <syslog.h>
  27. #endif
  28. #if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC || HAVE_STDARG_H
  29. # if HAVE_STDARG_H
  30. #  include <stdarg.h>
  31. #  define VA_START(args, lastarg) va_start(args, lastarg)
  32. # else
  33. #  include <varargs.h>
  34. #  define VA_START(args, lastarg) va_start(args)
  35. # endif
  36. #else
  37. # define va_alist a1, a2, a3, a4, a5, a6, a7, a8
  38. # define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8;
  39. #endif
  40. #if STDC_HEADERS || _LIBC
  41. # include <stdlib.h>
  42. # include <string.h>
  43. #else
  44. void exit ();
  45. #endif
  46. #include "i18n.h"
  47. #include "fetchmail.h"
  48. #define MALLOC(n) xmalloc(n)
  49. #define REALLOC(n,s) xrealloc(n,s)
  50. /* If NULL, error will flush stderr, then print on stderr the program
  51.    name, a colon and a space.  Otherwise, error will call this
  52.    function without parameters instead.  */
  53. void (*error_print_progname) (
  54. #if __STDC__ - 0
  55.       void
  56. #endif
  57.       );
  58. /* Used by error_build() and error_complete() to accumulate partial messages.  */
  59. static unsigned int partial_message_size = 0;
  60. static unsigned int partial_message_size_used = 0;
  61. static char *partial_message;
  62. static unsigned use_stderr;
  63. static unsigned int use_syslog;
  64. /* This variable is incremented each time `error' is called.  */
  65. unsigned int error_message_count;
  66. #ifdef _LIBC
  67. /* In the GNU C library, there is a predefined variable for this.  */
  68. # define program_name program_invocation_name
  69. # include <errno.h>
  70. #else
  71. /* The calling program should define program_name and set it to the
  72.    name of the executing program.  */
  73. extern char *program_name;
  74. # if !HAVE_STRERROR && !defined(strerror)
  75. char *strerror (errnum)
  76.      int errnum;
  77. {
  78.   extern char *sys_errlist[];
  79.   extern int sys_nerr;
  80.   if (errnum > 0 && errnum <= sys_nerr)
  81.     return sys_errlist[errnum];
  82.   return _("Unknown system error");
  83. }
  84. # endif /* HAVE_STRERROR */
  85. #endif /* _LIBC */
  86. /* Print the program name and error message MESSAGE, which is a printf-style
  87.    format string with optional args.
  88.    If ERRNUM is nonzero, print its corresponding system error message. */
  89. /* VARARGS */
  90. void
  91. #ifdef HAVE_STDARG_H
  92. report (FILE *errfp, const char *message, ...)
  93. #else
  94. report (FILE *errfp, message, va_alist)
  95.      const char *message;
  96.      va_dcl
  97. #endif
  98. {
  99. #ifdef VA_START
  100.   va_list args;
  101. #endif
  102.   /* If a partially built message exists, print it now so it's not lost.  */
  103.   if (partial_message_size_used != 0)
  104.     {
  105.       partial_message_size_used = 0;
  106.       report (errfp, 0, _("%s (log message incomplete)"), partial_message);
  107.     }
  108. #if defined(HAVE_SYSLOG)
  109.   if (use_syslog)
  110.     {
  111.       int priority;
  112. #ifdef VA_START
  113.       VA_START (args, message);
  114. #endif
  115.       priority = (errfp == stderr) ? LOG_ERR : LOG_INFO;
  116. #ifdef HAVE_VSYSLOG
  117.       vsyslog (priority, message, args);
  118. #else
  119.       {
  120.   char *a1 = va_arg(args, char *);
  121.   char *a2 = va_arg(args, char *);
  122.   char *a3 = va_arg(args, char *);
  123.   char *a4 = va_arg(args, char *);
  124.   char *a5 = va_arg(args, char *);
  125.   char *a6 = va_arg(args, char *);
  126.   char *a7 = va_arg(args, char *);
  127.   char *a8 = va_arg(args, char *);
  128.   syslog (priority, message, a1, a2, a3, a4, a5, a6, a7, a8);
  129.       }
  130. #endif
  131. #ifdef VA_START
  132.       va_end(args);
  133. #endif
  134.     }
  135.   else
  136. #endif
  137.     {
  138.       if (error_print_progname)
  139. (*error_print_progname) ();
  140.       else
  141. {
  142.   fflush (errfp);
  143.   if ( *message == 'n' )
  144.     {
  145.       fputc( 'n', errfp );
  146.       ++message;
  147.     }
  148.   fprintf (errfp, "%s: ", program_name);
  149. }
  150. #ifdef VA_START
  151.       VA_START (args, message);
  152. # if HAVE_VPRINTF || _LIBC
  153.       vfprintf (errfp, message, args);
  154. # else
  155.       _doprnt (message, args, errfp);
  156. # endif
  157.       va_end (args);
  158. #else
  159.       fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
  160. #endif
  161.       fflush (errfp);
  162.     }
  163.   ++error_message_count;
  164. }
  165. /*
  166.  * Calling report_init(1) causes error_build and error_complete to write
  167.  * to errfp without buffering.  This is needed for the ticker dots to
  168.  * work correctly.
  169.  */
  170. void report_init(int mode)
  171. {
  172.     switch(mode)
  173.     {
  174.     case 0: /* errfp, buffered */
  175.     default:
  176. use_stderr = FALSE;
  177. use_syslog = FALSE;
  178. break;
  179.     case 1: /* errfp, unbuffered */
  180. use_stderr = TRUE;
  181. use_syslog = FALSE;
  182. break;
  183. #ifdef HAVE_SYSLOG
  184.     case -1: /* syslogd */
  185. use_stderr = FALSE;
  186. use_syslog = TRUE;
  187. break;
  188. #endif /* HAVE_SYSLOG */
  189.     }
  190. }
  191. /* Build an error message by appending MESSAGE, which is a printf-style
  192.    format string with optional args, to the existing error message (which may
  193.    be empty.)  The completed error message is finally printed (and reset to
  194.    empty) by calling error_complete().
  195.    If an intervening call to report() occurs when a partially constructed
  196.    message exists, then, in an attempt to keep the messages in their proper
  197.    sequence, the partial message will be printed as-is (with a trailing 
  198.    newline) before report() prints its message. */
  199. /* VARARGS */
  200. void
  201. #ifdef HAVE_STDARG_H
  202. report_build (FILE *errfp, const char *message, ...)
  203. #else
  204. report_build (FILE *errfp, message, va_alist)
  205.      const char *message;
  206.      va_dcl
  207. #endif
  208. {
  209. #ifdef VA_START
  210.   va_list args;
  211.   int n;
  212. #endif
  213.   /* Make an initial guess for the size of any single message fragment.  */
  214.   if (partial_message_size == 0)
  215.     {
  216.       partial_message_size_used = 0;
  217.       partial_message_size = 2048;
  218.       partial_message = MALLOC (partial_message_size);
  219.     }
  220.   else
  221.     if (partial_message_size - partial_message_size_used < 1024)
  222.       {
  223.         partial_message_size += 2048;
  224.         partial_message = REALLOC (partial_message, partial_message_size);
  225.       }
  226. #if defined(VA_START)
  227.   VA_START (args, message);
  228. #if HAVE_VSNPRINTF || _LIBC
  229.   for ( ; ; )
  230.     {
  231.       n = vsnprintf (partial_message + partial_message_size_used,
  232.      partial_message_size - partial_message_size_used,
  233.      message, args);
  234.       if (n < partial_message_size - partial_message_size_used)
  235.         {
  236.   partial_message_size_used += n;
  237.   break;
  238. }
  239.       partial_message_size += 2048;
  240.       partial_message = REALLOC (partial_message, partial_message_size);
  241.     }
  242. #else
  243.   vsprintf (partial_message + partial_message_size_used, message, args);
  244.   partial_message_size_used += strlen(partial_message+partial_message_size_used);
  245.   /* Attempt to catch memory overwrites... */
  246.   if (partial_message_size_used >= partial_message_size)
  247.     {
  248.       partial_message_size_used = 0;
  249.       report (stderr, _("partial error message buffer overflow"));
  250.     }
  251. #endif
  252.   va_end (args);
  253. #else
  254. #if HAVE_SNPRINTF
  255.   for ( ; ; )
  256.     {
  257.       n = snprintf (partial_message + partial_message_size_used,
  258.     partial_message_size - partial_message_size_used,
  259.     message, a1, a2, a3, a4, a5, a6, a7, a8);
  260.       if (n < partial_message_size - partial_message_size_used)
  261.         {
  262.   partial_message_size_used += n;
  263.   break;
  264. }
  265.       partial_message_size += 2048;
  266.       partial_message = REALLOC (partial_message, partial_message_size);
  267.     }
  268. #else
  269.   sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
  270.   /* Attempt to catch memory overwrites... */
  271.   if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
  272.     {
  273.       partial_message_size_used = 0;
  274.       report (stderr, _("partial error message buffer overflow"));
  275.     }
  276. #endif
  277. #endif
  278.   if (use_stderr && partial_message_size_used != 0)
  279.     {
  280.       partial_message_size_used = 0;
  281.       fputs(partial_message, errfp);
  282.     }
  283. }
  284. /* Complete an error message by appending MESSAGE, which is a printf-style
  285.    format string with optional args, to the existing error message (which may
  286.    be empty.)  The completed error message is then printed (and reset to
  287.    empty.) */
  288. /* VARARGS */
  289. void
  290. #ifdef HAVE_STDARG_H
  291. report_complete (FILE *errfp, const char *message, ...)
  292. #else
  293. report_complete (FILE *errfp, message, va_alist)
  294.      const char *message;
  295.      va_dcl
  296. #endif
  297. {
  298. #ifdef VA_START
  299.   va_list args;
  300.   int n;
  301. #endif
  302.   /* Make an initial guess for the size of any single message fragment.  */
  303.   if (partial_message_size == 0)
  304.     {
  305.       partial_message_size_used = 0;
  306.       partial_message_size = 2048;
  307.       partial_message = MALLOC (partial_message_size);
  308.     }
  309.   else
  310.     if (partial_message_size - partial_message_size_used < 1024)
  311.       {
  312.         partial_message_size += 2048;
  313.         partial_message = REALLOC (partial_message, partial_message_size);
  314.       }
  315. #if defined(VA_START)
  316.   VA_START (args, message);
  317. #if HAVE_VSNPRINTF || _LIBC
  318.   for ( ; ; )
  319.     {
  320.       n = vsnprintf (partial_message + partial_message_size_used,
  321.      partial_message_size - partial_message_size_used,
  322.      message, args);
  323.       if (n < partial_message_size - partial_message_size_used)
  324.         {
  325.   partial_message_size_used += n;
  326.   break;
  327. }
  328.       partial_message_size += 2048;
  329.       partial_message = REALLOC (partial_message, partial_message_size);
  330.     }
  331. #else
  332.   vsprintf (partial_message + partial_message_size_used, message, args);
  333.   partial_message_size_used += strlen(partial_message+partial_message_size_used);
  334.   /* Attempt to catch memory overwrites... */
  335.   if (partial_message_size_used >= partial_message_size)
  336.     {
  337.       partial_message_size_used = 0;
  338.       report (stderr, _("partial error message buffer overflow"));
  339.     }
  340. #endif
  341.   va_end (args);
  342. #else
  343. #if HAVE_SNPRINTF
  344.   for ( ; ; )
  345.     {
  346.       n = snprintf (partial_message + partial_message_size_used,
  347.     partial_message_size - partial_message_size_used,
  348.     message, a1, a2, a3, a4, a5, a6, a7, a8);
  349.       if (n < partial_message_size - partial_message_size_used)
  350.         {
  351.   partial_message_size_used += n;
  352.   break;
  353. }
  354.       partial_message_size += 2048;
  355.       partial_message = REALLOC (partial_message, partial_message_size);
  356.     }
  357. #else
  358.   sprintf (partial_message + partial_message_size_used, message, a1, a2, a3, a4, a5, a6, a7, a8);
  359.   /* Attempt to catch memory overwrites... */
  360.   if ((partial_message_size_used = strlen (partial_message)) >= partial_message_size)
  361.     {
  362.       partial_message_size_used = 0;
  363.       report (stderr, _("partial error message buffer overflow"));
  364.     }
  365. #endif
  366. #endif
  367.   /* Finally... print it.  */
  368.   partial_message_size_used = 0;
  369.   if (use_stderr)
  370.     {
  371.       fputs(partial_message, errfp);
  372.       fflush (errfp);
  373.       ++error_message_count;
  374.     }
  375.   else
  376.     report(errfp, "%s", partial_message);
  377. }
  378. /* Sometimes we want to have at most one error per line.  This
  379.    variable controls whether this mode is selected or not.  */
  380. int error_one_per_line;
  381. void
  382. #ifdef HAVE_STDARG_H
  383. report_at_line (FILE *errfp, int errnum, const char *file_name,
  384.        unsigned int line_number, const char *message, ...)
  385. #else
  386. report_at_line (FILE *errfp, errnum, file_name, line_number, message, va_alist)
  387.      int errnum;
  388.      const char *file_name;
  389.      unsigned int line_number;
  390.      const char *message;
  391.      va_dcl
  392. #endif
  393. {
  394. #ifdef VA_START
  395.   va_list args;
  396. #endif
  397.   if (error_one_per_line)
  398.     {
  399.       static const char *old_file_name;
  400.       static unsigned int old_line_number;
  401.       if (old_line_number == line_number &&
  402.   (file_name == old_file_name || !strcmp (old_file_name, file_name)))
  403. /* Simply return and print nothing.  */
  404. return;
  405.       old_file_name = file_name;
  406.       old_line_number = line_number;
  407.     }
  408.   if (error_print_progname)
  409.     (*error_print_progname) ();
  410.   else
  411.     {
  412.       fflush (errfp);
  413.       if ( *message == 'n' )
  414. {
  415.   fputc( 'n', errfp );
  416.   ++message;
  417. }
  418.       fprintf (errfp, "%s:", program_name);
  419.     }
  420.   if (file_name != NULL)
  421.     fprintf (errfp, "%s:%d: ", file_name, line_number);
  422. #ifdef VA_START
  423.   VA_START (args, message);
  424. # if HAVE_VPRINTF || _LIBC
  425.   vfprintf (errfp, message, args);
  426. # else
  427.   _doprnt (message, args, errfp);
  428. # endif
  429.   va_end (args);
  430. #else
  431.   fprintf (errfp, message, a1, a2, a3, a4, a5, a6, a7, a8);
  432. #endif
  433.   ++error_message_count;
  434.   if (errnum)
  435.     fprintf (errfp, ": %s", strerror (errnum));
  436.   putc ('n', errfp);
  437.   fflush (errfp);
  438. }