#define STR(x) STR_HELPER(x) #define STR_HELPER(x) #x #define BEGIN do { #define END } while(0) #ifdef NDEBUG #define DEBUG(FORMAT, ...) #define LOG_PREFIX #define LOG_PREFIX_ARGS #else #define DEBUG(FORMAT, ...) WARN(FORMAT, __VA_ARGS__) #define LOG_PREFIX __FILE__ ":%s:" STR(__LINE__) ": " #define LOG_PREFIX_ARGS , __func__ #endif // void warn(const char *format, ...) // { // va_list ap; // va_start(ap, format); // vfprintf(stderr, format, ap); // putc('\n', stderr); // // #ifdef __MINGW32__ // // fflush(stderr); // // #endif // va_end(ap); // } void warn(const char *format, ...) { size_t l = strlen(format); char format2[l+2]; va_list ap; strcpy(format, format2); format[l] = '\n'; format[l+1] = '\0'; va_start(ap, format); vfprintf(stderr, format2, ap); // #ifdef __MINGW32__ // fflush(stderr); // #endif va_end(ap); } // void warn(const char *format, ...) // { // int l = strlen(format); // char format2[l+2]; // va_list ap; // snprintf(format2, l+2, "%s\n", format); // va_start(ap, format); // vfprintf(stderr, format2, ap); // // #ifdef __MINGW32__ // // fflush(stderr); // // #endif // va_end(ap); // } // // enum log_level { // DEBUG_LEVEL_ERROR, // DEBUG_LEVEL_WARN, // DEBUG_LEVEL_INFO // }; // // char *log_level_str[] = { // "[ERROR]", // "[WARN] ", // "[INFO] " // }; // // void debug(enum log_level level, const char *file, int line, const char *func, const char *syserr, const char *format, ...) // { // char format2[MAX_LINE]; // va_list ap; // snprintf(format2, MAX_LINE, "%%s %%s:%%d %%s: %s%%s%%s\n", format); // format[l] = '\n'; // format[l+1] = '\0'; // va_start(ap, format); // vfprintf(stderr, format2, ap); // // #ifdef __MINGW32__ // // fflush(stderr); // // #endif // va_end(ap); // } void error_exit(const char *format, ...) { va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); if (errno) perror(" "); else putc('\n', stderr); va_end(ap); exit(1); } void error_abort(const char *format, ...) { va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); if (errno) perror(" "); else putc('\n', stderr); va_end(ap); abort(); } #define LOG(FUNC, FORMAT, ...) FUNC(LOG_PREFIX FORMAT LOG_PREFIX_ARGS, ##__VA_ARGS__) #define WARN(...) LOG(warn, __VA_ARGS__) #define ERROR_EXIT(...) LOG(error_exit, __VA_ARGS__) #define ERROR_ABORT(...) LOG(error_abort, __VA_ARGS__) #define ERROR_GOTO(...) BEGIN WARN(__VA_ARGS__); goto error; END #define IS_NONZERO(X) (X) #define IS_NULL(X) ((X) == NULL) #define IS_NEGATIVE(X) ((X)<0) #define SAFE(FUNC, TEST, ...) { \ typeof(FUNC(__VA_ARGS__)) status = FUNC(__VA_ARGS__); \ if (TEST(status)) { \ ERROR(#FUNC " failed"); \ } \ return status; \ } void *Malloc(size_t size) SAFE(malloc, IS_NULL, size); void *Realloc(void *ptr, size_t size) SAFE(realloc, IS_NULL, ptr, size); FILE *Fopen(const char *path, const char *mode) SAFE(fopen, IS_NULL, path, mode); int Fclose(FILE *fp) SAFE(fclose, IS_NONZERO, fp); #define CHECK(VAR, TEST, FUNC, ...) BEGIN \ VAR = FUNC(__VA_ARGS__); \ if (TEST(VAR)) { \ ERROR(#FUNC " failed"); \ } \ END #define CHECK_VOID(TEST, FUNC, ...) BEGIN \ typeof(FUNC(__VA_ARGS__)) status; \ CHECK(status, TEST, FUNC, __VA_ARGS__); \ END #define MALLOC(VAR, SIZE) CHECK(VAR, IS_NULL, malloc, SIZE) #define REALLOC(VAR, SIZE) BEGIN typeof(VAR) VAR2; CHECK(VAR2, IS_NULL, realloc, VAR, SIZE); VAR = VAR2; END #define FREE(VAR) BEGIN free(VAR); VAR = NULL; END #define FOPEN(VAR, PATH, MODE) CHECK(VAR, IS_NULL, fopen, PATH, MODE) #define FCLOSE(FP) CHECK_VOID(IS_NONZERO, fclose, FP) /* #define FAILED(FUNCNAME, FORMAT, ...) #define NONE #define FIRST(...) FIRST_HELPER(__VA_ARGS__, throwaway) #define FIRST_HELPER(first, ...) first #define SECOND(...) SECOND_HELPER(__VA_ARGS__, throwaway) #define SECOND_HELPER(first, second, ...) second #define REST(...) REST_HELPER(NUM(__VA_ARGS__), __VA_ARGS__) #define REST_HELPER(qty, ...) REST_HELPER2(qty, __VA_ARGS__) #define REST_HELPER2(qty, ...) REST_HELPER_##qty(__VA_ARGS__) #define REST_HELPER_ONE(first) #define REST_HELPER_TWOORMORE(first, ...) , __VA_ARGS__ #define NUM(...) SELECT_10TH(__VA_ARGS__, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, TWOORMORE, ONE, throwaway) #define SELECT_10TH(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, ...) a10 #define X(A,B) A #define MAP_FIRST(...) __VA_ARGS__ #undef X #define CHECKER(WRAPPER, FUNCTION, ERROR_TEST, RETURNS, ARGS, PARAMS...) \ RETURNS WRAPPER(MAP_FIRST(__VA_ARGS__)) \ { \ RETURNS rv; \ errno = 0; \ rv = FUNCTION(__VA_ARGS__); \ if (!rv) \ failed(#FUNCTION); \ return rv; \ } CHECKER(Malloc, malloc, IS_NULL, void *, X(size_t,size)) CHECKER(Realloc, realloc, IS_NULL, void *, void *ptr, X(size_t,size)) */