Logo Search packages:      
Sourcecode: fhist version File versions

error.c

/*
 *    fhist - file history and comparison tools
 *    Copyright (C) 1991-1994, 1998-2000, 2002 Peter Miller;
 *    All rights reserved.
 *
 *    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 of the License, 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, USA.
 *
 * MANIFEST: functions to report errors
 */

#include <ac/ctype.h>
#include <ac/errno.h>
#include <ac/stdarg.h>
#include <ac/stddef.h>
#include <ac/stdio.h>
#include <ac/stdlib.h>
#include <ac/string.h>

#include <error.h>
#include <mprintf.h>
#include <progname.h>
#include <quit.h>


/*
 * NAME
 *    wrap - wrap s string over lines
 *
 * SYNOPSIS
 *    void wrap(char *);
 *
 * DESCRIPTION
 *    The wrap function is used to print error messages onto stderr
 *    wrapping ling lines.
 *
 * CAVEATS
 *    Line length is assumed to be 80 characters.
 */

#define PAGE_WIDTH 79

static void
wrap(char *s)
{
      static char escapes[] = "\rr\nn\ff\bb\tt";
      char  tmp[PAGE_WIDTH + 2];
      int   first_line;
      char  *tp;
      int   bomb_later;
      char  *progname;
      
      /*
       * Flush stdout so that errors are in sync with the output.
       * If you get an error doing this, whinge about it _after_ reporting
       * the originating error.  Also, clear the error on stdout to 
       * avoid getting caught in an infinite loop.
       */
      if (fflush(stdout) || ferror(stdout))
      {
            bomb_later = errno;
            clearerr(stdout);
      }
      else
            bomb_later = 0;

      progname = progname_get();
      first_line = 1;
      while (*s)
      {
            char  *ep;
            int   ocol;

            /*
             * Work out how many characters fit on the line.
             */
            if (first_line)
                  ocol = strlen(progname) + 2;
            else
                  ocol = 8;
            for (ep = s; *ep; ++ep)
            {
                  int   cw;
                  int   c;

                  c = (unsigned char)*ep;
                  if (isprint(c))
                        cw = 1 + (c == '\\');
                  else
                        cw = (strchr(escapes, c) ? 2 : 4);
                  if (ocol + cw > PAGE_WIDTH)
                        break;
                  ocol += cw;
            }

            /*
             * see if there is a better place to break the line
             */
            if (*ep && *ep != ' ')
            {
                  char  *mp;

                  for (mp = ep; mp > s; --mp)
                  {
                        if (strchr(" /", mp[-1]))
                        {
                              ep = mp;
                              break;
                        }
                  }
            }

            /*
             * ignore trailing blanks
             */
            while (ep > s && ep[-1] == ' ')
                  ep--;
            
            /*
             * print the line
             */
            if (first_line)
                  sprintf(tmp, "%.*s: ", (int)(sizeof(tmp) - 3), progname);
            else
                  strcpy(tmp, "\t");
            tp = tmp + strlen(tmp);
            while (s < ep)
            {
                  int   c;

                  c = (unsigned char)*s++;
                  if (isprint(c))
                  {
                        if (c == '\\')
                              *tp++ = '\\';
                        *tp++ = c;
                  }
                  else
                  {
                        char  *esc;

                        esc = strchr(escapes, c);
                        if (esc)
                        {
                              *tp++ = '\\';
                              *tp++ = esc[1];
                        }
                        else
                        {
                              sprintf(tp, "\\%3.3o", c);
                              tp += strlen(tp);
                        }
                  }
            }
            *tp++ = '\n';
            *tp = 0;
            fputs(tmp, stderr);
            if (ferror(stderr))
                  break;

            /*
             * skip leading spaces for subsequent lines
             */
            while (*s == ' ')
                  s++;
            first_line = 0;
      }
      if (fflush(stderr) || ferror(stderr))
      {
            /* don't print why, there is no point! */
            quit(1);
      }
      if (bomb_later)
      {
            errno = bomb_later;
            nfatal_raw("(stdout)");
      }
}


static void
double_jeopardy(void)
{
      char  buffer[200];

      sprintf
      (
            buffer,
            "while attempting to construct an error message: %.100s (fatal)",
            strerror(errno)
      );
      wrap(buffer);
      quit(1);
}


static char *
copy_string(char *s)
{
      char        *cp;

      errno = 0;
      cp = malloc(strlen(s) + 1);
      if (!cp)
      {
            if (!errno)
                  errno = ENOMEM;
            double_jeopardy();
      }
      strcpy(cp, s);
      return cp;
}


/*
 *  NAME
 *    error - place a message on the error stream
 *
 *  SYNOPSIS
 *    void error(char *s, ...);
 *
 *  DESCRIPTION
 *    Error places a message on the error output stream.
 *    The first argument is a printf-like format string,
 *    optionally followed by other arguments.
 *    The message will be prefixed by the program name and a colon,
 *    and will be terminated with a newline, automatically.
 *
 *  CAVEAT
 *    Things like "error(filename)" blow up if the filename
 *    contains a '%' character.
 */

void
error_raw(char *s, ...)
{
      va_list           ap;
      char        *buffer;

      va_start(ap, s);
      buffer = vmprintf_errok(s, ap);
      if (!buffer)
            double_jeopardy();
      va_end(ap);
      wrap(buffer);
}


/*
 *  NAME
 *    nerror - place a system fault message on the error stream
 *
 *  SYNOPSIS
 *    void nerror(char *s, ...);
 *
 *  DESCRIPTION
 *    Nerror places a message on the error output stream.
 *    The first argument is a printf-like format string,
 *    optionally followed by other arguments.
 *    The message will be prefixed by the program name and a colon,
 *    and will be terminated with a text description of the error
 *    indicated by the 'errno' global variable, automatically.
 *
 *  CAVEAT
 *    Things like "nerror(filename)" blow up if the filename
 *    contains a '%' character.
 */

void
nerror_raw(char *s, ...)
{
      va_list           ap;
      int         n;
      char        *buf1;
      char        *buf2;

      n = errno;
      va_start(ap, s);
      buf1 = vmprintf_errok(s, ap);
      if (!buf1)
            double_jeopardy();
      va_end(ap);
      buf1 = copy_string(buf1);
      buf2 = mprintf_errok("%s: %s", buf1, strerror(n));
      if (!buf2)
            double_jeopardy();
      free(buf1);
      wrap(buf2);
}


/*
 *  NAME
 *    nfatal - place a system fault message on the error stream and exit
 *
 *  SYNOPSIS
 *    void nfatal(char *s, ...);
 *
 *  DESCRIPTION
 *    Nfatal places a message on the error output stream and exits.
 *    The first argument is a printf-like format string,
 *    optionally followed by other arguments.
 *    The message will be prefixed by the program name and a colon,
 *    and will be terminated with a text description of the error
 *    indicated by the 'errno' global variable, automatically.
 *
 *  CAVEAT
 *    Things like "nfatal(filename)" blow up if the filename
 *    contains a '%' character.
 *
 *    This function does NOT return.
 */

void
nfatal_raw(char *s, ...)
{
      va_list           ap;
      int         n;
      char        *buf1;
      char        *buf2;

      n = errno;
      va_start(ap, s);
      buf1 = vmprintf_errok(s, ap);
      if (!buf1)
            double_jeopardy();
      va_end(ap);
      buf1 = copy_string(buf1);
      buf2 = mprintf_errok("%s: %s", buf1, strerror(n));
      if (!buf2)
            double_jeopardy();
      wrap(buf2);
      quit(1);
}


/*
 *  NAME
 *    fatal - place a message on the error stream and exit
 *
 *  SYNOPSIS
 *    void fatal(char *s, ...);
 *
 *  DESCRIPTION
 *    Fatal places a message on the error output stream and exits.
 *    The first argument is a printf-like format string,
 *    optionally followed by other arguments.
 *    The message will be prefixed by the program name and a colon,
 *    and will be terminated with a newline, automatically.
 *
 *  CAVEAT
 *    Things like "error(filename)" blow up if the filename
 *    contains a '%' character.
 *
 *    This function does NOT return.
 */

void
fatal_raw(char *s, ...)
{
      va_list           ap;
      char        *buffer;

      va_start(ap, s);
      buffer = vmprintf_errok(s, ap);
      if (!buffer)
            double_jeopardy();
      va_end(ap);
      wrap(buffer);
      quit(1);
}


/*
 *  NAME
 *    assert - make an assertion
 *
 *  SYNOPSIS
 *    void assert(int condition);
 *
 *  DESCRIPTION
 *    Assert is a handy tool for a programmer to guarantee the internal
 *    consistency of their program. If "-DDEBUG" is specified on
 *    the compiler's command line, then assert will generate code to verify
 *    the assertios made. If no DEBUG is defined, assertions will generate
 *    no code.
 *
 *  CAVEAT
 *    If the assertion fails, a fatal diagnostic is issued.
 *
 *    The #define's which control the compilation may be found in "error.h".
 *
 */

#ifdef my_assert
#undef my_assert
#endif

void
my_assert(int c, char *s, char *file, int line)
{
      if (c)
            return;
      error_raw("%s: %d: assertion \"%s\" failed (bug)", file, line, s);
      abort();
}

Generated by  Doxygen 1.6.0   Back to index