1 /********************************************************************** 2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold 3 This program is free software; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License as published by 5 the Free Software Foundation; either version 2, or (at your option) 6 any later version. 7 8 This program is distributed in the hope that it will be useful, 9 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 GNU General Public License for more details. 12 ***********************************************************************/ 13 #ifndef FC__LOG_H 14 #define FC__LOG_H 15 16 #ifdef __cplusplus 17 extern "C" { 18 #endif /* __cplusplus */ 19 20 #include <stdarg.h> 21 #include <stdlib.h> 22 23 #include "support.h" /* bool type and fc__attribute */ 24 25 enum log_level { 26 LOG_FATAL = 0, 27 LOG_ERROR, /* non-fatal errors */ 28 LOG_NORMAL, 29 LOG_VERBOSE, /* not shown by default */ 30 LOG_DEBUG /* suppressed unless DEBUG defined */ 31 }; 32 33 /* If one wants to compare autogames with lots of code changes, the line 34 * numbers can cause a lot of noise. In that case set this to a fixed 35 * value. */ 36 #define __FC_LINE__ __LINE__ 37 38 /* Dummy log message. */ 39 extern const char *nologmsg; 40 #define NOLOGMSG nologmsg 41 42 /* Preparation of the log message, i.e. add a backtrace. */ 43 typedef void (*log_pre_callback_fn)(enum log_level, bool print_from_where, 44 const char *where, const char *msg); 45 46 /* A function type to enable custom output of log messages other than 47 * via fputs(stderr). Eg, to the server console while handling prompts, 48 * rfcstyle, client notifications; Eg, to the client window output window? 49 */ 50 typedef void (*log_callback_fn)(enum log_level, const char *, bool file_too); 51 52 /* A function type to generate a custom prefix for the log messages, e.g. 53 * add the turn and/or time of the log message. */ 54 typedef const char *(*log_prefix_fn)(void); 55 56 void log_init(const char *filename, enum log_level initial_level, 57 log_callback_fn callback, log_prefix_fn prefix, 58 int fatal_assertions); 59 void log_close(void); 60 bool log_parse_level_str(const char *level_str, enum log_level *ret_level); 61 62 log_pre_callback_fn log_set_pre_callback(log_pre_callback_fn precallback); 63 log_callback_fn log_set_callback(log_callback_fn callback); 64 log_prefix_fn log_set_prefix(log_prefix_fn prefix); 65 void log_set_level(enum log_level level); 66 enum log_level log_get_level(void); 67 #ifdef FREECIV_DEBUG 68 bool log_do_output_for_level_at_location(enum log_level level, 69 const char *file, int line); 70 #endif 71 72 void vdo_log(const char *file, const char *function, int line, 73 bool print_from_where, enum log_level level, 74 char *buf, int buflen, const char *message, va_list args); 75 void do_log(const char *file, const char *function, int line, 76 bool print_from_where, enum log_level level, 77 const char *message, ...) 78 fc__attribute((__format__ (__printf__, 6, 7))); 79 80 #ifdef FREECIV_DEBUG 81 #define log_do_output_for_level(level) \ 82 log_do_output_for_level_at_location(level, __FILE__, __FC_LINE__) 83 #else 84 #define log_do_output_for_level(level) (log_get_level() >= level) 85 #endif /* FREECIV_DEBUG */ 86 87 88 /* The log macros */ 89 #define log_base(level, message, ...) \ 90 if (log_do_output_for_level(level)) { \ 91 do_log(__FILE__, __FUNCTION__, __FC_LINE__, FALSE, \ 92 level, message, ## __VA_ARGS__); \ 93 } 94 /* This one doesn't need check, fatal messages are always displayed. */ 95 #define log_fatal(message, ...) \ 96 do_log(__FILE__, __FUNCTION__, __FC_LINE__, FALSE, \ 97 LOG_FATAL, message, ## __VA_ARGS__); 98 #define log_error(message, ...) \ 99 log_base(LOG_ERROR, message, ## __VA_ARGS__) 100 #define log_normal(message, ...) \ 101 log_base(LOG_NORMAL, message, ## __VA_ARGS__) 102 #define log_verbose(message, ...) \ 103 log_base(LOG_VERBOSE, message, ## __VA_ARGS__) 104 #ifdef FREECIV_DEBUG 105 # define log_debug(message, ...) \ 106 log_base(LOG_DEBUG, message, ## __VA_ARGS__) 107 #else 108 # define log_debug(message, ...) /* Do nothing. */ 109 #endif /* FREECIV_DEBUG */ 110 #ifdef FREECIV_TESTMATIC 111 #define log_testmatic(message, ...) \ 112 log_base(LOG_ERROR, message, ## __VA_ARGS__) 113 #define log_testmatic_alt(altlvl, message, ...) \ 114 log_base(LOG_ERROR, message, ## __VA_ARGS__) 115 #else /* FREECIV_TESTMATIC */ 116 #define log_testmatic(message, ...) /* Do nothing. */ 117 #define log_testmatic_alt(altlvl, message, ...) \ 118 log_base(altlvl, message, ## __VA_ARGS__) 119 #endif /* FREECIV_TESTMATIC */ 120 121 #define log_va_list(level, msg, args) \ 122 if (log_do_output_for_level(level)) { \ 123 char __buf_[1024]; \ 124 vdo_log(__FILE__, __FUNCTION__, __FC_LINE__, FALSE, \ 125 level, __buf_, sizeof(__buf_), msg, args); \ 126 } 127 128 /* Used by game debug command */ 129 #define log_test log_normal 130 #define log_packet log_verbose 131 #define log_packet_detailed log_debug 132 #define LOG_TEST LOG_NORMAL /* needed by citylog_*() functions */ 133 134 135 /* Assertions. */ 136 void fc_assert_set_fatal(int fatal_assertions); 137 #ifdef FREECIV_NDEBUG 138 /* Disable the assertion failures, but not the tests! */ 139 #define fc_assert_fail(...) (void) 0 140 #else 141 void fc_assert_fail(const char *file, const char *function, int line, 142 const char *assertion, const char *message, ...) 143 fc__attribute((__format__ (__printf__, 5, 6))); 144 #endif /* FREECIV_NDEBUG */ 145 146 #define fc_assert_full(file, function, line, \ 147 condition, action, message, ...) \ 148 if (!(condition)) { \ 149 fc_assert_fail(file, function, line, #condition, \ 150 message, ## __VA_ARGS__); \ 151 action; \ 152 } \ 153 (void) 0 /* Force the usage of ';' at the end of the call. */ 154 155 #ifdef FREECIV_NDEBUG 156 /* Disabled. */ 157 #define fc_assert(...) (void) 0 158 #define fc_assert_msg(...) (void) 0 159 #else 160 /* Like assert(). */ 161 #define fc_assert(condition) \ 162 ((condition) ? (void) 0 \ 163 : fc_assert_fail(__FILE__, __FUNCTION__, __FC_LINE__, #condition, \ 164 NOLOGMSG, NOLOGMSG)) 165 /* Like assert() with extra message. */ 166 #define fc_assert_msg(condition, message, ...) \ 167 ((condition) ? (void) 0 \ 168 : fc_assert_fail(__FILE__, __FUNCTION__, __FC_LINE__, \ 169 #condition, message, ## __VA_ARGS__)) 170 #endif /* FREECIV_NDEBUG */ 171 172 /* Do action on failure. */ 173 #define fc_assert_action(condition, action) \ 174 fc_assert_full(__FILE__, __FUNCTION__, __FC_LINE__, condition, action, \ 175 NOLOGMSG, NOLOGMSG) 176 /* Return on failure. */ 177 #define fc_assert_ret(condition) \ 178 fc_assert_action(condition, return) 179 /* Return a value on failure. */ 180 #define fc_assert_ret_val(condition, val) \ 181 fc_assert_action(condition, return val) 182 /* Exit on failure. */ 183 #define fc_assert_exit(condition) \ 184 fc_assert_action(condition, exit(EXIT_FAILURE)) 185 186 /* Do action on failure with extra message. */ 187 #define fc_assert_action_msg(condition, action, message, ...) \ 188 fc_assert_full(__FILE__, __FUNCTION__, __FC_LINE__, condition, action, \ 189 message, ## __VA_ARGS__) 190 /* Return on failure with extra message. */ 191 #define fc_assert_ret_msg(condition, message, ...) \ 192 fc_assert_action_msg(condition, return, message, ## __VA_ARGS__) 193 /* Return a value on failure with extra message. */ 194 #define fc_assert_ret_val_msg(condition, val, message, ...) \ 195 fc_assert_action_msg(condition, return val, message, ## __VA_ARGS__) 196 /* Exit on failure with extra message. */ 197 #define fc_assert_exit_msg(condition, message, ...) \ 198 fc_assert_action(condition, \ 199 log_fatal(message, ## __VA_ARGS__); exit(EXIT_FAILURE)) 200 201 #ifdef __cplusplus 202 #ifdef FREECIV_CXX11_STATIC_ASSERT 203 #define FC_STATIC_ASSERT(cond, tag) static_assert(cond, #tag) 204 #endif /* FREECIV_CXX11_STATIC_ASSERT */ 205 #else /* __cplusplus */ 206 #ifdef FREECIV_C11_STATIC_ASSERT 207 #define FC_STATIC_ASSERT(cond, tag) _Static_assert(cond, #tag) 208 #endif /* FREECIV_C11_STATIC_ASSERT */ 209 #endif /* __cplusplus */ 210 211 #ifndef FC_STATIC_ASSERT 212 /* Static (compile-time) assertion. 213 * "tag" is a semi-meaningful C identifier which will appear in the 214 * compiler error message if the assertion fails. */ 215 #define FC_STATIC_ASSERT(cond, tag) \ 216 enum { static_assert_ ## tag = 1 / (!!(cond)) } 217 #endif 218 219 #ifdef __cplusplus 220 } 221 #endif /* __cplusplus */ 222 223 #endif /* FC__LOG_H */ 224