/*************************************************************************
** ^FILE: syserr.c - error-message printing routines
**
** ^DESCRIPTION:
**    This fill implements various routines for printing diagnostic
**    messages on standard diagnostic output (stderr). The routines are:
**
**       usrerr()  --  print message and any system message(s) and return
**       syserr()  --  print message and any system message(s) and exit
**       eprintf() --  print to stderr and return
**
** ^HISTORY:
**    27/08/91 	Earl Chew 	<cechew@bruce.cs.monash.edu.au>
**    - Use ProgNameLen when accessing ProgName
**
**    01/02/91	Brad Appleton	<brad@ssd.csd.harris.com>
**       - Changed to use varargs/stdargs
**       - Added structured comment blocks
**       - Added eprintf()
**
**    --/--/--	Peter da Silva	<peter@ferranti.com>
**
**    --/--/--	Eric P. Allman	<eric@Berkeley.EDU> 	Created
***^^**********************************************************************/

#include <stdio.h>
#include <errno.h>
#include <useful.h>
/* #include <funclist.h> */

#ifdef vms
# include <ssdef.h>
# define  e_FATAL  SS$_CANCEL
#else
# define  e_FATAL  127
#endif

VERSIONID("$Header: syserr.c,v 2.0 89/12/24 00:56:31 eric Exp $");

extern  char *ProgName;
extern  int ProgNameLen;
EXTERN  int   vfprintf  ARGS((FILE *, const char *, va_list));


/***************************************************************************
** ^FUNCTION: _error_message - generic message printing routine.
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
   static VOID _error_message( format, ap )
/*
** ^PARAMETERS:
*/
   char *format;
/*    -- the formatted message-string to print.
*/
   va_list ap;
/*    -- the list of variable arguments for vfprintf().
*/
#endif  /* !__ANSI_C__ */

/* ^DESCRIPTION:
**    _error_message will print the program name followed by the
**    formatted message. If errno is non-zero, the corresponding
**    system message will also be printed.
**
** ^REQUIREMENTS:
**    None.
**
** ^SIDE-EFFECTS:
**    Writes to stderr.
**
** ^RETURN-VALUE:
**    None.
**
** ^ALGORITHM:
**    - print the program name
**    - print the message
**    - if errno is non-zero, call perror()
***^^**********************************************************************/
#ifdef __ANSI_C__
   static void _error_message( const char *format, va_list ap )
#endif
{
   int save_err;

   save_err = errno;
   if (ProgName  &&  *ProgName)
      fprintf(stderr, "%.*s: ", ProgNameLen, ProgName);

   (VOID) vfprintf(stderr, format, ap);

   fputc('\n', stderr);
   if ( save_err ) {
      errno = save_err;
      perror("System error");
   }
   fflush(stderr);
}


/***************************************************************************
** ^FUNCTION: syserr - print a formatted message and exit
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
   VOID syserr( format, va_alist )
/*
** ^PARAMETERS:
*/
   char *format;
/*    -- the format string to pass to vfprintf()
*/
   va_dcl  
/*    -- the arguments to be formatted
*/
#endif  /* !__ANSI_C__ */

/* ^DESCRIPTION:
**    Syserr will print the current program name followed by the
**    formatted message. If errno is non-zero, it will use perror
**    to print the corresponding system error message. Lastly, Syserr
**    will terminate execution with an exit code of 1.
**
** ^REQUIREMENTS:
**    No special requirements.
**
** ^SIDE-EFFECTS:
**    All output is written to stderr. Program execution is terminated.
**
** ^RETURN-VALUE:
**    None (Does not return).
**
** ^ALGORITHM:
**    - print the error message(s)
**    - take care of recursive calls to syserr()
**    - exit
***^^**********************************************************************/
#ifdef __ANSI_C__
   void syserr( const char *format, ... )
#endif
{
   static BOOL exiting = FALSE;
   va_list ap;

   /* print the error message */
   VA_START(ap, format);
   _error_message(format, ap);
   VA_END(ap);

   /* if we recursively syserr during exit, drop out now! */
   if (exiting)  exit(e_FATAL);

   /* try a clean exit */
   exiting = TRUE;
   exit(e_FATAL);
   /*NOTREACHED*/
}


/***************************************************************************
** ^FUNCTION: eprintf - print a formatted message on stderr.
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
   int eprintf( format, va_alist )
/*
** ^PARAMETERS:
*/
   char *format;
/*    -- the printf() message to print.
*/
   va_dcl
/*    -- the arguments to be formatted
*/
#endif  /* !__ANSI_C__ */

/* ^DESCRIPTION:
**    Eprintf() will behaves exactly like printf with the sole
**    exception being that it writes to stderr instead of stdout.
**
** ^REQUIREMENTS:
**    None.
**
** ^SIDE-EFFECTS:
**    Writes to stderr.
**
** ^RETURN-VALUE:
**    Same as printf(3).
**
** ^ALGORITHM:
**    Trivial.
***^^**********************************************************************/
#ifdef __ANSI_C__
   int eprintf( const char *format, ... )
#endif
{
   int rc;
   va_list ap;

   VA_START(ap, format);
   rc = vfprintf( stderr, format, ap );
   VA_END(ap);

   fflush(stderr);
   return rc;
}


/***************************************************************************
** ^FUNCTION: usrerr - print a user error message
**
** ^SYNOPSIS:
*/
#ifndef __ANSI_C__
   VOID usrerr( format, va_alist )
/*
** ^PARAMETERS:
*/
   char *format;
/*    -- the format string to pass to vfprintf()
*/
   va_dcl
/*    -- the arguments to be formatted
*/
#endif  /* !__ANSI_C__ */

/* ^DESCRIPTION:
**    Usrerr will print the current program name followed by the
**    formatted message. If errno is non-zero, it will use perror
**    to print the corresponding system error message.
**
** ^REQUIREMENTS:
**    No special requirements.
**
** ^SIDE-EFFECTS:
**    All output is written to stderr.  Errno is cleared.
**
** ^RETURN-VALUE:
**    None.
**
** ^ALGORITHM:
**    - print the error message(s)
**    - set errno to zero
***^^**********************************************************************/
#ifdef __ANSI_C__
   void usrerr( const char *format, ... )
#endif
{
   va_list ap;

   /* print the error message */
   VA_START(ap, format);
   _error_message(format, ap);
   VA_END(ap);

   /* give us a clean slate */
   errno = 0;
}
