summaryrefslogtreecommitdiffstats
path: root/src/3rdparty/freetype/include/dlg/dlg.h
blob: fa10730e83a173eecae015068473376c15c821ba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
// Copyright (c) 2019 nyorain
// Distributed under the Boost Software License, Version 1.0.
// See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt

#ifndef INC_DLG_DLG_H_
#define INC_DLG_DLG_H_

#include <stdbool.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>

// Hosted at https://github.com/nyorain/dlg.
// There are examples and documentation.
// Issue reports and contributions appreciated.

// - CONFIG -
// Define this macro to make all dlg macros have no effect at all
// #define DLG_DISABLE

// the log/assertion levels below which logs/assertions are ignored
// defaulted depending on the NDEBUG macro
#ifndef DLG_LOG_LEVEL
	#ifdef NDEBUG
		#define DLG_LOG_LEVEL dlg_level_warn
	#else
		#define DLG_LOG_LEVEL dlg_level_trace
	#endif
#endif

#ifndef DLG_ASSERT_LEVEL
	#ifdef NDEBUG
		#define DLG_ASSERT_LEVEL dlg_level_warn
	#else
		#define DLG_ASSERT_LEVEL dlg_level_trace
	#endif
#endif

// the assert level of dlg_assert
#ifndef DLG_DEFAULT_ASSERT
	#define DLG_DEFAULT_ASSERT dlg_level_error
#endif

// evaluated to the 'file' member in dlg_origin
#ifndef DLG_FILE
	#define DLG_FILE dlg__strip_root_path(__FILE__, DLG_BASE_PATH)

	// the base path stripped from __FILE__. If you don't override DLG_FILE set this to
	// the project root to make 'main.c' from '/some/bullshit/main.c'
	#ifndef DLG_BASE_PATH
		#define DLG_BASE_PATH ""
	#endif
#endif

// Default tags applied to all logs/assertions (in the defining file).
// Must be in format ```#define DLG_DEFAULT_TAGS "tag1", "tag2"```
// or just nothing (as defaulted here)
#ifndef DLG_DEFAULT_TAGS
	#define DLG_DEFAULT_TAGS_TERM NULL
#else
	#define DLG_DEFAULT_TAGS_TERM DLG_DEFAULT_TAGS, NULL
#endif

// The function used for formatting. Can have any signature, but must be callable with
// the arguments the log/assertions macros are called with. Must return a const char*
// that will not be freed by dlg, the formatting function must keep track of it.
// The formatting function might use dlg_thread_buffer or a custom owned buffer.
// The returned const char* has to be valid until the dlg log/assertion ends.
// Usually a c function with ... (i.e. using va_list) or a variadic c++ template do
// allow formatting.
#ifndef DLG_FMT_FUNC
	#define DLG_FMT_FUNC dlg__printf_format
#endif

// Only overwrite (i.e. predefine) this if you know what you are doing.
// On windows this is used to add the dllimport specified.
// If you are using the static version of dlg (on windows) define
// DLG_STATIC before including dlg.h
#ifndef DLG_API
 	#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(DLG_STATIC)
		#define DLG_API __declspec(dllimport)
	#else
		#define DLG_API
	#endif
#endif

// This macro is used when an assertion fails. It gets the source expression
// and can return an alternative (that must stay alive).
// Mainly useful to execute something on failed assertion.
#ifndef DLG_FAILED_ASSERTION_TEXT
	#define DLG_FAILED_ASSERTION_TEXT(x) x
#endif

// - utility -
// two methods needed since cplusplus does not support compound literals
// and c does not support uniform initialization/initializer lists
#ifdef __cplusplus
	#include <initializer_list>
	#define DLG_CREATE_TAGS(...) std::initializer_list<const char*> \
		{DLG_DEFAULT_TAGS_TERM, __VA_ARGS__, NULL}.begin()
#else
	#define DLG_CREATE_TAGS(...) (const char* const[]) {DLG_DEFAULT_TAGS_TERM, __VA_ARGS__, NULL}
#endif

#ifdef __GNUC__
	#define DLG_PRINTF_ATTRIB(a, b) __attribute__ ((format (printf, a, b)))
#else
	#define DLG_PRINTF_ATTRIB(a, b)
#endif

#ifdef __cplusplus
extern "C" {
#endif


// Represents the importance of a log/assertion call.
enum dlg_level {
	dlg_level_trace = 0, // temporary used debug, e.g. to check if control reaches function
	dlg_level_debug, // general debugging, prints e.g. all major events
	dlg_level_info, // general useful information
	dlg_level_warn, // warning, something went wrong but might have no (really bad) side effect
	dlg_level_error, // something really went wrong; expect serious issues
	dlg_level_fatal // critical error; application is likely to crash/exit
};

// Holds various information associated with a log/assertion call.
// Forwarded to the output handler.
struct dlg_origin {
	const char* file;
	unsigned int line;
	const char* func;
	enum dlg_level level;
	const char** tags; // null-terminated
	const char* expr; // assertion expression, otherwise null
};

// Type of the output handler, see dlg_set_handler.
typedef void(*dlg_handler)(const struct dlg_origin* origin, const char* string, void* data);

#ifndef DLG_DISABLE
	// Tagged/Untagged logging with variable level
	// Tags must always be in the format `("tag1", "tag2")` (including brackets)
	// Example usages:
	//   dlg_log(dlg_level_warning, "test 1")
	//   dlg_logt(("tag1, "tag2"), dlg_level_debug, "test %d", 2)
	#define dlg_log(level, ...) if(level >= DLG_LOG_LEVEL) \
		dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__,  \
		DLG_FMT_FUNC(__VA_ARGS__), NULL)
	#define dlg_logt(level, tags, ...) if(level >= DLG_LOG_LEVEL) \
		dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, __func__, \
		DLG_FMT_FUNC(__VA_ARGS__), NULL)

	// Dynamic level assert macros in various versions for additional arguments
	// Example usages:
	//   dlg_assertl(dlg_level_warning, data != nullptr);
	//   dlg_assertlt(("tag1, "tag2"), dlg_level_trace, data != nullptr);
	//   dlg_asserttlm(("tag1), dlg_level_warning, data != nullptr, "Data must not be null");
	//   dlg_assertlm(dlg_level_error, data != nullptr, "Data must not be null");
	#define dlg_assertl(level, expr) if(level >= DLG_ASSERT_LEVEL && !(expr)) \
		dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__, NULL, \
			DLG_FAILED_ASSERTION_TEXT(#expr))
	#define dlg_assertlt(level, tags, expr) if(level >= DLG_ASSERT_LEVEL && !(expr)) \
		dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, __func__, NULL, \
			DLG_FAILED_ASSERTION_TEXT(#expr))
	#define dlg_assertlm(level, expr, ...) if(level >= DLG_ASSERT_LEVEL && !(expr)) \
		dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__,  \
			DLG_FMT_FUNC(__VA_ARGS__), DLG_FAILED_ASSERTION_TEXT(#expr))
	#define dlg_assertltm(level, tags, expr, ...) if(level >= DLG_ASSERT_LEVEL && !(expr)) \
		dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__,  \
			__func__, DLG_FMT_FUNC(__VA_ARGS__), DLG_FAILED_ASSERTION_TEXT(#expr))

	#define dlg__assert_or(level, tags, expr, code, msg) if(!(expr)) {\
			if(level >= DLG_ASSERT_LEVEL) \
				dlg__do_log(level, tags, DLG_FILE, __LINE__, __func__, msg, \
					DLG_FAILED_ASSERTION_TEXT(#expr)); \
			code; \
		} (void) NULL

	// - Private interface: not part of the abi/api but needed in macros -
	// Formats the given format string and arguments as printf would, uses the thread buffer.
	DLG_API const char* dlg__printf_format(const char* format, ...) DLG_PRINTF_ATTRIB(1, 2);
	DLG_API void dlg__do_log(enum dlg_level lvl, const char* const*, const char*, int,
		const char*, const char*, const char*);
	DLG_API const char* dlg__strip_root_path(const char* file, const char* base);

#else // DLG_DISABLE

	#define dlg_log(level, ...)
	#define dlg_logt(level, tags, ...)

	#define dlg_assertl(level, expr) // assert without tags/message
	#define dlg_assertlt(level, tags, expr) // assert with tags
	#define dlg_assertlm(level, expr, ...) // assert with message
	#define dlg_assertltm(level, tags, expr, ...) // assert with tags & message

	#define dlg__assert_or(level, tags, expr, code, msg) if(!(expr)) { code; } (void) NULL
#endif // DLG_DISABLE

// The API below is independent from DLG_DISABLE

// Sets the handler that is responsible for formatting and outputting log calls.
// This function is not thread safe and the handler is set globally.
// The handler itself must not change dlg tags or call a dlg macro (if it
// does so, the provided string or tags array in 'origin' might get invalid).
// The handler can also be used for various other things such as dealing
// with failed assertions or filtering calls based on the passed tags.
// The default handler is dlg_default_output (see its doc for more info).
// If using c++ make sure the registered handler cannot throw e.g. by
// wrapping everything into a try-catch blog.
DLG_API void dlg_set_handler(dlg_handler handler, void* data);

// The default output handler.
// Only use this to reset the output handler, prefer to use
// dlg_generic_output (from output.h) which this function simply calls.
// It also flushes the stream used and correctly outputs even from multiple threads.
DLG_API void dlg_default_output(const struct dlg_origin*, const char* string, void*);

// Returns the currently active dlg handler and sets `data` to
// its user data pointer. `data` must not be NULL.
// Useful to create handler chains.
// This function is not threadsafe, i.e. retrieving the handler while
// changing it from another thread is unsafe.
// See `dlg_set_handler`.
DLG_API dlg_handler dlg_get_handler(void** data);

// Adds the given tag associated with the given function to the thread specific list.
// If func is not NULL the tag will only applied to calls from the same function.
// Remove the tag again calling dlg_remove_tag (with exactly the same pointers!).
// Does not check if the tag is already present.
DLG_API void dlg_add_tag(const char* tag, const char* func);

// Removes a tag added with dlg_add_tag (has no effect for tags no present).
// The pointers must be exactly the same pointers that were supplied to dlg_add_tag,
// this function will not check using strcmp. When the same tag/func combination
// is added multiple times, this function remove exactly one candidate, it is
// undefined which. Returns whether a tag was found (and removed).
DLG_API bool dlg_remove_tag(const char* tag, const char* func);

// Returns the thread-specific buffer and its size for dlg.
// The buffer should only be used by formatting functions.
// The buffer can be reallocated and the size changed, just make sure
// to update both values correctly.
DLG_API char** dlg_thread_buffer(size_t** size);

// Untagged leveled logging
#define dlg_trace(...) dlg_log(dlg_level_trace, __VA_ARGS__)
#define dlg_debug(...) dlg_log(dlg_level_debug, __VA_ARGS__)
#define dlg_info(...) dlg_log(dlg_level_info, __VA_ARGS__)
#define dlg_warn(...) dlg_log(dlg_level_warn, __VA_ARGS__)
#define dlg_error(...) dlg_log(dlg_level_error, __VA_ARGS__)
#define dlg_fatal(...) dlg_log(dlg_level_fatal, __VA_ARGS__)

// Tagged leveled logging
#define dlg_tracet(tags, ...) dlg_logt(dlg_level_trace, tags, __VA_ARGS__)
#define dlg_debugt(tags, ...) dlg_logt(dlg_level_debug, tags, __VA_ARGS__)
#define dlg_infot(tags, ...) dlg_logt(dlg_level_info, tags, __VA_ARGS__)
#define dlg_warnt(tags, ...) dlg_logt(dlg_level_warn, tags, __VA_ARGS__)
#define dlg_errort(tags, ...) dlg_logt(dlg_level_error, tags, __VA_ARGS__)
#define dlg_fatalt(tags, ...) dlg_logt(dlg_level_fatal, tags, __VA_ARGS__)

// Assert macros useing DLG_DEFAULT_ASSERT as level
#define dlg_assert(expr) dlg_assertl(DLG_DEFAULT_ASSERT, expr)
#define dlg_assertt(tags, expr) dlg_assertlt(DLG_DEFAULT_ASSERT, tags, expr)
#define dlg_assertm(expr, ...) dlg_assertlm(DLG_DEFAULT_ASSERT, expr, __VA_ARGS__)
#define dlg_asserttm(tags, expr, ...) dlg_assertltm(DLG_DEFAULT_ASSERT, tags, expr, __VA_ARGS__)

// If (expr) does not evaluate to true, always executes 'code' (no matter what
// DLG_ASSERT_LEVEL is or if dlg is disabled or not).
// When dlg is enabled and the level is greater or equal to DLG_ASSERT_LEVEL,
// logs the failed assertion.
// Example usages:
//   dlg_assertl_or(dlg_level_warn, data != nullptr, return);
//   dlg_assertlm_or(dlg_level_fatal, data != nullptr, return, "Data must not be null");
//   dlg_assert_or(data != nullptr, logError(); return false);
#define dlg_assertltm_or(level, tags, expr, code, ...) dlg__assert_or(level, \
		DLG_CREATE_TAGS tags, expr, code, DLG_FMT_FUNC(__VA_ARGS__))
#define dlg_assertlm_or(level, expr, code, ...) dlg__assert_or(level, \
		DLG_CREATE_TAGS(NULL), expr, code, DLG_FMT_FUNC(__VA_ARGS__))
#define dlg_assertl_or(level, expr, code) dlg__assert_or(level, \
		DLG_CREATE_TAGS(NULL), expr, code, NULL)

#define dlg_assert_or(expr, code) dlg_assertl_or(DLG_DEFAULT_ASSERT, expr, code)
#define dlg_assertm_or(expr, code, ...) dlg_assertlm_or(DLG_DEFAULT_ASSERT, expr, code, __VA_ARGS__)

#ifdef __cplusplus
}
#endif

#endif // header guard