Skip to content

Instantly share code, notes, and snippets.

@ingramj
Created July 23, 2011 03:26
Show Gist options
  • Save ingramj/1100946 to your computer and use it in GitHub Desktop.
Save ingramj/1100946 to your computer and use it in GitHub Desktop.
Error reporting functions and macros. Includes goodies like color-coding and time stamps. Originally based on eprintf() from Kernighan and Pike's "The Practice of Programming".
#include "error.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <time.h>
const char *progname = NULL;
#ifdef DEBUG
static msglev_t display_level = INFO;
#else
static msglev_t display_level = WARNING;
#endif
/* ANSI color codes */
#define C_RED "\x1b[31m"
#define C_GREEN "\x1b[32m"
#define C_YELLOW "\x1b[33m"
#define C_BLUE "\x1b[34m"
#define C_MAGENTA "\x1b[35m"
#define C_CYAN "\x1b[36m"
#define C_RESET "\x1b[0m"
void set_msglevel(msglev_t lev)
{
display_level = lev;
}
void eprintf(msglev_t lev, int status, char const * const func,
char const * const fmt, ...)
{
if (lev > display_level) return;
struct tm local;
time_t t = time(NULL);
localtime_r(&t, &local); // We assume this works.
int olderr = errno;
(void) fflush(stdout);
char buf[1024];
size_t count = 0;
if (isatty(fileno(stderr))) {
char *name_color;
switch (lev) {
case ERROR:
name_color = C_RED;
break;
case WARNING:
name_color = C_YELLOW;
break;
case INFO:
name_color = C_GREEN;
}
count = strftime(buf, sizeof(buf), C_BLUE "%d %b %T ", &local);
if (progname != NULL) {
count += snprintf(buf + count, sizeof(buf) - count,
"%s%s: " C_CYAN "%s: " C_RESET,
name_color, progname, func);
} else {
count += snprintf(buf + count, sizeof(buf) - count,
"%s(%d): " C_CYAN "%s: " C_RESET,
name_color, getpid(), func);
}
} else {
count = strftime(buf, sizeof(buf), "%d %b %T ", &local);
if (progname != NULL) {
count += snprintf(buf + count, sizeof(buf) - count, "%s: %s: ",
progname, func);
} else {
count += snprintf(buf, sizeof(buf), "(%d): %s: ", getpid(), func);
}
}
va_list arg_list;
va_start(arg_list, fmt);
count += vsnprintf(buf+count, sizeof(buf) - count, fmt, arg_list);
va_end(arg_list);
if (fmt[0] != '\0' && fmt[strlen(fmt) - 1] == ':') {
count += snprintf(buf+count, sizeof(buf) - count, " %s", strerror(status));
}
snprintf(buf+count, sizeof(buf) - count, "\n");
fprintf(stderr, "%s", buf);
errno = olderr;
}
#ifndef _ERROR_H
#define _ERROR_H
/* Error reporting macros and functions, and wrappers for standard functions. */
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
/* This should be set to an appropriate value, such as argv[0]. If it is set,
then eprintf() will use it as a prefix for all messages. */
extern const char *progname;
/* Error messages have different "levels": ERROR, WARNING, and INFO. The program
has a level, and messages above that level are suppressed. ERROR messages are
always displayed (and always cause the program to exit). The default display
level is WARNING, or INFO if DEBUG is defined.
*/
typedef enum {
ERROR, // Fatal errors
WARNING, // Non-fatal errors
INFO // Informational messages
} msglev_t;
/* Set the message level at runtime. */
void set_msglevel(msglev_t lev);
/* Display an error message, and exit. */
#define error(...) do { \
eprintf(ERROR, errno, __func__, __VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0)
#define error_s(status, ...) do { \
eprintf(ERROR, status, __func__, __VA_ARGS__); \
exit(EXIT_FAILURE); \
} while (0)
/* Display a warning message. */
#define warn(...) eprintf(WARNING, errno, __func__, __VA_ARGS__);
#define warn_s(status, ...) eprintf(WARNING, status, __func__, __VA_ARGS__);
/* Display an informative message. */
#define info(...) eprintf(INFO, errno, __func__, __VA_ARGS__);
#define info_s(status, ...) eprintf(INFO, status, __func__, __VA_ARGS__);
/* Print a message if lev is less that or equal to the current display level.
The format string and extra arguments are like printf(). If fmt ends with a
':', then the result of strerr(status) is appended.
*/
void eprintf(msglev_t lev, int status, char const * const func,
char const * const fmt, ...);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment