forked from bartvdbraak/blender
C Logging: use instead of printf for messages
- See `--log` help message for usage. - Supports enabling categories. - Color severity. - Optionally logs to a file. - Currently use to replace printf calls in wm module. See D3120 for details.
This commit is contained in:
parent
c647c93f63
commit
891c1cfc9a
@ -674,6 +674,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
|
||||
extern_sdlew
|
||||
|
||||
bf_intern_glew_mx
|
||||
bf_intern_clog
|
||||
)
|
||||
|
||||
if(NOT WITH_SYSTEM_GLOG)
|
||||
|
@ -24,6 +24,7 @@
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
# add_subdirectory(atomic) # header only
|
||||
add_subdirectory(clog)
|
||||
add_subdirectory(string)
|
||||
add_subdirectory(ghost)
|
||||
add_subdirectory(guardedalloc)
|
||||
|
147
intern/clog/CLG_log.h
Normal file
147
intern/clog/CLG_log.h
Normal file
@ -0,0 +1,147 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#ifndef __CLOG_H__
|
||||
#define __CLOG_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define _CLOG_ATTR_NONNULL(args ...) __attribute__((nonnull(args)))
|
||||
#else
|
||||
# define _CLOG_ATTR_NONNULL(...)
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define _CLOG_ATTR_PRINTF_FORMAT(format_param, dots_param) __attribute__((format(printf, format_param, dots_param)))
|
||||
#else
|
||||
# define _CLOG_ATTR_PRINTF_FORMAT(format_param, dots_param)
|
||||
#endif
|
||||
|
||||
#define STRINGIFY_ARG(x) "" #x
|
||||
#define STRINGIFY_APPEND(a, b) "" a #b
|
||||
#define STRINGIFY(x) STRINGIFY_APPEND("", x)
|
||||
|
||||
struct CLogContext;
|
||||
|
||||
/* Don't typedef enums. */
|
||||
enum CLG_LogFlag {
|
||||
CLG_FLAG_USE = (1 << 0),
|
||||
};
|
||||
|
||||
enum CLG_Severity {
|
||||
CLG_SEVERITY_INFO = 0,
|
||||
CLG_SEVERITY_WARN,
|
||||
CLG_SEVERITY_ERROR,
|
||||
CLG_SEVERITY_FATAL,
|
||||
};
|
||||
#define CLG_SEVERITY_LEN (CLG_SEVERITY_FATAL + 1)
|
||||
|
||||
/* Each logger ID has one of these. */
|
||||
typedef struct CLG_LogType {
|
||||
struct CLG_LogType *next;
|
||||
char identifier[64];
|
||||
/** FILE output. */
|
||||
struct CLogContext *ctx;
|
||||
/** Control behavior. */
|
||||
int level;
|
||||
enum CLG_LogFlag flag;
|
||||
} CLG_LogType;
|
||||
|
||||
typedef struct CLG_LogRef {
|
||||
const char *identifier;
|
||||
CLG_LogType *type;
|
||||
} CLG_LogRef;
|
||||
|
||||
void CLG_log_str(
|
||||
CLG_LogType *lg, enum CLG_Severity severity, const char *file_line, const char *fn,
|
||||
const char *message)
|
||||
_CLOG_ATTR_NONNULL(1, 3, 4, 5);
|
||||
void CLG_logf(
|
||||
CLG_LogType *lg, enum CLG_Severity severity, const char *file_line, const char *fn,
|
||||
const char *format, ...)
|
||||
_CLOG_ATTR_NONNULL(1, 3, 4, 5) _CLOG_ATTR_PRINTF_FORMAT(5, 6);
|
||||
|
||||
/* Main initializer and distructor (per session, not logger). */
|
||||
void CLG_init(void);
|
||||
void CLG_exit(void);
|
||||
|
||||
void CLG_output_set(void *file_handle);
|
||||
void CLG_fatal_fn_set(void (*fatal_fn)(void *file_handle));
|
||||
|
||||
void CLG_type_filter(const char *type_filter, int type_filter_len);
|
||||
|
||||
void CLG_logref_init(CLG_LogRef *clg_ref);
|
||||
|
||||
/** Declare outside function, declare as extern in header. */
|
||||
#define CLG_LOGREF_DECLARE_GLOBAL(var, id) \
|
||||
static CLG_LogRef _static_ ## var = {id}; \
|
||||
CLG_LogRef *var = &_static_ ## var
|
||||
|
||||
/** Initialize struct once. */
|
||||
#define CLOG_ENSURE(clg_ref) \
|
||||
((clg_ref)->type ? (clg_ref)->type : (CLG_logref_init(clg_ref), (clg_ref)->type))
|
||||
|
||||
#define CLOG_AT_SEVERITY(clg_ref, severity, verbose_level, ...) { \
|
||||
CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
|
||||
if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || (severity >= CLG_SEVERITY_WARN)) { \
|
||||
CLG_logf(_lg_ty, severity, __FILE__ ":" STRINGIFY(__LINE__), __func__, __VA_ARGS__); \
|
||||
} \
|
||||
} ((void)0)
|
||||
|
||||
#define CLOG_STR_AT_SEVERITY(clg_ref, severity, verbose_level, str) { \
|
||||
CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
|
||||
if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || (severity >= CLG_SEVERITY_WARN)) { \
|
||||
CLG_log_str(lg, severity, __FILE__ ":" STRINGIFY(__LINE__), __func__, str); \
|
||||
} \
|
||||
} ((void)0)
|
||||
|
||||
#define CLOG_STR_AT_SEVERITY_N(clg_ref, severity, verbose_level, str) { \
|
||||
CLG_LogType *_lg_ty = CLOG_ENSURE(clg_ref); \
|
||||
if (((_lg_ty->flag & CLG_FLAG_USE) && (_lg_ty->level >= verbose_level)) || (severity >= CLG_SEVERITY_WARN)) { \
|
||||
const char *_str = str; \
|
||||
CLG_log_str(_lg_ty, severity, __FILE__ ":" STRINGIFY(__LINE__), __func__, _str); \
|
||||
MEM_freeN((void *)_str); \
|
||||
} \
|
||||
} ((void)0)
|
||||
|
||||
#define CLOG_INFO(clg_ref, level, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_INFO, level, __VA_ARGS__)
|
||||
#define CLOG_WARN(clg_ref, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_WARN, 0, __VA_ARGS__)
|
||||
#define CLOG_ERROR(clg_ref, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_ERROR, 0, __VA_ARGS__)
|
||||
#define CLOG_FATAL(clg_ref, ...) CLOG_AT_SEVERITY(clg_ref, CLG_SEVERITY_FATAL, 0, __VA_ARGS__)
|
||||
|
||||
#define CLOG_STR_INFO(clg_ref, level, ...) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_INFO, level, __VA_ARGS__)
|
||||
#define CLOG_STR_WARN(clg_ref, ...) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_WARN, 0, __VA_ARGS__)
|
||||
#define CLOG_STR_ERROR(clg_ref, ...) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_ERROR, 0, __VA_ARGS__)
|
||||
#define CLOG_STR_FATAL(clg_ref, ...) CLOG_STR_AT_SEVERITY(clg_ref, CLG_SEVERITY_FATAL, 0, __VA_ARGS__)
|
||||
|
||||
/* Allocated string which is immediately freed. */
|
||||
#define CLOG_STR_INFO_N(clg_ref, level, ...) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_INFO, level, __VA_ARGS__)
|
||||
#define CLOG_STR_WARN_N(clg_ref, ...) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_WARN, 0, __VA_ARGS__)
|
||||
#define CLOG_STR_ERROR_N(clg_ref, ...) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_ERROR, 0, __VA_ARGS__)
|
||||
#define CLOG_STR_FATAL_N(clg_ref, ...) CLOG_STR_AT_SEVERITY_N(clg_ref, CLG_SEVERITY_FATAL, 0, __VA_ARGS__)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __CLOG_H__ */
|
34
intern/clog/CMakeLists.txt
Normal file
34
intern/clog/CMakeLists.txt
Normal file
@ -0,0 +1,34 @@
|
||||
# ***** BEGIN GPL LICENSE BLOCK *****
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software Foundation,
|
||||
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
#
|
||||
# ***** END GPL LICENSE BLOCK *****
|
||||
|
||||
set(INC
|
||||
.
|
||||
../guardedalloc
|
||||
)
|
||||
|
||||
set(INC_SYS
|
||||
|
||||
)
|
||||
|
||||
set(SRC
|
||||
clog.c
|
||||
|
||||
CLG_log.h
|
||||
)
|
||||
|
||||
blender_add_lib(bf_intern_clog "${SRC}" "${INC}" "${INC_SYS}")
|
514
intern/clog/clog.c
Normal file
514
intern/clog/clog.c
Normal file
@ -0,0 +1,514 @@
|
||||
/*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 2
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
*
|
||||
* ***** END GPL LICENSE BLOCK *****
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* For 'isatty' to check for color. */
|
||||
#if defined(__unix__)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
/* own include. */
|
||||
#include "CLG_log.h"
|
||||
|
||||
/* Local utility defines */
|
||||
#define STREQ(a, b) (strcmp(a, b) == 0)
|
||||
#define STREQLEN(a, b, n) (strncmp(a, b, n) == 0)
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Types
|
||||
* \{ */
|
||||
|
||||
typedef struct CLG_IDFilter {
|
||||
struct CLG_IDFilter *next;
|
||||
/** Over alloc. */
|
||||
char match[0];
|
||||
} CLG_IDFilter;
|
||||
|
||||
typedef struct CLogContext {
|
||||
/** Single linked list of types. */
|
||||
CLG_LogType *types;
|
||||
CLG_IDFilter *filters;
|
||||
bool use_color;
|
||||
|
||||
/** Borrowed, not owned. */
|
||||
FILE *output;
|
||||
|
||||
/** For new types. */
|
||||
struct {
|
||||
int level;
|
||||
} default_type;
|
||||
|
||||
struct {
|
||||
void (*fatal_fn)(void *file_handle);
|
||||
} callbacks;
|
||||
} CLogContext;
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Mini Buffer Functionality
|
||||
*
|
||||
* Use so we can do a single call to write.
|
||||
* \{ */
|
||||
|
||||
#define CLOG_BUF_LEN_INIT 512
|
||||
|
||||
typedef struct CLogStringBuf {
|
||||
char *data;
|
||||
uint len;
|
||||
uint len_alloc;
|
||||
bool is_alloc;
|
||||
} CLogStringBuf;
|
||||
|
||||
static void clg_str_init(CLogStringBuf *cstr, char *buf_stack, uint buf_stack_len)
|
||||
{
|
||||
cstr->data = buf_stack;
|
||||
cstr->len_alloc = buf_stack_len;
|
||||
cstr->len = 0;
|
||||
cstr->is_alloc = false;
|
||||
}
|
||||
|
||||
static void clg_str_free(CLogStringBuf *cstr)
|
||||
{
|
||||
if (cstr->is_alloc) {
|
||||
MEM_freeN(cstr->data);
|
||||
}
|
||||
}
|
||||
|
||||
static void clg_str_reserve(CLogStringBuf *cstr, const uint len)
|
||||
{
|
||||
if (len > cstr->len_alloc) {
|
||||
if (cstr->is_alloc == false) {
|
||||
cstr->is_alloc = true;
|
||||
cstr->data = NULL;
|
||||
}
|
||||
cstr->len_alloc *= 2;
|
||||
if (len > cstr->len_alloc) {
|
||||
cstr->len_alloc = len;
|
||||
}
|
||||
cstr->data = MEM_reallocN(cstr->data, len);
|
||||
cstr->len_alloc = len;
|
||||
}
|
||||
}
|
||||
|
||||
static void clg_str_append_with_len(CLogStringBuf *cstr, const char *str, const uint len)
|
||||
{
|
||||
uint len_next = cstr->len + len;
|
||||
clg_str_reserve(cstr, len_next);
|
||||
char *str_dst = cstr->data + cstr->len;
|
||||
memcpy(str_dst, str, len);
|
||||
#if 0 /* no need. */
|
||||
str_dst[len] = '\0';
|
||||
#endif
|
||||
cstr->len = len_next;
|
||||
}
|
||||
|
||||
static void clg_str_append(CLogStringBuf *cstr, const char *str)
|
||||
{
|
||||
clg_str_append_with_len(cstr, str, strlen(str));
|
||||
}
|
||||
|
||||
static void clg_str_vappendf(CLogStringBuf *cstr, const char *fmt, va_list args)
|
||||
{
|
||||
/* Use limit because windows may use '-1' for a formatting error. */
|
||||
const uint len_max = 65535;
|
||||
uint len_avail = (cstr->len_alloc - cstr->len);
|
||||
if (len_avail == 0) {
|
||||
len_avail = CLOG_BUF_LEN_INIT;
|
||||
clg_str_reserve(cstr, len_avail);
|
||||
}
|
||||
while (true) {
|
||||
va_list args_cpy;
|
||||
va_copy(args_cpy, args);
|
||||
int retval = vsnprintf(cstr->data + cstr->len, len_avail, fmt, args_cpy);
|
||||
va_end(args_cpy);
|
||||
if (retval != -1) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
len_avail *= 2;
|
||||
if (len_avail >= len_max) {
|
||||
break;
|
||||
}
|
||||
clg_str_reserve(cstr, len_avail);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Internal Utilities
|
||||
* \{ */
|
||||
|
||||
enum eCLogColor {
|
||||
COLOR_DEFAULT,
|
||||
COLOR_RED,
|
||||
COLOR_GREEN,
|
||||
COLOR_YELLOW,
|
||||
|
||||
COLOR_RESET,
|
||||
};
|
||||
#define COLOR_LEN (COLOR_RESET + 1)
|
||||
|
||||
static const char *clg_color_table[COLOR_LEN] = {NULL};
|
||||
|
||||
static void clg_color_table_init(bool use_color)
|
||||
{
|
||||
for (int i = 0; i < COLOR_LEN; i++) {
|
||||
clg_color_table[i] = "";
|
||||
}
|
||||
if (use_color) {
|
||||
#ifdef _WIN32
|
||||
/* TODO */
|
||||
#else
|
||||
clg_color_table[COLOR_DEFAULT] = "\033[1;37m";
|
||||
clg_color_table[COLOR_RED] = "\033[1;31m";
|
||||
clg_color_table[COLOR_GREEN] = "\033[1;32m";
|
||||
clg_color_table[COLOR_YELLOW] = "\033[1;33m";
|
||||
clg_color_table[COLOR_RESET] = "\033[0m";
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
static const char *clg_severity_str[CLG_SEVERITY_LEN] = {
|
||||
[CLG_SEVERITY_INFO] = "INFO",
|
||||
[CLG_SEVERITY_WARN] = "WARN",
|
||||
[CLG_SEVERITY_ERROR] = "ERROR",
|
||||
[CLG_SEVERITY_FATAL] = "FATAL",
|
||||
};
|
||||
|
||||
static const char *clg_severity_as_text(enum CLG_Severity severity)
|
||||
{
|
||||
bool ok = (unsigned int)severity < CLG_SEVERITY_LEN;
|
||||
assert(ok);
|
||||
if (ok) {
|
||||
return clg_severity_str[severity];
|
||||
}
|
||||
else {
|
||||
return "INVALID_SEVERITY";
|
||||
}
|
||||
}
|
||||
|
||||
static enum eCLogColor clg_severity_to_color(enum CLG_Severity severity)
|
||||
{
|
||||
bool ok = (unsigned int)severity < CLG_SEVERITY_LEN;
|
||||
assert(ok);
|
||||
enum eCLogColor color = COLOR_DEFAULT;
|
||||
switch (severity) {
|
||||
case CLG_SEVERITY_INFO:
|
||||
color = COLOR_DEFAULT;
|
||||
break;
|
||||
case CLG_SEVERITY_WARN:
|
||||
color = COLOR_YELLOW;
|
||||
break;
|
||||
case CLG_SEVERITY_ERROR:
|
||||
case CLG_SEVERITY_FATAL:
|
||||
color = COLOR_RED;
|
||||
break;
|
||||
default:
|
||||
/* should never get here. */
|
||||
assert(false);
|
||||
}
|
||||
return color;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Context Type Access
|
||||
* \{ */
|
||||
|
||||
/**
|
||||
* Filter the indentifier based on very basic globbing.
|
||||
* - `foo` exact match of `foo`.
|
||||
* - `foo.bar` exact match for `foo.bar`
|
||||
* - `foo.*` match for `foo` & `foo.bar` & `foo.bar.baz`
|
||||
* - `*` matches everything.
|
||||
*/
|
||||
static bool clg_ctx_filter_check(CLogContext *ctx, const char *identifier)
|
||||
{
|
||||
const CLG_IDFilter *flt = ctx->filters;
|
||||
const int identifier_len = strlen(identifier);
|
||||
while (flt != NULL) {
|
||||
const int len = strlen(flt->match);
|
||||
if (STREQ(flt->match, "*") ||
|
||||
((len == identifier_len) && (STREQ(identifier, flt->match))))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if ((len >= 2) && (STREQLEN(".*", &flt->match[len - 2], 2))) {
|
||||
if (((identifier_len == len - 2) && STREQLEN(identifier, flt->match, len - 2)) ||
|
||||
((identifier_len >= len - 1) && STREQLEN(identifier, flt->match, len - 1)))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* \note This should never be called per logging call.
|
||||
* Searching is only to get an initial handle.
|
||||
*/
|
||||
static CLG_LogType *clg_ctx_type_find_by_name(CLogContext *ctx, const char *identifier)
|
||||
{
|
||||
for (CLG_LogType *ty = ctx->types; ty; ty = ty->next) {
|
||||
if (STREQ(identifier, ty->identifier)) {
|
||||
return ty;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static CLG_LogType *clg_ctx_type_register(CLogContext *ctx, const char *identifier)
|
||||
{
|
||||
assert(clg_ctx_type_find_by_name(ctx, identifier) == NULL);
|
||||
CLG_LogType *ty = MEM_callocN(sizeof(*ty), __func__);
|
||||
ty->next = ctx->types;
|
||||
ctx->types = ty;
|
||||
strncpy(ty->identifier, identifier, sizeof(ty->identifier) - 1);
|
||||
ty->ctx = ctx;
|
||||
ty->level = ctx->default_type.level;
|
||||
|
||||
if (clg_ctx_filter_check(ctx, ty->identifier)) {
|
||||
ty->flag |= CLG_FLAG_USE;
|
||||
}
|
||||
return ty;
|
||||
}
|
||||
|
||||
static void clg_ctx_fatal_action(CLogContext *ctx, FILE *file_handle)
|
||||
{
|
||||
if (ctx->callbacks.fatal_fn != NULL) {
|
||||
ctx->callbacks.fatal_fn(file_handle);
|
||||
}
|
||||
fflush(file_handle);
|
||||
abort();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Logging API
|
||||
* \{ */
|
||||
|
||||
static void write_severity(CLogStringBuf *cstr, enum CLG_Severity severity, bool use_color)
|
||||
{
|
||||
assert((unsigned int)severity < CLG_SEVERITY_LEN);
|
||||
if (use_color) {
|
||||
enum eCLogColor color = clg_severity_to_color(severity);
|
||||
clg_str_append(cstr, clg_color_table[color]);
|
||||
clg_str_append(cstr, clg_severity_as_text(severity));
|
||||
clg_str_append(cstr, clg_color_table[COLOR_RESET]);
|
||||
}
|
||||
else {
|
||||
clg_str_append(cstr, clg_severity_as_text(severity));
|
||||
}
|
||||
}
|
||||
|
||||
static void write_type(CLogStringBuf *cstr, CLG_LogType *lg)
|
||||
{
|
||||
clg_str_append(cstr, " (");
|
||||
clg_str_append(cstr, lg->identifier);
|
||||
clg_str_append(cstr, "): ");
|
||||
}
|
||||
|
||||
static void write_file_line_fn(CLogStringBuf *cstr, const char *file_line, const char *fn)
|
||||
{
|
||||
clg_str_append(cstr, file_line);
|
||||
clg_str_append(cstr, " ");
|
||||
clg_str_append(cstr, fn);
|
||||
clg_str_append(cstr, ": ");
|
||||
}
|
||||
|
||||
void CLG_log_str(
|
||||
CLG_LogType *lg, enum CLG_Severity severity, const char *file_line, const char *fn,
|
||||
const char *message)
|
||||
{
|
||||
CLogStringBuf cstr;
|
||||
char cstr_stack_buf[CLOG_BUF_LEN_INIT];
|
||||
clg_str_init(&cstr, cstr_stack_buf, sizeof(cstr_stack_buf));
|
||||
|
||||
write_severity(&cstr, severity, lg->ctx->use_color);
|
||||
write_type(&cstr, lg);
|
||||
|
||||
{
|
||||
write_file_line_fn(&cstr, file_line, fn);
|
||||
clg_str_append(&cstr, message);
|
||||
}
|
||||
clg_str_append(&cstr, "\n");
|
||||
|
||||
/* could be optional */
|
||||
fwrite(cstr.data, cstr.len, 1, lg->ctx->output);
|
||||
fflush(lg->ctx->output);
|
||||
|
||||
clg_str_free(&cstr);
|
||||
|
||||
if (severity == CLG_SEVERITY_FATAL) {
|
||||
clg_ctx_fatal_action(lg->ctx, lg->ctx->output);
|
||||
}
|
||||
}
|
||||
|
||||
void CLG_logf(
|
||||
CLG_LogType *lg, enum CLG_Severity severity, const char *file_line, const char *fn,
|
||||
const char *fmt, ...)
|
||||
{
|
||||
CLogStringBuf cstr;
|
||||
char cstr_stack_buf[CLOG_BUF_LEN_INIT];
|
||||
clg_str_init(&cstr, cstr_stack_buf, sizeof(cstr_stack_buf));
|
||||
|
||||
// FILE *fh = lg->ctx->output;
|
||||
write_severity(&cstr, severity, lg->ctx->use_color);
|
||||
write_type(&cstr, lg);
|
||||
|
||||
{
|
||||
write_file_line_fn(&cstr, file_line, fn);
|
||||
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
clg_str_vappendf(&cstr, fmt, ap);
|
||||
va_end(ap);
|
||||
}
|
||||
clg_str_append(&cstr, "\n");
|
||||
|
||||
/* could be optional */
|
||||
fwrite(cstr.data, cstr.len, 1, lg->ctx->output);
|
||||
fflush(lg->ctx->output);
|
||||
|
||||
if (severity == CLG_SEVERITY_FATAL) {
|
||||
clg_ctx_fatal_action(lg->ctx, lg->ctx->output);
|
||||
}
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Logging Context API
|
||||
* \{ */
|
||||
|
||||
static void CLG_ctx_output_set(CLogContext *ctx, void *file_handle)
|
||||
{
|
||||
ctx->output = file_handle;
|
||||
#if defined(__unix__)
|
||||
ctx->use_color = isatty(fileno(file_handle));
|
||||
#endif
|
||||
}
|
||||
|
||||
/** Action on fatal severity. */
|
||||
static void CLG_ctx_fatal_fn_set(CLogContext *ctx, void (*fatal_fn)(void *file_handle))
|
||||
{
|
||||
ctx->callbacks.fatal_fn = fatal_fn;
|
||||
}
|
||||
|
||||
static void CLG_ctx_type_filter(CLogContext *ctx, const char *type_match, int type_match_len)
|
||||
{
|
||||
CLG_IDFilter *flt = MEM_callocN(sizeof(*flt) + (type_match_len + 1), __func__);
|
||||
flt->next = ctx->filters;
|
||||
ctx->filters = flt;
|
||||
memcpy(flt->match, type_match, type_match_len);
|
||||
/* no need to null terminate since we calloc'd */
|
||||
}
|
||||
|
||||
static CLogContext *CLG_ctx_init(void)
|
||||
{
|
||||
CLogContext *ctx = MEM_callocN(sizeof(*ctx), __func__);
|
||||
ctx->use_color = true;
|
||||
ctx->default_type.level = 1;
|
||||
CLG_ctx_output_set(ctx, stdout);
|
||||
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static void CLG_ctx_free(CLogContext *ctx)
|
||||
{
|
||||
while (ctx->types != NULL) {
|
||||
CLG_LogType *item = ctx->types;
|
||||
ctx->types = item->next;
|
||||
MEM_freeN(item);
|
||||
}
|
||||
while (ctx->filters != NULL) {
|
||||
CLG_IDFilter *item = ctx->filters;
|
||||
ctx->filters = item->next;
|
||||
MEM_freeN(item);
|
||||
}
|
||||
MEM_freeN(ctx);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Public Logging API
|
||||
*
|
||||
* Currently uses global context.
|
||||
* \{ */
|
||||
|
||||
/* We could support multiple at once, for now this seems not needed. */
|
||||
struct CLogContext *g_ctx = NULL;
|
||||
|
||||
void CLG_init(void)
|
||||
{
|
||||
g_ctx = CLG_ctx_init();
|
||||
|
||||
clg_color_table_init(g_ctx->use_color);
|
||||
}
|
||||
|
||||
void CLG_exit(void)
|
||||
{
|
||||
CLG_ctx_free(g_ctx);
|
||||
}
|
||||
|
||||
void CLG_output_set(void *file_handle)
|
||||
{
|
||||
CLG_ctx_output_set(g_ctx, file_handle);
|
||||
}
|
||||
|
||||
void CLG_fatal_fn_set(void (*fatal_fn)(void *file_handle))
|
||||
{
|
||||
CLG_ctx_fatal_fn_set(g_ctx, fatal_fn);
|
||||
}
|
||||
|
||||
void CLG_type_filter(const char *type_match, int type_match_len)
|
||||
{
|
||||
CLG_ctx_type_filter(g_ctx, type_match, type_match_len);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Logging Reference API
|
||||
* Use to avoid lookups each time.
|
||||
* \{ */
|
||||
|
||||
void CLG_logref_init(CLG_LogRef *clg_ref)
|
||||
{
|
||||
assert(clg_ref->type == NULL);
|
||||
CLG_LogType *clg_ty = clg_ctx_type_find_by_name(g_ctx, clg_ref->identifier);
|
||||
clg_ref->type = clg_ty ? clg_ty : clg_ctx_type_register(g_ctx, clg_ref->identifier);
|
||||
}
|
||||
|
||||
/** \} */
|
@ -2668,8 +2668,8 @@ class VIEW3D_MT_edit_mesh_vertices(Menu):
|
||||
layout.operator("object.vertex_parent_set")
|
||||
|
||||
|
||||
class VIEW3D_MT_edit_mesh_edges_data(Menu):
|
||||
bl_label = "Edge Data"
|
||||
class VIEW3D_MT_edit_mesh_edges(Menu):
|
||||
bl_label = "Edges"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
@ -2678,6 +2678,13 @@ class VIEW3D_MT_edit_mesh_edges_data(Menu):
|
||||
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
|
||||
layout.operator("mesh.edge_face_add")
|
||||
layout.operator("mesh.subdivide")
|
||||
layout.operator("mesh.subdivide_edgering")
|
||||
layout.operator("mesh.unsubdivide")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("transform.edge_crease")
|
||||
layout.operator("transform.edge_bevelweight")
|
||||
|
||||
@ -2698,26 +2705,6 @@ class VIEW3D_MT_edit_mesh_edges_data(Menu):
|
||||
layout.operator("mesh.mark_freestyle_edge", text="Clear Freestyle Edge").clear = True
|
||||
layout.separator()
|
||||
|
||||
|
||||
class VIEW3D_MT_edit_mesh_edges(Menu):
|
||||
bl_label = "Edges"
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.operator_context = 'INVOKE_REGION_WIN'
|
||||
|
||||
layout.operator("mesh.edge_face_add")
|
||||
layout.operator("mesh.subdivide")
|
||||
layout.operator("mesh.subdivide_edgering")
|
||||
layout.operator("mesh.unsubdivide")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.menu("VIEW3D_MT_edit_mesh_edges_data")
|
||||
|
||||
layout.separator()
|
||||
|
||||
layout.operator("mesh.edge_rotate", text="Rotate Edge CW").use_ccw = False
|
||||
layout.operator("mesh.edge_rotate", text="Rotate Edge CCW").use_ccw = True
|
||||
|
||||
@ -4124,7 +4111,6 @@ classes = (
|
||||
VIEW3D_MT_edit_mesh_extrude,
|
||||
VIEW3D_MT_edit_mesh_vertices,
|
||||
VIEW3D_MT_edit_mesh_edges,
|
||||
VIEW3D_MT_edit_mesh_edges_data,
|
||||
VIEW3D_MT_edit_mesh_faces,
|
||||
VIEW3D_MT_edit_mesh_normals,
|
||||
VIEW3D_MT_edit_mesh_clean,
|
||||
|
@ -80,6 +80,13 @@ typedef struct Global {
|
||||
* however this is now only used for runtime options */
|
||||
int f;
|
||||
|
||||
struct {
|
||||
/* Logging vars (different loggers may use). */
|
||||
int level;
|
||||
/* FILE handle or use stderr (we own this so close when done). */
|
||||
void *file;
|
||||
} log;
|
||||
|
||||
/* debug flag, G_DEBUG, G_DEBUG_PYTHON & friends, set python or command line args */
|
||||
int debug;
|
||||
|
||||
|
@ -48,6 +48,7 @@ set(INC
|
||||
../../../intern/mikktspace
|
||||
../../../intern/smoke/extern
|
||||
../../../intern/atomic
|
||||
../../../intern/clog
|
||||
../../../intern/libmv
|
||||
../../../extern/curve_fit_nd
|
||||
)
|
||||
|
@ -83,6 +83,10 @@ void BKE_blender_free(void)
|
||||
BKE_main_free(G.main);
|
||||
G.main = NULL;
|
||||
|
||||
if (G.log.file != NULL) {
|
||||
fclose(G.log.file);
|
||||
}
|
||||
|
||||
BKE_spacetypes_free(); /* after free main, it uses space callbacks */
|
||||
|
||||
IMB_exit();
|
||||
@ -130,6 +134,8 @@ void BKE_blender_globals_init(void)
|
||||
#else
|
||||
G.f &= ~G_SCRIPT_AUTOEXEC;
|
||||
#endif
|
||||
|
||||
G.log.level = 1;
|
||||
}
|
||||
|
||||
void BKE_blender_globals_clear(void)
|
||||
|
@ -252,9 +252,6 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
|
||||
Depsgraph *graph,
|
||||
const unsigned int layers)
|
||||
{
|
||||
/* Set time for the current graph evaluation context. */
|
||||
TimeSourceDepsNode *time_src = graph->find_time_source();
|
||||
eval_ctx->ctime = time_src->cfra;
|
||||
/* Nothing to update, early out. */
|
||||
if (BLI_gset_len(graph->entry_tags) == 0) {
|
||||
return;
|
||||
@ -265,6 +262,9 @@ void deg_evaluate_on_refresh(EvaluationContext *eval_ctx,
|
||||
graph->layers);
|
||||
const bool do_time_debug = ((G.debug & G_DEBUG_DEPSGRAPH_TIME) != 0);
|
||||
const double start_time = do_time_debug ? PIL_check_seconds_timer() : 0;
|
||||
/* Set time for the current graph evaluation context. */
|
||||
TimeSourceDepsNode *time_src = graph->find_time_source();
|
||||
eval_ctx->ctime = time_src->cfra;
|
||||
/* Set up evaluation context for depsgraph itself. */
|
||||
DepsgraphEvalState state;
|
||||
state.eval_ctx = eval_ctx;
|
||||
|
@ -30,6 +30,7 @@ set(INC
|
||||
../../makesrna
|
||||
../../windowmanager
|
||||
../../../../intern/guardedalloc
|
||||
../../../../intern/clog
|
||||
../../../../intern/glew-mx
|
||||
)
|
||||
|
||||
|
@ -689,8 +689,6 @@ PyDoc_STRVAR(euler_doc,
|
||||
"\n"
|
||||
" This object gives access to Eulers in Blender.\n"
|
||||
"\n"
|
||||
" .. seealso:: `Euler angles <https://en.wikipedia.org/wiki/Euler_angles>`__ on Wikipedia.\n"
|
||||
"\n"
|
||||
" :param angles: Three angles, in radians.\n"
|
||||
" :type angles: 3d vector\n"
|
||||
" :param order: Optional order of the angles, a permutation of ``XYZ``.\n"
|
||||
|
@ -39,6 +39,7 @@ set(INC
|
||||
../nodes
|
||||
../render/extern/include
|
||||
../../gameengine/BlenderRoutines
|
||||
../../../intern/clog
|
||||
../../../intern/ghost
|
||||
../../../intern/guardedalloc
|
||||
../../../intern/glew-mx
|
||||
|
@ -719,6 +719,14 @@ typedef struct RecentFile {
|
||||
char *filepath;
|
||||
} RecentFile;
|
||||
|
||||
/* Logging */
|
||||
struct CLG_LogRef;
|
||||
/* wm_init_exit.c */
|
||||
extern struct CLG_LogRef *WM_LOG_OPERATORS;
|
||||
extern struct CLG_LogRef *WM_LOG_HANDLERS;
|
||||
extern struct CLG_LogRef *WM_LOG_EVENTS;
|
||||
extern struct CLG_LogRef *WM_LOG_KEYMAPS;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -43,6 +43,8 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "GHOST_C-api.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
@ -353,13 +355,11 @@ void wm_event_do_notifiers(bContext *C)
|
||||
|
||||
|
||||
ED_screen_set(C, note->reference); // XXX hrms, think this over!
|
||||
if (G.debug & G_DEBUG_EVENTS)
|
||||
printf("%s: screen set %p\n", __func__, note->reference);
|
||||
CLOG_INFO(WM_LOG_EVENTS, 1, "screen set %p", note->reference);
|
||||
}
|
||||
else if (note->data == ND_SCREENDELETE) {
|
||||
ED_screen_delete(C, note->reference); // XXX hrms, think this over!
|
||||
if (G.debug & G_DEBUG_EVENTS)
|
||||
printf("%s: screen delete %p\n", __func__, note->reference);
|
||||
CLOG_INFO(WM_LOG_EVENTS, 1, "screen delete %p", note->reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -545,14 +545,6 @@ int WM_operator_poll_context(bContext *C, wmOperatorType *ot, short context)
|
||||
return wm_operator_call_internal(C, ot, NULL, NULL, context, true);
|
||||
}
|
||||
|
||||
static void wm_operator_print(bContext *C, wmOperator *op)
|
||||
{
|
||||
/* context is needed for enum function */
|
||||
char *buf = WM_operator_pystring(C, op, false, true);
|
||||
puts(buf);
|
||||
MEM_freeN(buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the active region for this space from the context.
|
||||
*
|
||||
@ -711,12 +703,9 @@ static void wm_operator_reports(bContext *C, wmOperator *op, int retval, bool ca
|
||||
CTX_wm_region_set(C, ar_prev);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (retval & OPERATOR_FINISHED) {
|
||||
if (G.debug & G_DEBUG_WM) {
|
||||
/* todo - this print may double up, might want to check more flags then the FINISHED */
|
||||
wm_operator_print(C, op);
|
||||
}
|
||||
CLOG_STR_INFO_N(WM_LOG_OPERATORS, 1, WM_operator_pystring(C, op, false, true));
|
||||
|
||||
if (caller_owns_reports == false) {
|
||||
BKE_reports_print(op->reports, RPT_DEBUG); /* print out reports to console. */
|
||||
@ -1041,9 +1030,7 @@ bool WM_operator_last_properties_init(wmOperator *op)
|
||||
IDProperty *replaceprops = IDP_New(IDP_GROUP, &val, "wmOperatorProperties");
|
||||
PropertyRNA *iterprop;
|
||||
|
||||
if (G.debug & G_DEBUG_WM) {
|
||||
printf("%s: loading previous properties for '%s'\n", __func__, op->type->idname);
|
||||
}
|
||||
CLOG_INFO(WM_LOG_OPERATORS, 1, "loading previous properties for '%s'", op->type->idname);
|
||||
|
||||
iterprop = RNA_struct_iterator_property(op->type->srna);
|
||||
|
||||
@ -1088,9 +1075,7 @@ bool WM_operator_last_properties_store(wmOperator *op)
|
||||
}
|
||||
|
||||
if (op->properties) {
|
||||
if (G.debug & G_DEBUG_WM) {
|
||||
printf("%s: storing properties for '%s'\n", __func__, op->type->idname);
|
||||
}
|
||||
CLOG_INFO(WM_LOG_OPERATORS, 1, "storing properties for '%s'", op->type->idname);
|
||||
op->type->last_properties = IDP_CopyProperty(op->properties);
|
||||
return true;
|
||||
}
|
||||
@ -1140,11 +1125,12 @@ static int wm_operator_invoke(
|
||||
WM_operator_last_properties_init(op);
|
||||
}
|
||||
|
||||
if ((G.debug & G_DEBUG_HANDLERS) && ((event == NULL) || (event->type != MOUSEMOVE))) {
|
||||
printf("%s: handle evt %d win %d op %s\n",
|
||||
__func__, event ? event->type : 0, CTX_wm_screen(C)->subwinactive, ot->idname);
|
||||
if ((event == NULL) || (event->type != MOUSEMOVE)) {
|
||||
CLOG_INFO(WM_LOG_HANDLERS, 2,
|
||||
"handle evt %d win %d op %s",
|
||||
event ? event->type : 0, CTX_wm_screen(C)->subwinactive, ot->idname);
|
||||
}
|
||||
|
||||
|
||||
if (op->type->invoke && event) {
|
||||
wm_region_mouse_co(C, event);
|
||||
|
||||
@ -1169,9 +1155,9 @@ static int wm_operator_invoke(
|
||||
}
|
||||
else {
|
||||
/* debug, important to leave a while, should never happen */
|
||||
printf("%s: invalid operator call '%s'\n", __func__, ot->idname);
|
||||
CLOG_ERROR(WM_LOG_OPERATORS, "invalid operator call '%s'", op->idname);
|
||||
}
|
||||
|
||||
|
||||
/* Note, if the report is given as an argument then assume the caller will deal with displaying them
|
||||
* currently python only uses this */
|
||||
if (!(retval & OPERATOR_HANDLED) && (retval & (OPERATOR_FINISHED | OPERATOR_CANCELLED))) {
|
||||
@ -1446,8 +1432,10 @@ int WM_operator_call_py(
|
||||
if (is_undo && op->type->flag & OPTYPE_UNDO && CTX_wm_manager(C) == wm)
|
||||
wm->op_undo_depth--;
|
||||
}
|
||||
else
|
||||
printf("error \"%s\" operator has no exec function, python cannot call it\n", op->type->name);
|
||||
else {
|
||||
CLOG_WARN(WM_LOG_OPERATORS, "\"%s\" operator has no exec function, Python cannot call it", op->type->name);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* not especially nice using undo depth here, its used so py never
|
||||
@ -1491,8 +1479,9 @@ static void wm_handler_op_context(bContext *C, wmEventHandler *handler, const wm
|
||||
if (sa == NULL) {
|
||||
/* when changing screen layouts with running modal handlers (like render display), this
|
||||
* is not an error to print */
|
||||
if (handler->op == NULL)
|
||||
printf("internal error: handler (%s) has invalid area\n", handler->op->type->idname);
|
||||
if (handler->op == NULL) {
|
||||
CLOG_ERROR(WM_LOG_HANDLERS, "internal error: handler (%s) has invalid area", handler->op->type->idname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ARegion *ar;
|
||||
@ -1805,10 +1794,9 @@ static int wm_handler_operator_call(bContext *C, ListBase *handlers, wmEventHand
|
||||
//retval &= ~OPERATOR_PASS_THROUGH;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
else {
|
||||
printf("%s: error '%s' missing modal\n", __func__, op->idname);
|
||||
CLOG_ERROR(WM_LOG_HANDLERS, "missing modal '%s'", op->idname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
@ -2099,19 +2087,15 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers
|
||||
action |= wm_handler_operator_call(C, handlers, handler, event, kmi->ptr);
|
||||
if (action & WM_HANDLER_BREAK) {
|
||||
/* not always_pass here, it denotes removed handler */
|
||||
|
||||
if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS))
|
||||
printf("%s: handled! '%s'\n", __func__, kmi->idname);
|
||||
|
||||
CLOG_INFO(WM_LOG_HANDLERS, 2, "handled! '%s'", kmi->idname);
|
||||
break;
|
||||
}
|
||||
else {
|
||||
if (action & WM_HANDLER_HANDLED) {
|
||||
if (G.debug & (G_DEBUG_EVENTS | G_DEBUG_HANDLERS))
|
||||
printf("%s: handled - and pass on! '%s'\n", __func__, kmi->idname);
|
||||
CLOG_INFO(WM_LOG_HANDLERS, 2, "handled - and pass on! '%s'", kmi->idname);
|
||||
}
|
||||
else {
|
||||
PRINT("%s: un-handled '%s'\n", __func__, kmi->idname);
|
||||
CLOG_INFO(WM_LOG_HANDLERS, 2, "un-handled '%s'", kmi->idname);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -2237,10 +2221,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
|
||||
{
|
||||
event->val = KM_CLICK;
|
||||
|
||||
if (G.debug & (G_DEBUG_HANDLERS)) {
|
||||
printf("%s: handling CLICK\n", __func__);
|
||||
}
|
||||
|
||||
CLOG_INFO(WM_LOG_HANDLERS, 1, "handling CLICK");
|
||||
|
||||
action |= wm_handlers_do_intern(C, event, handlers);
|
||||
|
||||
event->val = KM_RELEASE;
|
||||
@ -2461,13 +2443,14 @@ void wm_event_do_handlers(bContext *C)
|
||||
|
||||
if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
|
||||
printf("\n%s: Handling event\n", __func__);
|
||||
|
||||
WM_event_print(event);
|
||||
}
|
||||
|
||||
/* take care of pie event filter */
|
||||
if (wm_event_pie_filter(win, event)) {
|
||||
if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS) && !ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
|
||||
printf("\n%s: event filtered due to pie button pressed\n", __func__);
|
||||
if (!ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) {
|
||||
CLOG_INFO(WM_LOG_HANDLERS, 1, "event filtered due to pie button pressed");
|
||||
}
|
||||
BLI_remlink(&win->queue, event);
|
||||
wm_event_free(event);
|
||||
@ -2751,7 +2734,7 @@ wmEventHandler *WM_event_add_keymap_handler(ListBase *handlers, wmKeyMap *keymap
|
||||
wmEventHandler *handler;
|
||||
|
||||
if (!keymap) {
|
||||
printf("%s: called with NULL keymap\n", __func__);
|
||||
CLOG_WARN(WM_LOG_HANDLERS, "called with NULL keymap");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -3372,8 +3355,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
|
||||
|
||||
/* double click test */
|
||||
if (wm_event_is_double_click(&event, evt)) {
|
||||
if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS))
|
||||
printf("%s Send double click\n", __func__);
|
||||
CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click");
|
||||
event.val = KM_DBL_CLICK;
|
||||
}
|
||||
if (event.val == KM_PRESS) {
|
||||
@ -3427,7 +3409,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
|
||||
|
||||
/* ghost should do this already for key up */
|
||||
if (event.utf8_buf[0]) {
|
||||
printf("%s: ghost on your platform is misbehaving, utf8 events on key up!\n", __func__);
|
||||
CLOG_ERROR(WM_LOG_EVENTS, "ghost on your platform is misbehaving, utf8 events on key up!");
|
||||
}
|
||||
event.utf8_buf[0] = '\0';
|
||||
}
|
||||
@ -3440,8 +3422,9 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
|
||||
|
||||
if (event.utf8_buf[0]) {
|
||||
if (BLI_str_utf8_size(event.utf8_buf) == -1) {
|
||||
printf("%s: ghost detected an invalid unicode character '%d'!\n",
|
||||
__func__, (int)(unsigned char)event.utf8_buf[0]);
|
||||
CLOG_ERROR(WM_LOG_EVENTS,
|
||||
"ghost detected an invalid unicode character '%d'",
|
||||
(int)(unsigned char)event.utf8_buf[0]);
|
||||
event.utf8_buf[0] = '\0';
|
||||
}
|
||||
}
|
||||
@ -3490,8 +3473,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
|
||||
/* double click test */
|
||||
/* if previous event was same type, and previous was release, and now it presses... */
|
||||
if (wm_event_is_double_click(&event, evt)) {
|
||||
if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS))
|
||||
printf("%s Send double click\n", __func__);
|
||||
CLOG_INFO(WM_LOG_HANDLERS, 1, "Send double click");
|
||||
evt->val = event.val = KM_DBL_CLICK;
|
||||
}
|
||||
|
||||
@ -3561,9 +3543,7 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, int U
|
||||
attach_ndof_data(&event, customdata);
|
||||
wm_event_add(win, &event);
|
||||
|
||||
if (G.debug & (G_DEBUG_HANDLERS | G_DEBUG_EVENTS))
|
||||
printf("%s sending NDOF_MOTION, prev = %d %d\n", __func__, event.x, event.y);
|
||||
|
||||
CLOG_INFO(WM_LOG_HANDLERS, 1, "sending NDOF_MOTION, prev = %d %d", event.x, event.y);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -40,6 +40,8 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "DNA_genfile.h"
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_userdef_types.h"
|
||||
@ -127,6 +129,11 @@
|
||||
# include "BKE_subsurf.h"
|
||||
#endif
|
||||
|
||||
CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_OPERATORS, "wm.operator");
|
||||
CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_HANDLERS, "wm.handler");
|
||||
CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_EVENTS, "wm.event");
|
||||
CLG_LOGREF_DECLARE_GLOBAL(WM_LOG_KEYMAPS, "wm.keymap");
|
||||
|
||||
static void wm_init_reports(bContext *C)
|
||||
{
|
||||
ReportList *reports = CTX_wm_reports(C);
|
||||
@ -613,6 +620,8 @@ void WM_exit_ext(bContext *C, const bool do_python)
|
||||
* see also T50676. */
|
||||
BKE_sound_exit();
|
||||
|
||||
CLG_exit();
|
||||
|
||||
BKE_blender_atexit();
|
||||
|
||||
if (MEM_get_memory_blocks_in_use() != 0) {
|
||||
|
@ -1,4 +1,5 @@
|
||||
/*
|
||||
*
|
||||
* ***** BEGIN GPL LICENSE BLOCK *****
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
@ -39,6 +40,7 @@
|
||||
#include "DNA_windowmanager_types.h"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "BLI_blenlib.h"
|
||||
#include "BLI_utildefines.h"
|
||||
@ -886,11 +888,13 @@ wmKeyMapItem *WM_modalkeymap_find_propvalue(wmKeyMap *km, const int propvalue)
|
||||
void WM_modalkeymap_assign(wmKeyMap *km, const char *opname)
|
||||
{
|
||||
wmOperatorType *ot = WM_operatortype_find(opname, 0);
|
||||
|
||||
if (ot)
|
||||
|
||||
if (ot) {
|
||||
ot->modalkeymap = km;
|
||||
else
|
||||
printf("error: modalkeymap_assign, unknown operator %s\n", opname);
|
||||
}
|
||||
else {
|
||||
CLOG_ERROR(WM_LOG_KEYMAPS, "unknown operator '%s'", opname);
|
||||
}
|
||||
}
|
||||
|
||||
static void wm_user_modal_keymap_set_items(wmWindowManager *wm, wmKeyMap *km)
|
||||
|
@ -46,6 +46,8 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_object_types.h"
|
||||
#include "DNA_screen_types.h"
|
||||
@ -139,12 +141,12 @@ wmOperatorType *WM_operatortype_find(const char *idname, bool quiet)
|
||||
}
|
||||
|
||||
if (!quiet) {
|
||||
printf("search for unknown operator '%s', '%s'\n", idname_bl, idname);
|
||||
CLOG_INFO(WM_LOG_OPERATORS, 0, "search for unknown operator '%s', '%s'\n", idname_bl, idname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!quiet) {
|
||||
printf("search for empty operator\n");
|
||||
CLOG_INFO(WM_LOG_OPERATORS, 0, "search for empty operator");
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,8 +172,7 @@ void WM_operatortype_append(void (*opfunc)(wmOperatorType *))
|
||||
opfunc(ot);
|
||||
|
||||
if (ot->name == NULL) {
|
||||
fprintf(stderr, "ERROR: Operator %s has no name property!\n", ot->idname);
|
||||
ot->name = N_("Dummy Name");
|
||||
CLOG_ERROR(WM_LOG_OPERATORS, "Operator '%s' has no name property", ot->idname);
|
||||
}
|
||||
|
||||
/* XXX All ops should have a description but for now allow them not to. */
|
||||
@ -255,7 +256,7 @@ static int wm_macro_exec(bContext *C, wmOperator *op)
|
||||
}
|
||||
}
|
||||
else {
|
||||
printf("%s: '%s' cant exec macro\n", __func__, opm->type->idname);
|
||||
CLOG_WARN(WM_LOG_OPERATORS, "'%s' cant exec macro", opm->type->idname);
|
||||
}
|
||||
}
|
||||
|
||||
@ -300,8 +301,9 @@ static int wm_macro_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
wmOperator *opm = op->opm;
|
||||
int retval = OPERATOR_FINISHED;
|
||||
|
||||
if (opm == NULL)
|
||||
printf("%s: macro error, calling NULL modal()\n", __func__);
|
||||
if (opm == NULL) {
|
||||
CLOG_ERROR(WM_LOG_OPERATORS, "macro error, calling NULL modal()");
|
||||
}
|
||||
else {
|
||||
retval = opm->type->modal(C, opm, event);
|
||||
OPERATOR_RETVAL_CHECK(retval);
|
||||
@ -375,7 +377,7 @@ wmOperatorType *WM_operatortype_append_macro(const char *idname, const char *nam
|
||||
const char *i18n_context;
|
||||
|
||||
if (WM_operatortype_find(idname, true)) {
|
||||
printf("%s: macro error: operator %s exists\n", __func__, idname);
|
||||
CLOG_ERROR(WM_LOG_OPERATORS, "operator %s exists, cannot create macro", idname);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1135,11 +1137,14 @@ int WM_menu_invoke_ex(bContext *C, wmOperator *op, int opcontext)
|
||||
uiLayout *layout;
|
||||
|
||||
if (prop == NULL) {
|
||||
printf("%s: %s has no enum property set\n", __func__, op->type->idname);
|
||||
CLOG_ERROR(WM_LOG_OPERATORS,
|
||||
"'%s' has no enum property set",
|
||||
op->type->idname);
|
||||
}
|
||||
else if (RNA_property_type(prop) != PROP_ENUM) {
|
||||
printf("%s: %s \"%s\" is not an enum property\n",
|
||||
__func__, op->type->idname, RNA_property_identifier(prop));
|
||||
CLOG_ERROR(WM_LOG_OPERATORS,
|
||||
"'%s', '%s' is not an enum property",
|
||||
op->type->idname, RNA_property_identifier(prop));
|
||||
}
|
||||
else if (RNA_property_is_set(op->ptr, prop)) {
|
||||
const int retval = op->type->exec(C, op);
|
||||
@ -1827,8 +1832,9 @@ static uiBlock *wm_block_create_splash(bContext *C, ARegion *ar, void *UNUSED(ar
|
||||
memcpy(ibuf->rect, ibuf_template->rect, ibuf_template->x * ibuf_template->y * sizeof(char[4]));
|
||||
}
|
||||
else {
|
||||
printf("Splash expected %dx%d found %dx%d, ignoring: %s\n",
|
||||
x_expect, y_expect, ibuf_template->x, ibuf_template->y, splash_filepath);
|
||||
CLOG_ERROR(WM_LOG_OPERATORS,
|
||||
"Splash expected %dx%d found %dx%d, ignoring: %s\n",
|
||||
x_expect, y_expect, ibuf_template->x, ibuf_template->y, splash_filepath);
|
||||
}
|
||||
IMB_freeImBuf(ibuf_template);
|
||||
}
|
||||
|
@ -26,6 +26,7 @@
|
||||
setup_libdirs()
|
||||
|
||||
blender_include_dirs(
|
||||
../../intern/clog
|
||||
../../intern/guardedalloc
|
||||
../../intern/glew-mx
|
||||
../blender/blenlib
|
||||
|
@ -42,6 +42,8 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#include "DNA_genfile.h"
|
||||
|
||||
#include "BLI_args.h"
|
||||
@ -49,6 +51,7 @@
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_callbacks.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_system.h"
|
||||
|
||||
/* mostly init functions */
|
||||
#include "BKE_appdir.h"
|
||||
@ -180,6 +183,11 @@ static void callback_main_atexit(void *user_data)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void callback_clg_fatal(void *fp)
|
||||
{
|
||||
BLI_system_backtrace(fp);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
|
||||
@ -304,6 +312,10 @@ int main(
|
||||
sdlewInit();
|
||||
#endif
|
||||
|
||||
/* Initialize logging */
|
||||
CLG_init();
|
||||
CLG_fatal_fn_set(callback_clg_fatal);
|
||||
|
||||
C = CTX_create();
|
||||
|
||||
#ifdef WITH_PYTHON_MODULE
|
||||
|
@ -30,6 +30,8 @@
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "CLG_log.h"
|
||||
|
||||
#ifdef WIN32
|
||||
# include "BLI_winstuff.h"
|
||||
#endif
|
||||
@ -529,6 +531,11 @@ static int arg_handle_print_help(int UNUSED(argc), const char **UNUSED(argv), vo
|
||||
BLI_argsPrintArgDoc(ba, "--python-exit-code");
|
||||
BLI_argsPrintArgDoc(ba, "--addons");
|
||||
|
||||
printf("\n");
|
||||
printf("Logging Options:\n");
|
||||
BLI_argsPrintArgDoc(ba, "--log");
|
||||
BLI_argsPrintArgDoc(ba, "--log-level");
|
||||
BLI_argsPrintArgDoc(ba, "--log-file");
|
||||
|
||||
printf("\n");
|
||||
printf("Debug Options:\n");
|
||||
@ -704,6 +711,88 @@ static int arg_handle_background_mode_set(int UNUSED(argc), const char **UNUSED(
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char arg_handle_log_level_set_doc[] =
|
||||
"\n\tSet the logging verbosity level (higher for more details) defaults to 1."
|
||||
;
|
||||
static int arg_handle_log_level_set(int argc, const char **argv, void *UNUSED(data))
|
||||
{
|
||||
const char *arg_id = "--log-level";
|
||||
if (argc > 1) {
|
||||
const char *err_msg = NULL;
|
||||
if (!parse_int_clamp(argv[1], NULL, 0, INT_MAX, &G.log.level, &err_msg)) {
|
||||
printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
printf("\nError: '%s' no args given.\n", arg_id);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const char arg_handle_log_file_set_doc[] =
|
||||
"\n\tSet a file to output the log to."
|
||||
;
|
||||
static int arg_handle_log_file_set(int argc, const char **argv, void *UNUSED(data))
|
||||
{
|
||||
const char *arg_id = "--log-file";
|
||||
if (argc > 1) {
|
||||
errno = 0;
|
||||
FILE *fp = BLI_fopen(argv[1], "w");
|
||||
if (fp == NULL) {
|
||||
const char *err_msg = errno ? strerror(errno) : "unknown";
|
||||
printf("\nError: %s '%s %s'.\n", err_msg, arg_id, argv[1]);
|
||||
}
|
||||
else {
|
||||
if (UNLIKELY(G.log.file != NULL)) {
|
||||
fclose(G.log.file);
|
||||
}
|
||||
G.log.file = fp;
|
||||
CLG_output_set(G.log.file);
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
printf("\nError: '%s' no args given.\n", arg_id);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const char arg_handle_log_set_doc[] =
|
||||
"\n\tEnable logging categories, taking a single comma separated argument.\n"
|
||||
"\tMultiple categories can be matched using a '.*' suffix, so '--log \"wm.*\"' logs every kind of window-manager message.\n"
|
||||
"\tUse \"*\" to log everything."
|
||||
;
|
||||
static int arg_handle_log_set(int argc, const char **argv, void *UNUSED(data))
|
||||
{
|
||||
const char *arg_id = "--log";
|
||||
if (argc > 1) {
|
||||
const char *str_step = argv[1];
|
||||
while (*str_step) {
|
||||
const char *str_step_end = strchr(str_step, ',');
|
||||
int str_step_len = str_step_end ? (str_step_end - str_step) : strlen(str_step);
|
||||
|
||||
CLG_type_filter(str_step, str_step_len);
|
||||
|
||||
if (str_step_end) {
|
||||
/* typically only be one, but don't fail on multiple.*/
|
||||
while (*str_step_end == ',') {
|
||||
str_step_end++;
|
||||
}
|
||||
str_step = str_step_end;
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
else {
|
||||
printf("\nError: '%s' no args given.\n", arg_id);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static const char arg_handle_debug_mode_set_doc[] =
|
||||
"\n"
|
||||
"\tTurn debugging on.\n"
|
||||
@ -1827,6 +1916,10 @@ void main_args_setup(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
|
||||
|
||||
BLI_argsAdd(ba, 1, "-a", NULL, CB(arg_handle_playback_mode), NULL);
|
||||
|
||||
BLI_argsAdd(ba, 1, NULL, "--log-level", CB(arg_handle_log_level_set), ba);
|
||||
BLI_argsAdd(ba, 1, NULL, "--log-file", CB(arg_handle_log_file_set), ba);
|
||||
BLI_argsAdd(ba, 1, NULL, "--log", CB(arg_handle_log_set), ba);
|
||||
|
||||
BLI_argsAdd(ba, 1, "-d", "--debug", CB(arg_handle_debug_mode_set), ba);
|
||||
|
||||
#ifdef WITH_FFMPEG
|
||||
|
Loading…
Reference in New Issue
Block a user