Created
July 23, 2011 03:26
-
-
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".
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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