/*
* 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();
}
syntax highlighted by Code2HTML, v. 0.9.1