21#ifdef WITH_CLOG_PTHREADS
27#if defined(__unix__) || defined(__APPLE__) || defined(__HAIKU__)
38# include <VersionHelpers.h>
40# if !defined(ENABLE_VIRTUAL_TERMINAL_PROCESSING)
41# define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
46#define __STDC_FORMAT_MACROS
58#define STREQ(a, b) (strcmp(a, b) == 0)
59#define STREQLEN(a, b, n) (strncmp(a, b, n) == 0)
62# define PATHSEP_CHAR '\\'
64# define PATHSEP_CHAR '/'
82#ifdef WITH_CLOG_PTHREADS
83 pthread_mutex_t types_lock;
135#define CLOG_BUF_LEN_INIT 512
146 cstr->
data = buf_stack;
182 char *str_dst = cstr->
data + cstr->
len;
183 memcpy(str_dst,
str,
len);
187 cstr->
len = len_next;
199 char *str_dst = cstr->
data + cstr->
len;
200 memset(str_dst, c,
len);
204 cstr->
len = len_next;
211 const uint len_max = 65535;
212 uint len_avail = cstr->len_alloc - cstr->len;
215 va_copy(args_cpy, args);
216 int retval = vsnprintf(cstr->data + cstr->len, len_avail,
format, args_cpy);
225 if ((
uint)retval <= len_avail) {
227 cstr->len += (
uint)retval;
240 len_avail = cstr->len_alloc - cstr->len;
247 if (indent_len < 2) {
251 uint num_newlines = 0;
253 if (cstr->
data[
i] ==
'\n') {
257 if (num_newlines == 0) {
261 const char *old_data = cstr->
data;
262 const uint old_len = cstr->
len;
263 const bool old_is_alloc = cstr->
is_alloc;
265 cstr->
len_alloc = cstr->
len + (num_newlines * indent_len);
270 for (
uint i = 0;
i < old_len;
i++) {
271 cstr->
data[cstr->
len++] = old_data[
i];
272 if (old_data[
i] ==
'\n') {
273 memset(cstr->
data + cstr->
len,
' ', indent_len);
274 cstr->
data[cstr->
len + indent_len - 2] =
'|';
275 cstr->
len += indent_len;
299#define COLOR_LEN (COLOR_RESET + 1)
303static DWORD clg_previous_console_mode = 0;
338 return "INVALID_LEVEL";
380 const size_t identifier_len = strlen(identifier);
383 while (flt !=
nullptr) {
384 const size_t len = strlen(flt->
match);
392 memcpy(match, flt->
match + 1,
len - 2);
393 const bool success = (strstr(identifier, match) !=
nullptr);
421 if (
STREQ(identifier, ty->identifier)) {
476 tick = GetTickCount64();
479 gettimeofday(&tv,
nullptr);
480 tick = tv.tv_sec * 1000 + tv.tv_usec / 1000;
493 char timestamp_str[128];
495 const int h = int(timestamp / (1000 * 60 * 60));
496 const int m = int((timestamp / (1000 * 60)) % 60);
497 const int s = int((timestamp / 1000) % 60);
498 const int r = int(timestamp % 1000);
500 const uint timestamp_len =
502 snprintf(timestamp_str,
sizeof(timestamp_str),
"%.2d:%.2d:%.2d.%.3d ", h, m, s, r) :
503 snprintf(timestamp_str,
sizeof(timestamp_str),
"%.2d:%.2d.%.3d ", m, s, r);
511 char memory_str[128];
512 const uint len = snprintf(memory_str,
sizeof(memory_str),
"%dM", (
int)
mem_in_use);
516 const uint memory_align_width = 5;
517 const uint num_spaces = (
len < memory_align_width) ? memory_align_width -
len : 0;
545 const uint type_align_width = 16;
546 const uint num_spaces = (
len < type_align_width) ? type_align_width -
len : 0;
551 const char *file_line,
553 const bool use_basename,
554 const bool use_color)
560 uint file_line_len = strlen(file_line);
562 uint file_line_offset = file_line_len;
563 while (file_line_offset-- > 0) {
569 file_line += file_line_offset;
570 file_line_len -= file_line_offset;
584 const char *file_line,
590 clg_str_init(&cstr, cstr_stack_buf,
sizeof(cstr_stack_buf));
638 const char *file_line,
645 clg_str_init(&cstr, cstr_stack_buf,
sizeof(cstr_stack_buf));
703 int bytes_written = write(lg->
ctx->
output, message, strlen(message));
715 ctx->
output_file =
static_cast<FILE *
>(file_handle);
717#if defined(__unix__) || defined(__APPLE__)
727 GetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), &clg_previous_console_mode);
730 if (IsWindows10OrGreater() && isatty(ctx->
output)) {
731 DWORD mode = clg_previous_console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING;
732 if (SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), mode)) {
780 const char *type_match,
783 if (type_match_len == 0) {
787 MEM_callocN(
sizeof(*flt) + type_match_len + 1, __func__));
788 flt->
next = *flt_list;
790 memcpy(flt->
match, type_match, type_match_len);
795 const char *type_match,
802 const char *type_match,
822#ifdef WITH_CLOG_PTHREADS
823 pthread_mutex_init(&ctx->types_lock,
nullptr);
835 SetConsoleMode(GetStdHandle(STD_OUTPUT_HANDLE), clg_previous_console_mode);
837 while (ctx->
types !=
nullptr) {
848 while (ctx->
filters[
i] !=
nullptr) {
854#ifdef WITH_CLOG_PTHREADS
855 pthread_mutex_destroy(&ctx->types_lock);
962 static std::mutex
mutex;
965 clg_ref->
next = *all_refs;
973 auto cmp = [](
const char *a,
const char *
b) {
return std::strcmp(a,
b) < 0; };
974 std::set<
const char *,
decltype(cmp)> identifiers(cmp);
976 identifiers.insert(ref->identifier);
979 for (
const char *identifier : identifiers) {
980 callback(identifier, user_data);
986#ifdef WITH_CLOG_PTHREADS
988 pthread_mutex_lock(&
g_ctx->types_lock);
990 if (clg_ref->
type ==
nullptr) {
992 if (clg_ty ==
nullptr) {
995#ifdef WITH_CLOG_PTHREADS
998 clg_ref->
type = clg_ty;
1001#ifdef WITH_CLOG_PTHREADS
1002 pthread_mutex_unlock(&
g_ctx->types_lock);
1008 if (clg_ref->
type ==
nullptr) {
#define ATTR_PRINTF_FORMAT(format_param, dots_param)
#define STREQLEN(a, b, n)
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
Provides wrapper around system-specific atomic primitives, and some extensions (faked-atomic operatio...
ATOMIC_INLINE void * atomic_cas_ptr(void **v, void *old, void *_new)
BMesh const char void * data
unsigned long long int uint64_t
static void CLG_ctx_output_set(CLogContext *ctx, void *file_handle)
static void write_type(CLogStringBuf *cstr, const CLG_LogType *lg)
static uint64_t clg_timestamp_ticks_get()
static void clg_str_append_char(CLogStringBuf *cstr, const char c, const uint len)
void CLG_type_filter_exclude(const char *type_match, int type_match_len)
static void clg_str_vappendf(CLogStringBuf *cstr, const char *format, va_list args)
static void clg_ctx_fatal_action(CLogContext *ctx)
void CLG_output_set(void *file_handle)
static void CLG_ctx_free(CLogContext *ctx)
void CLG_output_use_basename_set(int value)
void CLG_output_use_memory_set(int value)
void CLG_log_raw(const CLG_LogType *lg, const char *message)
void CLG_error_fn_set(void(*error_fn)(void *file_handle))
void CLG_level_set(CLG_Level level)
void CLG_output_use_source_set(int value)
static void clg_ctx_error_action(CLogContext *ctx)
static CLG_LogType * clg_ctx_type_find_by_name(CLogContext *ctx, const char *identifier)
void CLG_backtrace_fn_set(void(*fatal_fn)(void *file_handle))
static void CLG_ctx_output_use_timestamp_set(CLogContext *ctx, int value)
static std::mutex LOG_MUTEX
static void clg_str_append_with_len(CLogStringBuf *cstr, const char *str, const uint len)
static void write_memory(CLogStringBuf *cstr)
void CLG_log_str(const CLG_LogType *lg, enum CLG_Level level, const char *file_line, const char *fn, const char *message)
static CLogContext * CLG_ctx_init()
static void write_timestamp(CLogStringBuf *cstr, const uint64_t timestamp_tick_start)
static void CLG_ctx_output_use_source_set(CLogContext *ctx, int value)
#define CLOG_BUF_LEN_INIT
void CLG_logf(const CLG_LogType *lg, enum CLG_Level level, const char *file_line, const char *fn, const char *format,...)
#define STREQLEN(a, b, n)
void CLG_fatal_fn_set(void(*fatal_fn)(void *file_handle))
static void clg_str_append(CLogStringBuf *cstr, const char *str)
void CLG_logref_list_all(void(*callback)(const char *identifier, void *user_data), void *user_data)
void CLG_logref_register(CLG_LogRef *clg_ref)
static void CLG_ctx_output_use_memory_set(CLogContext *ctx, int value)
static const char * clg_color_table[COLOR_LEN]
static void CLG_ctx_fatal_fn_set(CLogContext *ctx, void(*fatal_fn)(void *file_handle))
void CLG_type_filter_include(const char *type_match, int type_match_len)
void CLG_logref_init(CLG_LogRef *clg_ref)
static void clg_ctx_type_filter_append(CLG_IDFilter **flt_list, const char *type_match, int type_match_len)
static struct CLogContext * g_ctx
static void clg_str_free(CLogStringBuf *cstr)
static void write_level(CLogStringBuf *cstr, enum CLG_Level level, bool use_color)
void CLG_output_use_timestamp_set(int value)
static void CLG_ctx_output_use_basename_set(CLogContext *ctx, int value)
static CLG_LogType * clg_ctx_type_register(CLogContext *ctx, const char *identifier)
static void clg_str_init(CLogStringBuf *cstr, char *buf_stack, uint buf_stack_len)
static void clg_ctx_backtrace(CLogContext *ctx)
static void CLG_ctx_backtrace_fn_set(CLogContext *ctx, void(*backtrace_fn)(void *file_handle))
static CLG_LogRef ** clg_all_refs_p()
static void clg_str_reserve(CLogStringBuf *cstr, const uint len)
void CLG_quiet_set(bool quiet)
static void CLG_ctx_level_set(CLogContext *ctx, CLG_Level level)
static void CLG_ctx_type_filter_exclude(CLogContext *ctx, const char *type_match, int type_match_len)
static void clg_str_indent_multiline(CLogStringBuf *cstr, const uint indent_len)
static void clg_color_table_init(bool use_color)
static const char * clg_level_as_text(enum CLG_Level level)
static void write_file_line_fn(CLogStringBuf *cstr, const char *file_line, const char *fn, const bool use_basename, const bool use_color)
int CLG_color_support_get(CLG_LogRef *clg_ref)
static enum eCLogColor clg_level_to_color(enum CLG_Level level)
static bool clg_ctx_filter_check(CLogContext *ctx, const char *identifier)
static void CLG_ctx_type_filter_include(CLogContext *ctx, const char *type_match, int type_match_len)
static void CLT_ctx_error_fn_set(CLogContext *ctx, void(*error_fn)(void *file_handle))
#define assert(assertion)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
size_t(* MEM_get_memory_in_use)(void)
void * MEM_callocN(size_t len, const char *str)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
struct CLG_IDFilter * next
struct CLG_LogType * next
struct CLogContext::@150175052047236141236166345214312336306070316061 default_type
void(* fatal_fn)(void *file_handle)
void(* error_fn)(void *file_handle)
uint64_t timestamp_tick_start
void(* backtrace_fn)(void *file_handle)
CLG_IDFilter * filters[2]
struct CLogContext::@363215326307130321371241047232307372132122233336 callbacks