tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

dlg.h (12449B)


      1 // Copyright (c) 2019 nyorain
      2 // Distributed under the Boost Software License, Version 1.0.
      3 // See accompanying file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt
      4 
      5 #ifndef INC_DLG_DLG_H_
      6 #define INC_DLG_DLG_H_
      7 
      8 #include <stdbool.h>
      9 #include <stddef.h>
     10 #include <stdlib.h>
     11 #include <stdarg.h>
     12 #include <stdio.h>
     13 
     14 // Hosted at https://github.com/nyorain/dlg.
     15 // There are examples and documentation.
     16 // Issue reports and contributions appreciated.
     17 
     18 // - CONFIG -
     19 // Define this macro to make all dlg macros have no effect at all
     20 // #define DLG_DISABLE
     21 
     22 // the log/assertion levels below which logs/assertions are ignored
     23 // defaulted depending on the NDEBUG macro
     24 #ifndef DLG_LOG_LEVEL
     25 #ifdef NDEBUG
     26 	#define DLG_LOG_LEVEL dlg_level_warn
     27 #else
     28 	#define DLG_LOG_LEVEL dlg_level_trace
     29 #endif
     30 #endif
     31 
     32 #ifndef DLG_ASSERT_LEVEL
     33 #ifdef NDEBUG
     34 	#define DLG_ASSERT_LEVEL dlg_level_warn
     35 #else
     36 	#define DLG_ASSERT_LEVEL dlg_level_trace
     37 #endif
     38 #endif
     39 
     40 // the assert level of dlg_assert
     41 #ifndef DLG_DEFAULT_ASSERT
     42 #define DLG_DEFAULT_ASSERT dlg_level_error
     43 #endif
     44 
     45 // evaluated to the 'file' member in dlg_origin
     46 #ifndef DLG_FILE
     47 #define DLG_FILE dlg__strip_root_path(__FILE__, DLG_BASE_PATH)
     48 
     49 // the base path stripped from __FILE__. If you don't override DLG_FILE set this to
     50 // the project root to make 'main.c' from '/some/bullshit/main.c'
     51 #ifndef DLG_BASE_PATH
     52 	#define DLG_BASE_PATH ""
     53 #endif
     54 #endif
     55 
     56 // Default tags applied to all logs/assertions (in the defining file).
     57 // Must be in format ```#define DLG_DEFAULT_TAGS "tag1", "tag2"```
     58 // or just nothing (as defaulted here)
     59 #ifndef DLG_DEFAULT_TAGS
     60 #define DLG_DEFAULT_TAGS_TERM NULL
     61 #else
     62 #define DLG_DEFAULT_TAGS_TERM DLG_DEFAULT_TAGS, NULL
     63 #endif
     64 
     65 // The function used for formatting. Can have any signature, but must be callable with
     66 // the arguments the log/assertions macros are called with. Must return a const char*
     67 // that will not be freed by dlg, the formatting function must keep track of it.
     68 // The formatting function might use dlg_thread_buffer or a custom owned buffer.
     69 // The returned const char* has to be valid until the dlg log/assertion ends.
     70 // Usually a c function with ... (i.e. using va_list) or a variadic c++ template do
     71 // allow formatting.
     72 #ifndef DLG_FMT_FUNC
     73 #define DLG_FMT_FUNC dlg__printf_format
     74 #endif
     75 
     76 // Only overwrite (i.e. predefine) this if you know what you are doing.
     77 // On windows this is used to add the dllimport specified.
     78 // If you are using the static version of dlg (on windows) define
     79 // DLG_STATIC before including dlg.h
     80 #ifndef DLG_API
     81 	#if (defined(_WIN32) || defined(__CYGWIN__)) && !defined(DLG_STATIC)
     82 	#define DLG_API __declspec(dllimport)
     83 #else
     84 	#define DLG_API
     85 #endif
     86 #endif
     87 
     88 // This macro is used when an assertion fails. It gets the source expression
     89 // and can return an alternative (that must stay alive).
     90 // Mainly useful to execute something on failed assertion.
     91 #ifndef DLG_FAILED_ASSERTION_TEXT
     92 #define DLG_FAILED_ASSERTION_TEXT(x) x
     93 #endif
     94 
     95 // - utility -
     96 // two methods needed since cplusplus does not support compound literals
     97 // and c does not support uniform initialization/initializer lists
     98 #ifdef __cplusplus
     99 #include <initializer_list>
    100 #define DLG_CREATE_TAGS(...) std::initializer_list<const char*> \
    101 	{DLG_DEFAULT_TAGS_TERM, __VA_ARGS__, NULL}.begin()
    102 #else
    103 #define DLG_CREATE_TAGS(...) (const char* const[]) {DLG_DEFAULT_TAGS_TERM, __VA_ARGS__, NULL}
    104 #endif
    105 
    106 #ifdef __GNUC__
    107 #define DLG_PRINTF_ATTRIB(a, b) __attribute__ ((format (printf, a, b)))
    108 #else
    109 #define DLG_PRINTF_ATTRIB(a, b)
    110 #endif
    111 
    112 #ifdef __cplusplus
    113 extern "C" {
    114 #endif
    115 
    116 
    117 // Represents the importance of a log/assertion call.
    118 enum dlg_level {
    119 dlg_level_trace = 0, // temporary used debug, e.g. to check if control reaches function
    120 dlg_level_debug, // general debugging, prints e.g. all major events
    121 dlg_level_info, // general useful information
    122 dlg_level_warn, // warning, something went wrong but might have no (really bad) side effect
    123 dlg_level_error, // something really went wrong; expect serious issues
    124 dlg_level_fatal // critical error; application is likely to crash/exit
    125 };
    126 
    127 // Holds various information associated with a log/assertion call.
    128 // Forwarded to the output handler.
    129 struct dlg_origin {
    130 const char* file;
    131 unsigned int line;
    132 const char* func;
    133 enum dlg_level level;
    134 const char** tags; // null-terminated
    135 const char* expr; // assertion expression, otherwise null
    136 };
    137 
    138 // Type of the output handler, see dlg_set_handler.
    139 typedef void(*dlg_handler)(const struct dlg_origin* origin, const char* string, void* data);
    140 
    141 #ifndef DLG_DISABLE
    142 // Tagged/Untagged logging with variable level
    143 // Tags must always be in the format `("tag1", "tag2")` (including brackets)
    144 // Example usages:
    145 //   dlg_log(dlg_level_warning, "test 1")
    146 //   dlg_logt(("tag1, "tag2"), dlg_level_debug, "test %d", 2)
    147 #define dlg_log(level, ...) if(level >= DLG_LOG_LEVEL) \
    148 	dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__,  \
    149 	DLG_FMT_FUNC(__VA_ARGS__), NULL)
    150 #define dlg_logt(level, tags, ...) if(level >= DLG_LOG_LEVEL) \
    151 	dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, __func__, \
    152 	DLG_FMT_FUNC(__VA_ARGS__), NULL)
    153 
    154 // Dynamic level assert macros in various versions for additional arguments
    155 // Example usages:
    156 //   dlg_assertl(dlg_level_warning, data != nullptr);
    157 //   dlg_assertlt(("tag1, "tag2"), dlg_level_trace, data != nullptr);
    158 //   dlg_asserttlm(("tag1), dlg_level_warning, data != nullptr, "Data must not be null");
    159 //   dlg_assertlm(dlg_level_error, data != nullptr, "Data must not be null");
    160 #define dlg_assertl(level, expr) if(level >= DLG_ASSERT_LEVEL && !(expr)) \
    161 	dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__, NULL, \
    162 		DLG_FAILED_ASSERTION_TEXT(#expr))
    163 #define dlg_assertlt(level, tags, expr) if(level >= DLG_ASSERT_LEVEL && !(expr)) \
    164 	dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__, __func__, NULL, \
    165 		DLG_FAILED_ASSERTION_TEXT(#expr))
    166 #define dlg_assertlm(level, expr, ...) if(level >= DLG_ASSERT_LEVEL && !(expr)) \
    167 	dlg__do_log(level, DLG_CREATE_TAGS(NULL), DLG_FILE, __LINE__, __func__,  \
    168 		DLG_FMT_FUNC(__VA_ARGS__), DLG_FAILED_ASSERTION_TEXT(#expr))
    169 #define dlg_assertltm(level, tags, expr, ...) if(level >= DLG_ASSERT_LEVEL && !(expr)) \
    170 	dlg__do_log(level, DLG_CREATE_TAGS tags, DLG_FILE, __LINE__,  \
    171 		__func__, DLG_FMT_FUNC(__VA_ARGS__), DLG_FAILED_ASSERTION_TEXT(#expr))
    172 
    173 #define dlg__assert_or(level, tags, expr, code, msg) if(!(expr)) {\
    174 		if(level >= DLG_ASSERT_LEVEL) \
    175 			dlg__do_log(level, tags, DLG_FILE, __LINE__, __func__, msg, \
    176 				DLG_FAILED_ASSERTION_TEXT(#expr)); \
    177 		code; \
    178 	} (void) NULL
    179 
    180 // - Private interface: not part of the abi/api but needed in macros -
    181 // Formats the given format string and arguments as printf would, uses the thread buffer.
    182 DLG_API const char* dlg__printf_format(const char* format, ...) DLG_PRINTF_ATTRIB(1, 2);
    183 DLG_API void dlg__do_log(enum dlg_level lvl, const char* const*, const char*, int,
    184 	const char*, const char*, const char*);
    185 DLG_API const char* dlg__strip_root_path(const char* file, const char* base);
    186 
    187 #else // DLG_DISABLE
    188 
    189 #define dlg_log(level, ...)
    190 #define dlg_logt(level, tags, ...)
    191 
    192 #define dlg_assertl(level, expr) // assert without tags/message
    193 #define dlg_assertlt(level, tags, expr) // assert with tags
    194 #define dlg_assertlm(level, expr, ...) // assert with message
    195 #define dlg_assertltm(level, tags, expr, ...) // assert with tags & message
    196 
    197 #define dlg__assert_or(level, tags, expr, code, msg) if(!(expr)) { code; } (void) NULL
    198 #endif // DLG_DISABLE
    199 
    200 // The API below is independent from DLG_DISABLE
    201 
    202 // Sets the handler that is responsible for formatting and outputting log calls.
    203 // This function is not thread safe and the handler is set globally.
    204 // The handler itself must not change dlg tags or call a dlg macro (if it
    205 // does so, the provided string or tags array in 'origin' might get invalid).
    206 // The handler can also be used for various other things such as dealing
    207 // with failed assertions or filtering calls based on the passed tags.
    208 // The default handler is dlg_default_output (see its doc for more info).
    209 // If using c++ make sure the registered handler cannot throw e.g. by
    210 // wrapping everything into a try-catch blog.
    211 DLG_API void dlg_set_handler(dlg_handler handler, void* data);
    212 
    213 // The default output handler.
    214 // Only use this to reset the output handler, prefer to use
    215 // dlg_generic_output (from output.h) which this function simply calls.
    216 // It also flushes the stream used and correctly outputs even from multiple threads.
    217 DLG_API void dlg_default_output(const struct dlg_origin*, const char* string, void*);
    218 
    219 // Returns the currently active dlg handler and sets `data` to
    220 // its user data pointer. `data` must not be NULL.
    221 // Useful to create handler chains.
    222 // This function is not threadsafe, i.e. retrieving the handler while
    223 // changing it from another thread is unsafe.
    224 // See `dlg_set_handler`.
    225 DLG_API dlg_handler dlg_get_handler(void** data);
    226 
    227 // Adds the given tag associated with the given function to the thread specific list.
    228 // If func is not NULL the tag will only applied to calls from the same function.
    229 // Remove the tag again calling dlg_remove_tag (with exactly the same pointers!).
    230 // Does not check if the tag is already present.
    231 DLG_API void dlg_add_tag(const char* tag, const char* func);
    232 
    233 // Removes a tag added with dlg_add_tag (has no effect for tags no present).
    234 // The pointers must be exactly the same pointers that were supplied to dlg_add_tag,
    235 // this function will not check using strcmp. When the same tag/func combination
    236 // is added multiple times, this function remove exactly one candidate, it is
    237 // undefined which. Returns whether a tag was found (and removed).
    238 DLG_API bool dlg_remove_tag(const char* tag, const char* func);
    239 
    240 // Returns the thread-specific buffer and its size for dlg.
    241 // The buffer should only be used by formatting functions.
    242 // The buffer can be reallocated and the size changed, just make sure
    243 // to update both values correctly.
    244 DLG_API char** dlg_thread_buffer(size_t** size);
    245 
    246 // Untagged leveled logging
    247 #define dlg_trace(...) dlg_log(dlg_level_trace, __VA_ARGS__)
    248 #define dlg_debug(...) dlg_log(dlg_level_debug, __VA_ARGS__)
    249 #define dlg_info(...) dlg_log(dlg_level_info, __VA_ARGS__)
    250 #define dlg_warn(...) dlg_log(dlg_level_warn, __VA_ARGS__)
    251 #define dlg_error(...) dlg_log(dlg_level_error, __VA_ARGS__)
    252 #define dlg_fatal(...) dlg_log(dlg_level_fatal, __VA_ARGS__)
    253 
    254 // Tagged leveled logging
    255 #define dlg_tracet(tags, ...) dlg_logt(dlg_level_trace, tags, __VA_ARGS__)
    256 #define dlg_debugt(tags, ...) dlg_logt(dlg_level_debug, tags, __VA_ARGS__)
    257 #define dlg_infot(tags, ...) dlg_logt(dlg_level_info, tags, __VA_ARGS__)
    258 #define dlg_warnt(tags, ...) dlg_logt(dlg_level_warn, tags, __VA_ARGS__)
    259 #define dlg_errort(tags, ...) dlg_logt(dlg_level_error, tags, __VA_ARGS__)
    260 #define dlg_fatalt(tags, ...) dlg_logt(dlg_level_fatal, tags, __VA_ARGS__)
    261 
    262 // Assert macros useing DLG_DEFAULT_ASSERT as level
    263 #define dlg_assert(expr) dlg_assertl(DLG_DEFAULT_ASSERT, expr)
    264 #define dlg_assertt(tags, expr) dlg_assertlt(DLG_DEFAULT_ASSERT, tags, expr)
    265 #define dlg_assertm(expr, ...) dlg_assertlm(DLG_DEFAULT_ASSERT, expr, __VA_ARGS__)
    266 #define dlg_asserttm(tags, expr, ...) dlg_assertltm(DLG_DEFAULT_ASSERT, tags, expr, __VA_ARGS__)
    267 
    268 // If (expr) does not evaluate to true, always executes 'code' (no matter what
    269 // DLG_ASSERT_LEVEL is or if dlg is disabled or not).
    270 // When dlg is enabled and the level is greater or equal to DLG_ASSERT_LEVEL,
    271 // logs the failed assertion.
    272 // Example usages:
    273 //   dlg_assertl_or(dlg_level_warn, data != nullptr, return);
    274 //   dlg_assertlm_or(dlg_level_fatal, data != nullptr, return, "Data must not be null");
    275 //   dlg_assert_or(data != nullptr, logError(); return false);
    276 #define dlg_assertltm_or(level, tags, expr, code, ...) dlg__assert_or(level, \
    277 	DLG_CREATE_TAGS tags, expr, code, DLG_FMT_FUNC(__VA_ARGS__))
    278 #define dlg_assertlm_or(level, expr, code, ...) dlg__assert_or(level, \
    279 	DLG_CREATE_TAGS(NULL), expr, code, DLG_FMT_FUNC(__VA_ARGS__))
    280 #define dlg_assertl_or(level, expr, code) dlg__assert_or(level, \
    281 	DLG_CREATE_TAGS(NULL), expr, code, NULL)
    282 
    283 #define dlg_assert_or(expr, code) dlg_assertl_or(DLG_DEFAULT_ASSERT, expr, code)
    284 #define dlg_assertm_or(expr, code, ...) dlg_assertlm_or(DLG_DEFAULT_ASSERT, expr, code, __VA_ARGS__)
    285 
    286 #ifdef __cplusplus
    287 }
    288 #endif
    289 
    290 #endif // header guard