// 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 #define report_info( ...) report(REPORT_INFO, __VA_ARGS__) #define report_error(...) report(REPORT_ERROR, __VA_ARGS__) #define report_fatal(...) report(REPORT_FATAL, __VA_ARGS__) #ifndef REPORT_STREAM_INFO #define REPORT_STREAM_INFO stderr #endif #ifndef REPORT_STREAM_ERROR #define REPORT_STREAM_ERROR stderr #endif #ifndef REPORT_FORMAT_PREFIX_INFO #define REPORT_FORMAT_PREFIX_INFO "Info: " #endif #ifndef REPORT_FORMAT_PREFIX_ERROR #define REPORT_FORMAT_PREFIX_ERROR "Error: " #endif #ifndef REPORT_FORMAT_PREFIX_FATAL #define REPORT_FORMAT_PREFIX_FATAL "Fatal: " #endif static int report(int report, int report_errno, char const * format, ...) { FILE * stream = REPORT_STREAM_INFO; if (report >= REPORT_ERROR) stream = REPORT_STREAM_ERROR; fprintf(stream, "%s", report == REPORT_INFO ? REPORT_FORMAT_PREFIX_INFO : report == REPORT_ERROR ? REPORT_FORMAT_PREFIX_ERROR : report == REPORT_FATAL ? REPORT_FORMAT_PREFIX_FATAL : "" ); { 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 (report >= REPORT_FATAL) exit(EXIT_FAILURE); return report; }