Files
test2/source/blender/blenkernel/intern/idprop_utils.c
Sergey Sharybin c1bc70b711 Cleanup: Add a copyright notice to files and use SPDX format
A lot of files were missing copyright field in the header and
the Blender Foundation contributed to them in a sense of bug
fixing and general maintenance.

This change makes it explicit that those files are at least
partially copyrighted by the Blender Foundation.

Note that this does not make it so the Blender Foundation is
the only holder of the copyright in those files, and developers
who do not have a signed contract with the foundation still
hold the copyright as well.

Another aspect of this change is using SPDX format for the
header. We already used it for the license specification,
and now we state it for the copyright as well, following the
FAQ:

    https://reuse.software/faq/
2023-05-31 16:19:06 +02:00

244 lines
6.5 KiB
C

/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*/
#include <stdio.h>
#include <string.h>
#include "BLI_dynstr.h"
#include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h"
#include "DNA_ID.h"
#include "BKE_idprop.h"
#include "BKE_idtype.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)SNPRINTF_RLEN(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))
#define STR_APPEND_STR_QUOTE(str) idp_str_append_escape(state, str, (uint)strlen(str), true)
#define STR_APPEND_STR_LEN_QUOTE(str, str_len) idp_str_append_escape(state, str, str_len, true)
#define STR_APPEND_FMT(format, ...) \
state->str_append_fn( \
state->user_data, state->buf, (uint)SNPRINTF_RLEN(state->buf, format, __VA_ARGS__))
switch (prop->type) {
case IDP_STRING: {
STR_APPEND_STR_LEN_QUOTE(IDP_String(prop), (uint)MAX2(0, prop->len - 1));
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_BOOLEAN: {
STR_APPEND_FMT("%s", IDP_Bool(prop) ? "True" : "False");
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;
case IDP_BOOLEAN:
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("%s", IDP_Bool(prop) ? "True" : "False");
}
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("{");
LISTBASE_FOREACH (const IDProperty *, subprop, &prop->data.group) {
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;
if (id != NULL) {
STR_APPEND_STR("bpy.data.");
STR_APPEND_STR(BKE_idtype_idcode_to_name_plural(GS(id->name)));
STR_APPEND_STR("[");
STR_APPEND_STR_QUOTE(id->name + 2);
STR_APPEND_STR("]");
}
else {
STR_APPEND_STR("None");
}
break;
}
default: {
BLI_assert_unreachable();
break;
}
}
#undef STR_APPEND_STR
#undef STR_APPEND_STR_QUOTE
#undef STR_APPEND_STR_LEN_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);
}
/** \} */