// TODO: Document that `perror(3)` is standard but does not take a printf-style // format argument. The ones that do are nonstandard, `err(3)` (BSD), `error` // (GNU). #include <stdlib.h> #include <stdio.h> #include <stdarg.h> #include <errno.h> #define REPORT_INFO 0 #define REPORT_ERROR 1 #define REPORT_FATAL 2 #ifndef REPORT_STREAM_INFO #define REPORT_STREAM_INFO stderr #endif #ifndef REPORT_STREAM_ERROR #define REPORT_STREAM_ERROR stderr #endif #ifndef REPORT_STREAM_FATAL #define REPORT_STREAM_FATAL stderr #endif #ifndef REPORT_PREFIX_INFO #define REPORT_PREFIX_INFO "Info: " #endif #ifndef REPORT_PREFIX_ERROR #define REPORT_PREFIX_ERROR "Error: " #endif #ifndef REPORT_PREFIX_FATAL #define REPORT_PREFIX_FATAL "Fatal: " #endif #define report_info( ...) report(REPORT_STREAM_INFO, REPORT_PREFIX_INFO, 0, __VA_ARGS__) #define report_error(...) report(REPORT_STREAM_ERROR, REPORT_PREFIX_ERROR, 0, __VA_ARGS__) #define report_fatal(...) report(REPORT_STREAM_FATAL, REPORT_PREFIX_FATAL, 1, __VA_ARGS__) static int report( FILE * stream, char const * prefix, int fatal, int report_errno, char const * format, ... ) { fprintf(stream, "%s", prefix); { va_list ap; va_start(ap, format); vfprintf(stream, format, ap); va_end(ap); } if (report_errno) fprintf(stream, ": %s", strerror(report_errno)); fprintf(stream, "\n"); if (fatal) exit(EXIT_FAILURE); return EXIT_FAILURE; }