/*
* dnsutl - utilities to make DNS easier to configure
* Copyright (C) 1991-1993, 1995, 1999, 2000, 2006, 2007 Peter Miller
*
* 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 3 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, see
* <http://www.gnu.org/licenses/>.
*/
#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 <arglex.h>
static char *huge_buffer;
static void
make_huge_buffer(void)
{
static int entry_count;
if (huge_buffer)
return;
entry_count++;
if (entry_count != 1)
{
static char small_buffer[100];
/* just enuf for "out of memory" message */
huge_buffer = small_buffer;
}
else
{
huge_buffer = malloc(100000L);
if (!huge_buffer)
fatal("can't alloc buffer for error messages");
}
entry_count--;
}
/*
* 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(const char *s)
{
static char escapes[] = "\rr\nn\ff\bb\tt";
char tmp[PAGE_WIDTH + 2];
int first_line;
char *tp;
int bomb_later;
/*
* 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;
first_line = 1;
while (*s)
{
const 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 != ' ')
{
const 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: ", progname);
else
strcpy(tmp, " ");
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! */
exit(1);
}
if (bomb_later)
{
errno = bomb_later;
nfatal("(stdout)");
}
}
/*
* 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(const char *s, ...)
{
va_list ap;
va_start(ap, s);
make_huge_buffer();
vsprintf(huge_buffer, s, ap);
va_end(ap);
wrap(huge_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(const char *s, ...)
{
va_list ap;
int n;
va_start(ap, s);
n = errno;
make_huge_buffer();
vsprintf(huge_buffer, s, ap);
va_end(ap);
strcat(huge_buffer, ": ");
strcat(huge_buffer, strerror(n));
wrap(huge_buffer);
}
/*
* 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(const char *s, ...)
{
va_list ap;
int n;
va_start(ap, s);
n = errno;
make_huge_buffer();
vsprintf(huge_buffer, s, ap);
va_end(ap);
strcat(huge_buffer, ": ");
strcat(huge_buffer, strerror(n));
wrap(huge_buffer);
exit(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(const char *s, ...)
{
va_list ap;
va_start(ap, s);
make_huge_buffer();
vsprintf(huge_buffer, s, ap);
va_end(ap);
wrap(huge_buffer);
exit(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".
*
*/
void
cook_assert(int c, const char *s, const char *file, int line)
{
if (c)
return;
error("%s: %d: assertion \"%s\" failed (bug)", file, line, s);
abort();
}
syntax highlighted by Code2HTML, v. 0.9.1