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