diff options
Diffstat (limited to 'src/libeinfo')
-rw-r--r-- | src/libeinfo/Makefile | 14 | ||||
-rw-r--r-- | src/libeinfo/einfo.h | 144 | ||||
-rw-r--r-- | src/libeinfo/einfo.map | 35 | ||||
-rw-r--r-- | src/libeinfo/libeinfo.c | 1060 |
4 files changed, 1253 insertions, 0 deletions
diff --git a/src/libeinfo/Makefile b/src/libeinfo/Makefile new file mode 100644 index 00000000..b6826340 --- /dev/null +++ b/src/libeinfo/Makefile @@ -0,0 +1,14 @@ +TOPDIR= .. +include $(TOPDIR)/os.mk + +LIB= einfo +SHLIB_MAJOR= 1 +SRCS= libeinfo.c +INCS= einfo.h + +SHLIBDIR= /${LIBNAME} + +include $(TOPDIR)/cc.mk +include $(TOPDIR)/lib.mk +include $(TOPDIR)/$(TERMCAP).mk + diff --git a/src/libeinfo/einfo.h b/src/libeinfo/einfo.h new file mode 100644 index 00000000..2720e458 --- /dev/null +++ b/src/libeinfo/einfo.h @@ -0,0 +1,144 @@ +/* + * Copyright 2007 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __EINFO_H__ +#define __EINFO_H__ + +#ifdef __GNUC__ +# define __EINFO_PRINTF __attribute__ ((__format__ (__printf__, 1, 2))) +# define __EINFO_XPRINTF __attribute__ ((__noreturn__, __format__ (__printf__, 1, 2))) +# define __EEND_PRINTF __attribute__ ((__format__ (__printf__, 2, 3))) +#else +# define __EINFO_PRINTF +# define __EINFO_XPRINTF +# define __EEND_PRINTF +#endif + +#include <sys/types.h> +#include <stdbool.h> + +/* Although OpenRC requires C99, linking to us should not. */ +#ifdef restrict +# define __EINFO_RESTRICT restrict +#else +# ifdef __restrict +# define __EINFO_RESTRICT __restrict +# else +# define __EINFO_RESTRICT +# endif +#endif + +/*! @brief Color types to use */ +typedef enum +{ + ECOLOR_NORMAL = 1, + ECOLOR_GOOD = 2, + ECOLOR_WARN = 3, + ECOLOR_BAD = 4, + ECOLOR_HILITE = 5, + ECOLOR_BRACKET = 6 +} einfo_color_t; + +/*! @brief Returns the ASCII code for the color */ +const char *ecolor (einfo_color_t); + +/*! @brief Writes to syslog. */ +void elog (int __level, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; + +/*! + * @brief Display informational messages. + * + * The einfo family of functions display messages in a consistent manner + * across applications. Basically they prefix the message with + * " * ". If the terminal can handle color then we color the * based on + * the command used. Otherwise we are identical to the printf function. + * + * - einfo - green + * - ewarn - yellow + * - eerror - red + * + * The n suffix denotes that no new line should be printed. + * The v suffix means only print if EINFO_VERBOSE is yes. + */ +/*@{*/ +int einfon (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; +int ewarnn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; +int eerrorn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; +int einfo (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; +int ewarn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; +void ewarnx (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_XPRINTF; +int eerror (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; +void eerrorx (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_XPRINTF; + +int einfovn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; +int ewarnvn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; +int ebeginvn (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; +int eendvn (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; +int ewendvn (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; +int einfov (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; +int ewarnv (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; +/*@}*/ + +/*! @ingroup ebegin + * @brief Display informational messages that may take some time. + * + * Similar to einfo, but we add ... to the end of the message */ +/*@{*/ +int ebeginv (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; +int ebegin (const char * __EINFO_RESTRICT __fmt, ...) __EINFO_PRINTF; +/*@}*/ + +/*! @ingroup eend + * @brief End an ebegin. + * + * If you ebegin, you should eend also. + * eend places [ ok ] or [ !! ] at the end of the terminal line depending on + * retval (0 or ok, anything else for !!) + * + * ebracket allows you to specifiy the position, color and message */ +/*@{*/ +int eend (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; +int ewend (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; +void ebracket (int __col, einfo_color_t __color, const char * __EINFO_RESTRICT __msg); + +int eendv (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; +int ewendv (int __retval, const char * __EINFO_RESTRICT __fmt, ...) __EEND_PRINTF; +/*@}*/ + +/*! @ingroup eindent + * @brief Indents the einfo lines. + * + * For each indent you should outdent when done */ +/*@{*/ +void eindent (void); +void eoutdent (void); +void eindentv (void); +void eoutdentv (void); + +/*! @brief Prefix each einfo line with something */ +void eprefix (const char * __EINFO_RESTRICT __prefix); + +#endif diff --git a/src/libeinfo/einfo.map b/src/libeinfo/einfo.map new file mode 100644 index 00000000..428a8954 --- /dev/null +++ b/src/libeinfo/einfo.map @@ -0,0 +1,35 @@ +EINFO_1.0 { +global: + ecolor; + elog; + einfon; + ewarnn; + eerrorn; + einfo; + ewarn; + ewarnx; + eerror; + eerrorx; + einfovn; + ewarnvn; + ebeginvn; + eendvn; + ewendvn; + einfov; + ewarnv; + ebeginv; + ebegin; + eend; + ewend; + ebracket; + eendv; + ewendv; + eindent; + eoutdent; + eindentv; + eoutdentv; + eprefix; + +local: + *; +}; diff --git a/src/libeinfo/libeinfo.c b/src/libeinfo/libeinfo.c new file mode 100644 index 00000000..d80af9c0 --- /dev/null +++ b/src/libeinfo/libeinfo.c @@ -0,0 +1,1060 @@ +/* + einfo.c + Informational functions + */ + +/* + * Copyright 2007-2008 Roy Marples + * All rights reserved + + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +const char libeinfo_copyright[] = "Copyright (c) 2007-2008 Roy Marples"; + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <syslog.h> +#ifdef HAVE_TERMCAP +#include <termcap.h> +#endif +#include <unistd.h> + +#include "einfo.h" +#include "rc.h" +#include "rc-misc.h" + +#include "hidden-visibility.h" +hidden_proto(ecolor) +hidden_proto(ebegin) +hidden_proto(ebeginv) +hidden_proto(ebracket) +hidden_proto(eend) +hidden_proto(eendv) +hidden_proto(eerror) +hidden_proto(eerrorn) +hidden_proto(eerrorx) +hidden_proto(eindent) +hidden_proto(eindentv) +hidden_proto(einfo) +hidden_proto(einfon) +hidden_proto(einfov) +hidden_proto(einfovn) +hidden_proto(elog) +hidden_proto(eoutdent) +hidden_proto(eoutdentv) +hidden_proto(eprefix) +hidden_proto(ewarn) +hidden_proto(ewarnn) +hidden_proto(ewarnv) +hidden_proto(ewarnvn) +hidden_proto(ewarnx) +hidden_proto(ewend) +hidden_proto(ewendv) + + /* Incase we cannot work out how many columns from ioctl, supply a default */ +#define DEFAULT_COLS 80 + +#define OK "ok" +#define NOT_OK "!!" + +/* Number of spaces for an indent */ +#define INDENT_WIDTH 2 + +/* How wide can the indent go? */ +#define INDENT_MAX 40 + +/* Default colours */ +#define GOOD 2 +#define WARN 3 +#define BAD 1 +#define HILITE 6 +#define BRACKET 4 + +/* We fallback to these escape codes if termcap isn't available + * like say /usr isn't mounted */ +#define AF "\033[3%dm" +#define CE "\033[K" +#define CH "\033[%dC" +#define MD "\033[1m" +#define ME "\033[m" +#define UP "\033[A" + +/* A pointer to a string to prefix to einfo/ewarn/eerror messages */ +static const char *_eprefix = NULL; + +/* Buffers and structures to hold the final colours */ +static char ebuffer[100]; +struct ecolor { + einfo_color_t color; + int def; + const char *name; + char *str; +}; +static char nullstr = '\0'; + +static struct ecolor ecolors[] = { + { ECOLOR_GOOD, GOOD, "good", NULL }, + { ECOLOR_WARN, WARN, "warn", NULL }, + { ECOLOR_BAD, BAD, "bad", NULL }, + { ECOLOR_HILITE, HILITE, "hilite", NULL }, + { ECOLOR_BRACKET, BRACKET, "bracket", NULL }, + { ECOLOR_NORMAL, 0, NULL, NULL }, +}; + +static char *flush = NULL; +static char *up = NULL; +static char *goto_column = NULL; + +static const char *term = NULL; +static bool term_is_cons25 = false; + +/* Termcap buffers and pointers + * Static buffers suck hard, but some termcap implementations require them */ +#ifdef HAVE_TERMCAP +static char termcapbuf[2048]; +static char tcapbuf[512]; +#else +/* No curses support, so we hardcode a list of colour capable terms */ +static const char *const color_terms[] = { + "Eterm", + "ansi", + "color-xterm", + "con132x25", + "con132x30", + "con132x43", + "con132x60", + "con80x25", + "con80x28", + "con80x30", + "con80x43", + "con80x50", + "con80x60", + "cons25", + "console", + "cygwin", + "dtterm", + "gnome", + "konsole", + "kterm", + "linux", + "linux-c", + "mach-color", + "mlterm", + "putty", + "rxvt", + "rxvt-cygwin", + "rxvt-cygwin-native", + "rxvt-unicode", + "screen", + "screen-bce", + "screen-w", + "screen.linux", + "vt100", + "xterm", + "xterm-256color", + "xterm-color", + "xterm-debian", + NULL +}; +#endif + +/* strlcat and strlcpy are nice, shame glibc does not define them */ +#ifdef __GLIBC__ +# if ! defined (__UCLIBC__) && ! defined (__dietlibc__) +static size_t strlcat (char *dst, const char *src, size_t size) +{ + char *d = dst; + const char *s = src; + size_t src_n = size; + size_t dst_n; + + while (src_n-- != 0 && *d != '\0') + d++; + dst_n = d - dst; + src_n = size - dst_n; + + if (src_n == 0) + return (dst_n + strlen (src)); + + while (*s != '\0') { + if (src_n != 1) { + *d++ = *s; + src_n--; + } + s++; + } + *d = '\0'; + + return (dst_n + (s - src)); +} + +static size_t strlcpy (char *dst, const char *src, size_t size) +{ + const char *s = src; + size_t n = size; + + if (n && --n) + do { + if (! (*dst++ = *src++)) + break; + } while (--n); + + if (! n) { + if (size) + *dst = '\0'; + while (*src++); + } + + return (src - s - 1); +} +# endif +#endif + +static bool yesno (const char *value) +{ + if (! value) { + errno = ENOENT; + return (false); + } + + if (strcasecmp (value, "yes") == 0 || + strcasecmp (value, "y") == 0 || + strcasecmp (value, "true") == 0 || + strcasecmp (value, "on") == 0 || + strcasecmp (value, "1") == 0) + return (true); + + if (strcasecmp (value, "no") != 0 && + strcasecmp (value, "n") != 0 && + strcasecmp (value, "false") != 0 && + strcasecmp (value, "off") != 0 && + strcasecmp (value, "0") != 0) + errno = EINVAL; + + return (false); +} + +static bool noyes (const char *value) +{ + int serrno = errno; + bool retval; + + errno = 0; + retval = yesno (value); + if (errno == 0) { + retval = ! retval; + errno = serrno; + } + + return (retval); +} + +static bool is_quiet() +{ + return (yesno (getenv ("EINFO_QUIET"))); +} + +static bool is_verbose() +{ + return (yesno (getenv ("EINFO_VERBOSE"))); +} + +/* Fake tgoto call - very crapy, but works for our needs */ +#ifndef HAVE_TERMCAP +static char *tgoto (const char *cap, int a, int b) +{ + static char buf[20]; + + snprintf (buf, sizeof (buf), cap, b, a); + return (buf); +} +#endif + +static bool colour_terminal (FILE * __EINFO_RESTRICT f) +{ + static int in_colour = -1; + char *e; + int c; + const char *_af = NULL; + const char *_ce = NULL; + const char *_ch = NULL; + const char *_md = NULL; + const char *_me = NULL; + const char *_up = NULL; + char tmp[100]; + char *p; + unsigned int i = 0; + + if (f && ! isatty (fileno (f))) + return (false); + + if (noyes (getenv ("EINFO_COLOR"))) + return (false); + + if (in_colour == 0) + return (false); + if (in_colour == 1) + return (true); + + term_is_cons25 = false; + + if (! term) { + term = getenv ("TERM"); + if (! term) + return (false); + } + + if (strcmp (term, "cons25") == 0) + term_is_cons25 = true; + +#ifdef HAVE_TERMCAP + /* Check termcap to see if we can do colour or not */ + if (tgetent (termcapbuf, term) == 1) { + char *bp = tcapbuf; + + _af = tgetstr ("AF", &bp); + _ce = tgetstr ("ce", &bp); + _ch = tgetstr ("ch", &bp); + /* Our ch use also works with RI .... for now */ + if (! _ch) + _ch = tgetstr ("RI", &bp); + _md = tgetstr ("md", &bp); + _me = tgetstr ("me", &bp); + _up = tgetstr ("up", &bp); + } + + /* Cheat here as vanilla BSD has the whole termcap info in /usr + * which is not available to us when we boot */ + if (term_is_cons25) { +#else + while (color_terms[i]) { + if (strcmp (color_terms[i], term) == 0) { + in_colour = 1; + } + i++; + } + + if (in_colour != 1) { + in_colour = 0; + return (false); + } +#endif + if (! _af) + _af = AF; + if (! _ce) + _ce = CE; + if (! _ch) + _ch = CH; + if (! _md) + _md = MD; + if (! _me) + _me = ME; + if (! _up) + _up = UP; +#ifdef HAVE_TERMCAP + } + + if (! _af || ! _ce || ! _ch || ! _me || !_md || ! _up) { + in_colour = 0; + return (false); + } +#endif + +#define _GET_CAP(_d, _c) strlcpy (_d, tgoto (_c, 0, 0), sizeof (_d)); +#define _ASSIGN_CAP(_v) { \ + _v = p; \ + p += strlcpy (p, tmp, sizeof (ebuffer) - (p - ebuffer)) + 1; \ +} + + /* Now setup our colours */ + p = ebuffer; + for (i = 0; i < sizeof (ecolors) / sizeof (ecolors[0]); i++) { + tmp[0] = '\0'; + + if (ecolors[i].name) { + const char *bold = _md; + c = ecolors[i].def; + + /* See if the user wants to override the colour + * We use a :col;bold: format like 2;1: for bold green + * and 1;0: for a normal red */ + if ((e = getenv("EINFO_COLOR"))) { + char *ee = strstr (e, ecolors[i].name); + + if (ee) + ee += strlen (ecolors[i].name); + + if (ee && *ee == '=') { + + char *d = xstrdup (ee + 1); + char *end = strchr (d, ':'); + if (end) + *end = '\0'; + + c = atoi(d); + + end = strchr (d, ';'); + if (end && *++end == '0') + bold = _me; + + free (d); + } + } + strlcpy (tmp, tgoto (bold, 0, 0), sizeof (tmp)); + strlcat (tmp, tgoto (_af, 0, c & 0x07), sizeof (tmp)); + } else + _GET_CAP (tmp, _me); + + if (tmp[0]) + _ASSIGN_CAP (ecolors[i].str) + else + ecolors[i].str = &nullstr; + } + + _GET_CAP (tmp, _ce) + _ASSIGN_CAP (flush) + _GET_CAP (tmp, _up); + _ASSIGN_CAP (up); + strlcpy (tmp, _ch, sizeof (tmp)); + _ASSIGN_CAP (goto_column); + + in_colour = 1; + return (true); +} + +static int get_term_columns (FILE * __EINFO_RESTRICT stream) +{ + struct winsize ws; + char *env = getenv ("COLUMNS"); + char *p; + int i; + + if (env) { + i = strtol (env, &p, 10); + if (! *p) + return (i); + } + + if (ioctl (fileno (stream), TIOCGWINSZ, &ws) == 0) + return (ws.ws_col); + + return (DEFAULT_COLS); +} + +void eprefix (const char *__EINFO_RESTRICT prefix) +{ + _eprefix = prefix; +} +hidden_def(eprefix) + +static void elogv (int level, const char *__EINFO_RESTRICT fmt, va_list ap) +{ + char *e = getenv ("EINFO_LOG"); + va_list apc; + + if (fmt && e) { + closelog (); + openlog (e, LOG_PID, LOG_DAEMON); + va_copy (apc, ap); + vsyslog (level, fmt, apc); + va_end (apc); + closelog (); + } +} + +void elog (int level, const char *__EINFO_RESTRICT fmt, ...) +{ + va_list ap; + + va_start (ap, fmt); + elogv (level, fmt, ap); + va_end (ap); +} +hidden_def(elog) + +static int _eindent (FILE * __EINFO_RESTRICT stream) +{ + char *env = getenv ("EINFO_INDENT"); + int amount = 0; + char indent[INDENT_MAX]; + + if (env) { + errno = 0; + amount = strtol (env, NULL, 0); + if (errno != 0 || amount < 0) + amount = 0; + else if (amount > INDENT_MAX) + amount = INDENT_MAX; + + if (amount > 0) + memset (indent, ' ', amount); + } + + /* Terminate it */ + memset (indent + amount, 0, 1); + return (fprintf (stream, "%s", indent)); +} + +static const char *_ecolor (FILE * __EINFO_RESTRICT f, einfo_color_t color) +{ + unsigned int i; + + if (! colour_terminal (f)) + return (""); + + for (i = 0; i < sizeof (ecolors) / sizeof (ecolors[0]); i++) { + if (ecolors[i].color == color) + return (ecolors[i].str); + } + + return (""); +} +hidden_def(ecolor) + +const char *ecolor (einfo_color_t color) +{ + FILE *f = stdout; + + /* Try and guess a valid tty */ + if (! isatty (fileno (f))) { + f = stderr; + if (! isatty (fileno (f))) { + f = stdin; + if (! isatty (fileno (f))) + f = NULL; + } + } + + return (_ecolor (f, color)); +} + +#define LASTCMD(_cmd) \ + unsetenv ("EINFO_LASTCMD"); \ + setenv ("EINFO_LASTCMD", _cmd, 1); + +#define EINFOVN(_file, _color) \ +{ \ + char *_e = getenv ("EINFO_LASTCMD"); \ + if (_e && ! colour_terminal (_file) && strcmp (_e, "ewarn") != 0 && \ + _e[strlen (_e) - 1] == 'n') \ + fprintf (_file, "\n"); \ + if (_eprefix) \ + fprintf (_file, "%s%s%s|", _ecolor (_file, _color), _eprefix, _ecolor (_file, ECOLOR_NORMAL)); \ + fprintf (_file, " %s*%s ", _ecolor (_file, _color), _ecolor (_file, ECOLOR_NORMAL)); \ + retval += _eindent (_file); \ +{ \ + va_list _ap; \ + va_copy (_ap, ap); \ + retval += vfprintf (_file, fmt, _ap) + 3; \ + va_end (_ap); \ +} \ + if (colour_terminal (_file)) \ + fprintf (_file, "%s", flush); \ +} + +static int _einfovn (const char *__EINFO_RESTRICT fmt, va_list ap) +{ + int retval = 0; + + EINFOVN (stdout, ECOLOR_GOOD); + return (retval); +} + +static int _ewarnvn (const char *__EINFO_RESTRICT fmt, va_list ap) +{ + int retval = 0; + + EINFOVN (stdout, ECOLOR_WARN); + return (retval); +} + +static int _eerrorvn (const char *__EINFO_RESTRICT fmt, va_list ap) +{ + int retval = 0; + + EINFOVN (stderr, ECOLOR_BAD); + return (retval); +} + +int einfon (const char *__EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (! fmt || is_quiet ()) + return (0); + + va_start (ap, fmt); + retval = _einfovn (fmt, ap); + va_end (ap); + + LASTCMD ("einfon"); + + return (retval); +} +hidden_def(einfon) + +int ewarnn (const char *__EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (! fmt || is_quiet ()) + return (0); + + va_start (ap, fmt); + retval = _ewarnvn (fmt, ap); + va_end (ap); + + LASTCMD ("ewarnn"); + + return (retval); +} +hidden_def(ewarnn) + +int eerrorn (const char *__EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + va_start (ap, fmt); + retval = _eerrorvn (fmt, ap); + va_end (ap); + + LASTCMD ("errorn"); + + return (retval); +} +hidden_def(eerrorn) + +int einfo (const char *__EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (! fmt || is_quiet()) + return (0); + + va_start (ap, fmt); + retval = _einfovn (fmt, ap); + retval += printf ("\n"); + va_end (ap); + + LASTCMD ("einfo"); + + return (retval); +} +hidden_def(einfo) + +int ewarn (const char *__EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (! fmt || is_quiet ()) + return (0); + + va_start (ap, fmt); + elogv (LOG_WARNING, fmt, ap); + retval = _ewarnvn (fmt, ap); + retval += printf ("\n"); + va_end (ap); + + LASTCMD ("ewarn"); + + return (retval); +} +hidden_def(ewarn) + +void ewarnx (const char *__EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (fmt && ! is_quiet ()) { + va_start (ap, fmt); + elogv (LOG_WARNING, fmt, ap); + retval = _ewarnvn (fmt, ap); + va_end (ap); + retval += printf ("\n"); + } + exit (EXIT_FAILURE); +} +hidden_def(ewarnx) + +int eerror (const char *__EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (! fmt) + return (0); + + va_start (ap, fmt); + elogv (LOG_ERR, fmt, ap); + retval = _eerrorvn (fmt, ap); + va_end (ap); + retval += fprintf (stderr, "\n"); + + LASTCMD ("eerror"); + + return (retval); +} +hidden_def(eerror) + +void eerrorx (const char *__EINFO_RESTRICT fmt, ...) +{ + va_list ap; + + if (fmt) { + va_start (ap, fmt); + elogv (LOG_ERR, fmt, ap); + _eerrorvn (fmt, ap); + va_end (ap); + fprintf (stderr, "\n"); + } + + exit (EXIT_FAILURE); +} +hidden_def(eerrorx) + +int ebegin (const char *__EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (! fmt || is_quiet ()) + return (0); + + va_start (ap, fmt); + retval = _einfovn (fmt, ap); + va_end (ap); + retval += printf (" ..."); + if (colour_terminal (stdout)) + retval += printf ("\n"); + + LASTCMD ("ebegin"); + + return (retval); +} +hidden_def(ebegin) + +static void _eend (FILE * __EINFO_RESTRICT fp, int col, einfo_color_t color, + const char *msg) +{ + int i; + int cols; + + if (! msg) + return; + + cols = get_term_columns (fp) - (strlen (msg) + 3); + + /* cons25 is special - we need to remove one char, otherwise things + * do not align properly at all. */ + if (! term) { + term = getenv ("TERM"); + if (term && strcmp (term, "cons25") == 0) + term_is_cons25 = true; + else + term_is_cons25 = false; + } + if (term_is_cons25) + cols--; + + if (cols > 0 && colour_terminal (fp)) { + fprintf (fp, "%s%s %s[%s%s%s]%s\n", up, tgoto (goto_column, 0, cols), + ecolor (ECOLOR_BRACKET), ecolor (color), msg, + ecolor (ECOLOR_BRACKET), ecolor (ECOLOR_NORMAL)); + } else { + if (col > 0) + for (i = 0; i < cols - col; i++) + fprintf (fp, " "); + fprintf (fp, " [%s]\n", msg); + } +} + +static int _do_eend (const char *cmd, int retval, const char *__EINFO_RESTRICT fmt, va_list ap) +{ + int col = 0; + FILE *fp = stdout; + va_list apc; + + if (fmt && retval != 0) { + va_copy (apc, ap); + if (strcmp (cmd, "ewend") == 0) { + col = _ewarnvn (fmt, apc); + fp = stdout; + } else { + col = _eerrorvn (fmt, apc); + fp = stderr; + } + col += fprintf (fp, "\n"); + va_end (apc); + } + + _eend (fp, col, + retval == 0 ? ECOLOR_GOOD : ECOLOR_BAD, + retval == 0 ? OK : NOT_OK); + return (retval); +} + +int eend (int retval, const char *__EINFO_RESTRICT fmt, ...) +{ + va_list ap; + + if (is_quiet ()) + return (retval); + + va_start (ap, fmt); + _do_eend ("eend", retval, fmt, ap); + va_end (ap); + + LASTCMD ("eend"); + + return (retval); +} +hidden_def(eend) + +int ewend (int retval, const char *__EINFO_RESTRICT fmt, ...) +{ + va_list ap; + + if (is_quiet ()) + return (retval); + + va_start (ap, fmt); + _do_eend ("ewend", retval, fmt, ap); + va_end (ap); + + LASTCMD ("ewend"); + + return (retval); +} +hidden_def(ewend) + +void ebracket (int col, einfo_color_t color, const char *msg) +{ + _eend (stdout, col, color, msg); +} +hidden_def(ebracket) + +void eindent (void) +{ + char *env = getenv ("EINFO_INDENT"); + int amount = 0; + char num[10]; + + if (env) { + errno = 0; + amount = strtol (env, NULL, 0); + if (errno != 0) + amount = 0; + } + + amount += INDENT_WIDTH; + if (amount > INDENT_MAX) + amount = INDENT_MAX; + + snprintf (num, 10, "%08d", amount); + setenv ("EINFO_INDENT", num, 1); +} +hidden_def(eindent) + +void eoutdent (void) +{ + char *env = getenv ("EINFO_INDENT"); + int amount = 0; + char num[10]; + + if (! env) + return; + + errno = 0; + amount = strtol (env, NULL, 0); + if (errno != 0) + amount = 0; + else + amount -= INDENT_WIDTH; + + if (amount <= 0) + unsetenv ("EINFO_EINDENT"); + else { + snprintf (num, 10, "%08d", amount); + setenv ("EINFO_EINDENT", num, 1); + } +} +hidden_def(eoutdent) + +int einfovn (const char *__EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (! fmt || ! is_verbose ()) + return (0); + + va_start (ap, fmt); + retval = _einfovn (fmt, ap); + va_end (ap); + + LASTCMD ("einfovn"); + + return (retval); +} +hidden_def(einfovn) + +int ewarnvn (const char *__EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (! fmt || ! is_verbose ()) + return (0); + + va_start (ap, fmt); + retval = _ewarnvn (fmt, ap); + va_end (ap); + + LASTCMD ("ewarnvn"); + + return (retval); +} +hidden_def(ewarnvn) + +int einfov (const char *__EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (! fmt || ! is_verbose ()) + return (0); + + va_start (ap, fmt); + retval = _einfovn (fmt, ap); + retval += printf ("\n"); + va_end (ap); + + LASTCMD ("einfov"); + + return (retval); +} +hidden_def(einfov) + +int ewarnv (const char *__EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (! fmt || ! is_verbose ()) + return (0); + + va_start (ap, fmt); + retval = _ewarnvn (fmt, ap); + retval += printf ("\n"); + va_end (ap); + + LASTCMD ("ewarnv"); + + return (retval); +} +hidden_def(ewarnv) + +int ebeginv (const char *__EINFO_RESTRICT fmt, ...) +{ + int retval; + va_list ap; + + if (! fmt || ! is_verbose ()) + return (0); + + va_start (ap, fmt); + retval = _einfovn (fmt, ap); + retval += printf (" ..."); + if (colour_terminal (stdout)) + retval += printf ("\n"); + va_end (ap); + + LASTCMD ("ebeginv"); + + return (retval); +} +hidden_def(ebeginv) + +int eendv (int retval, const char *__EINFO_RESTRICT fmt, ...) +{ + va_list ap; + + if (! is_verbose ()) + return (0); + + va_start (ap, fmt); + _do_eend ("eendv", retval, fmt, ap); + va_end (ap); + + LASTCMD ("eendv"); + + return (retval); +} +hidden_def(eendv) + +int ewendv (int retval, const char *__EINFO_RESTRICT fmt, ...) +{ + va_list ap; + + if (! is_verbose ()) + return (0); + + va_start (ap, fmt); + _do_eend ("ewendv", retval, fmt, ap); + va_end (ap); + + LASTCMD ("ewendv"); + + return (retval); +} +hidden_def(ewendv) + +void eindentv (void) +{ + if (is_verbose ()) + eindent (); +} +hidden_def(eindentv) + +void eoutdentv (void) +{ + if (is_verbose ()) + eoutdent (); +} +hidden_def(eoutdentv) |