diff options
author | Campbell Barton <ideasman42@gmail.com> | 2018-05-05 15:27:54 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2018-05-05 15:41:25 +0300 |
commit | d3b3df037197d46b608eb38a5dbd6f1d2761ec36 (patch) | |
tree | 2fe30727f100f5f89415a25971c228ad44fc0994 /source/blender/blenkernel/intern | |
parent | d83681807e1ef39228620d10fee22003d753a050 (diff) |
IDProp API: add native C repr function
Was using Python which wasn't very efficient (even for logging).
Diffstat (limited to 'source/blender/blenkernel/intern')
-rw-r--r-- | source/blender/blenkernel/intern/idprop.c | 14 | ||||
-rw-r--r-- | source/blender/blenkernel/intern/idprop_utils.c | 251 |
2 files changed, 251 insertions, 14 deletions
diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index 5fb6dd558e0..fe00d68b4ea 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -1069,17 +1069,3 @@ void IDP_ClearProperty(IDProperty *prop) /** \} */ -/* We could write a C version, see: idprop_py_api.c */ -#ifndef WITH_PYTHON -char *IDP_reprN(IDProperty *UNUSED(prop)) -{ - return BLI_strdup("<unsupported>"); -} - -void IDP_print(IDProperty *prop) -{ - char *repr = IDP_reprN(prop); - printf("IDProperty(%p): %s\n", prop, repr); - MEM_freeN(repr); -} -#endif /* WITH_PYTHON */ diff --git a/source/blender/blenkernel/intern/idprop_utils.c b/source/blender/blenkernel/intern/idprop_utils.c new file mode 100644 index 00000000000..21005da2d97 --- /dev/null +++ b/source/blender/blenkernel/intern/idprop_utils.c @@ -0,0 +1,251 @@ +/* + * ***** 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 ***** + */ + +/** \file blender/blenkernel/intern/idprop_utils.c + * \ingroup bke + */ + +#include <stdio.h> +#include <string.h> + +#include "BLI_utildefines.h" +#include "BLI_string.h" +#include "BLI_dynstr.h" + +#include "BKE_idprop.h" +#include "BKE_idcode.h" + +#include "MEM_guardedalloc.h" + +#include "BLI_strict_flags.h" + + +/* -------------------------------------------------------------------- */ +/** \name IDProp Repr + * + * Convert an IDProperty to a string. + * + * Output should be a valid Python literal + * (with minor exceptions - float nan for eg). + * \{ */ + +struct ReprState { + void (*str_append_fn)(void *user_data, const char *str, uint str_len); + void *user_data; + /* Big enough to format any primitive type. */ + char buf[128]; +}; + +static void idp_str_append_escape(struct ReprState *state, const char *str, const uint str_len, bool quote) +{ + if (quote) { + state->str_append_fn(state->user_data, "\"", 1); + } + uint i_prev = 0, i = 0; + while (i < str_len) { + const char c = str[i]; + if (c == '"') { + if (i_prev != i) { + state->str_append_fn(state->user_data, str + i_prev, i - i_prev); + } + state->str_append_fn(state->user_data, "\\\"", 2); + i_prev = i + 1; + } + else if (c == '\\') { + if (i_prev != i) { + state->str_append_fn(state->user_data, str + i_prev, i - i_prev); + } + state->str_append_fn(state->user_data, "\\\\", 2); + i_prev = i + 1; + } + else if (c < 32) { + if (i_prev != i) { + state->str_append_fn(state->user_data, str + i_prev, i - i_prev); + } + char buf[5]; + uint len = (uint)BLI_snprintf_rlen(buf, sizeof(buf), "\\x%02x", c); + BLI_assert(len == 4); + state->str_append_fn(state->user_data, buf, len); + i_prev = i + 1; + } + i++; + } + state->str_append_fn(state->user_data, str + i_prev, i - i_prev); + if (quote) { + state->str_append_fn(state->user_data, "\"", 1); + } +} + +static void idp_repr_fn_recursive(struct ReprState *state, const IDProperty *prop) +{ + /* Note: 'strlen' will be calculated at compile time for literals. */ +#define STR_APPEND_STR(str) { \ + state->str_append_fn(state->user_data, str, (uint)strlen(str)); \ +} ((void)0) + +#define STR_APPEND_STR_QUOTE(str) { \ + idp_str_append_escape(state, str, (uint)strlen(str), true); \ +} ((void)0) + +#define STR_APPEND_FMT(format, ...) { \ + const uint len = (uint)BLI_snprintf_rlen(state->buf, sizeof(state->buf), format, __VA_ARGS__); \ + state->str_append_fn(state->user_data, state->buf, len); \ +} ((void)0) + + switch (prop->type) { + case IDP_STRING: + { + STR_APPEND_STR_QUOTE(IDP_String(prop)); + break; + } + case IDP_INT: + { + STR_APPEND_FMT("%d", IDP_Int(prop)); + break; + } + case IDP_FLOAT: + { + STR_APPEND_FMT("%g", (double)IDP_Float(prop)); + break; + } + case IDP_DOUBLE: + { + STR_APPEND_FMT("%g", IDP_Double(prop)); + break; + } + case IDP_ARRAY: + { + STR_APPEND_STR("["); + switch (prop->subtype) { + case IDP_INT: + for (const int *v = prop->data.pointer, *v_end = v + prop->len; v != v_end; v++) { + if (v != prop->data.pointer) { + STR_APPEND_STR(", "); + } + STR_APPEND_FMT("%d", *v); + } + break; + case IDP_FLOAT: + for (const float *v = prop->data.pointer, *v_end = v + prop->len; v != v_end; v++) { + if (v != prop->data.pointer) { + STR_APPEND_STR(", "); + } + STR_APPEND_FMT("%g", (double)*v); + } + break; + case IDP_DOUBLE: + for (const double *v = prop->data.pointer, *v_end = v + prop->len; v != v_end; v++) { + if (v != prop->data.pointer) { + STR_APPEND_STR(", "); + } + STR_APPEND_FMT("%g", *v); + } + break; + } + STR_APPEND_STR("]"); + break; + } + case IDP_IDPARRAY: + { + STR_APPEND_STR("["); + for (const IDProperty *v = prop->data.pointer, *v_end = v + prop->len; v != v_end; v++) { + if (v != prop->data.pointer) { + STR_APPEND_STR(", "); + } + idp_repr_fn_recursive(state, v); + } + STR_APPEND_STR("]"); + break; + } + case IDP_GROUP: + { + STR_APPEND_STR("{"); + for (const IDProperty *subprop = prop->data.group.first; subprop; subprop = subprop->next) { + if (subprop != prop->data.group.first) { + STR_APPEND_STR(", "); + } + STR_APPEND_STR_QUOTE(subprop->name); + STR_APPEND_STR(": "); + idp_repr_fn_recursive(state, subprop); + } + STR_APPEND_STR("}"); + break; + } + case IDP_ID: + { + const ID *id = prop->data.pointer; + STR_APPEND_STR("bpy.data."); + STR_APPEND_STR(BKE_idcode_to_name_plural(GS(id->name))); + STR_APPEND_STR("["); + STR_APPEND_STR_QUOTE(id->name + 2); + STR_APPEND_STR("]"); + break; + } + default: + { + BLI_assert(0); + break; + } + } + +#undef STR_APPEND_STR +#undef STR_APPEND_STR_QUOTE +#undef STR_APPEND_FMT + +} + +void IDP_repr_fn( + const IDProperty *prop, + void (*str_append_fn)(void *user_data, const char *str, uint str_len), + void *user_data) +{ + struct ReprState state = { + .str_append_fn = str_append_fn, + .user_data = user_data, + }; + idp_repr_fn_recursive(&state, prop); +} + +static void repr_str(void *user_data, const char *str, uint len) +{ + BLI_dynstr_nappend(user_data, str, (int)len); +} + +char *IDP_reprN(const IDProperty *prop, uint *r_len) +{ + DynStr *ds = BLI_dynstr_new(); + IDP_repr_fn(prop, repr_str, ds); + char *cstring = BLI_dynstr_get_cstring(ds); + if (r_len != NULL) { + *r_len = (uint)BLI_dynstr_get_len(ds); + } + BLI_dynstr_free(ds); + return cstring; +} + +void IDP_print(const IDProperty *prop) +{ + char *repr = IDP_reprN(prop, NULL); + printf("IDProperty(%p): ", prop); + puts(repr); + MEM_freeN(repr); +} + +/** \} */ |