Merge branch 'master' into blender2.8

This commit is contained in:
2017-08-23 19:21:52 +10:00
6 changed files with 213 additions and 104 deletions

View File

@@ -39,6 +39,7 @@ extern "C" {
#endif
#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h" /* only for _VA_NARGS_COUNT */
struct ListBase;
@@ -49,6 +50,24 @@ size_t BLI_split_name_num(char *left, int *nr, const char *name, const char deli
void BLI_string_split_suffix(const char *string, char *r_body, char *r_suf, const size_t str_len);
void BLI_string_split_prefix(const char *string, char *r_pre, char *r_body, const size_t str_len);
/* Join strings, return newly allocated string. */
char *BLI_string_join_arrayN(
const char *strings[], uint strings_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
char *BLI_string_join_array_by_sep_charN(
char sep, const char *strings[], uint strings_len) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL();
char *BLI_string_join_array_by_sep_char_with_tableN(
char sep, char *table[], const char *strings[], uint strings_len) ATTR_NONNULL();
/* Take multiple arguments, pass as (array, length). */
#define BLI_string_joinN(...) \
BLI_string_join_arrayN( \
((const char *[]){__VA_ARGS__}), _VA_NARGS_COUNT(__VA_ARGS__))
#define BLI_string_join_by_sep_charN(sep, ...) \
BLI_string_join_array_by_sep_charN( \
sep, ((const char *[]){__VA_ARGS__}), _VA_NARGS_COUNT(__VA_ARGS__))
#define BLI_string_join_by_sep_char_with_tableN(sep, table, ...) \
BLI_string_join_array_by_sep_char_with_tableN( \
sep, table, ((const char *[]){__VA_ARGS__}), _VA_NARGS_COUNT(__VA_ARGS__))
void BLI_string_flip_side_name(char *r_name, const char *from_name, const bool strip_number, const size_t name_len);
bool BLI_uniquename_cb(

View File

@@ -383,3 +383,91 @@ bool BLI_uniquename(ListBase *list, void *vlink, const char *defname, char delim
return BLI_uniquename_cb(uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len);
}
/* ------------------------------------------------------------------------- */
/** \name Join Strings
*
* For non array versions of these functions, use the macros:
* - #BLI_string_joinN
* - #BLI_string_join_by_sep_charN
* - #BLI_string_join_by_sep_char_with_tableN
*
* \{ */
/**
* Join an array of strings into a newly allocated, null terminated string.
*/
char *BLI_string_join_arrayN(
const char *strings[], uint strings_len)
{
uint total_len = 1;
for (uint i = 0; i < strings_len; i++) {
total_len += strlen(strings[i]);
}
char *result = MEM_mallocN(sizeof(char) * total_len, __func__);
char *c = result;
for (uint i = 0; i < strings_len; i++) {
c += BLI_strcpy_rlen(c, strings[i]);
}
return result;
}
/**
* A version of #BLI_string_joinN that takes a separator which can be any character including '\0'.
*/
char *BLI_string_join_array_by_sep_charN(
char sep, const char *strings[], uint strings_len)
{
uint total_len = 0;
for (uint i = 0; i < strings_len; i++) {
total_len += strlen(strings[i]) + 1;
}
if (total_len == 0) {
total_len = 1;
}
char *result = MEM_mallocN(sizeof(char) * total_len, __func__);
char *c = result;
if (strings_len != 0) {
for (uint i = 0; i < strings_len; i++) {
c += BLI_strcpy_rlen(c, strings[i]);
*c = sep;
c++;
}
c--;
}
*c = '\0';
return result;
}
/**
* A version of #BLI_string_join_array_by_sep_charN that takes a table array.
* The new location of each string is written into this array.
*/
char *BLI_string_join_array_by_sep_char_with_tableN(
char sep, char *table[], const char *strings[], uint strings_len)
{
uint total_len = 0;
for (uint i = 0; i < strings_len; i++) {
total_len += strlen(strings[i]) + 1;
}
if (total_len == 0) {
total_len = 1;
}
char *result = MEM_mallocN(sizeof(char) * total_len, __func__);
char *c = result;
if (strings_len != 0) {
for (uint i = 0; i < strings_len; i++) {
table[i] = c; /* <-- only difference to BLI_string_join_array_by_sep_charN. */
c += BLI_strcpy_rlen(c, strings[i]);
*c = sep;
c++;
}
c--;
}
*c = '\0';
return result;
}
/** \} */

View File

@@ -32,6 +32,7 @@
#include "DNA_windowmanager_types.h"
#include "BLI_utildefines.h"
#include "BLI_string_utils.h"
#include "BLT_translation.h"
@@ -1216,8 +1217,8 @@ static StructRNA *rna_Operator_register(
struct {
char idname[OP_MAX_TYPENAME];
char name[OP_MAX_TYPENAME];
char descr[RNA_DYN_DESCR_MAX];
char ctxt[RNA_DYN_DESCR_MAX];
char description[RNA_DYN_DESCR_MAX];
char translation_context[RNA_DYN_DESCR_MAX];
char undo_group[OP_MAX_TYPENAME];
} temp_buffers;
@@ -1225,15 +1226,15 @@ static StructRNA *rna_Operator_register(
dummyop.type = &dummyot;
dummyot.idname = temp_buffers.idname; /* only assigne the pointer, string is NULL'd */
dummyot.name = temp_buffers.name; /* only assigne the pointer, string is NULL'd */
dummyot.description = temp_buffers.descr; /* only assigne the pointer, string is NULL'd */
dummyot.translation_context = temp_buffers.ctxt; /* only assigne the pointer, string is NULL'd */
dummyot.description = temp_buffers.description; /* only assigne the pointer, string is NULL'd */
dummyot.translation_context = temp_buffers.translation_context; /* only assigne the pointer, string is NULL'd */
dummyot.undo_group = temp_buffers.undo_group; /* only assigne the pointer, string is NULL'd */
RNA_pointer_create(NULL, &RNA_Operator, &dummyop, &dummyotr);
/* clear in case they are left unset */
temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.descr[0] = temp_buffers.undo_group[0] = '\0';
temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.description[0] = temp_buffers.undo_group[0] = '\0';
/* We have to set default op context! */
strcpy(temp_buffers.ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
strcpy(temp_buffers.translation_context, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
/* validate the python class */
if (validate(&dummyotr, data, have_function) != 0)
@@ -1248,72 +1249,31 @@ static StructRNA *rna_Operator_register(
if (!RNA_struct_available_or_report(reports, identifier)) {
return NULL;
}
if (!WM_operator_py_idname_ok_or_report(reports, identifier, temp_buffers.idname)) {
return NULL;
}
{ /* convert foo.bar to FOO_OT_bar
* allocate the description and the idname in 1 go */
/* Convert foo.bar to FOO_OT_bar
* allocate all strings at once. */
{
char idname_conv[sizeof(dummyop.idname)];
WM_operator_bl_idname(idname_conv, temp_buffers.idname); /* convert the idname from python */
const char *strings[] = {
idname_conv,
temp_buffers.name,
temp_buffers.description,
temp_buffers.translation_context,
temp_buffers.undo_group,
};
char *strings_table[ARRAY_SIZE(strings)];
BLI_string_join_array_by_sep_char_with_tableN('\0', strings_table, strings, ARRAY_SIZE(strings));
/* inconveniently long name sanity check */
{
char *ch = temp_buffers.idname;
int i;
int dot = 0;
for (i = 0; *ch; i++) {
if ((*ch >= 'a' && *ch <= 'z') || (*ch >= '0' && *ch <= '9') || *ch == '_') {
/* pass */
}
else if (*ch == '.') {
dot++;
}
else {
BKE_reportf(reports, RPT_ERROR,
"Registering operator class: '%s', invalid bl_idname '%s', at position %d",
identifier, temp_buffers.idname, i);
return NULL;
}
ch++;
}
if (i > ((int)sizeof(dummyop.idname)) - 3) {
BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', "
"is too long, maximum length is %d", identifier, temp_buffers.idname,
(int)sizeof(dummyop.idname) - 3);
return NULL;
}
if (dot != 1) {
BKE_reportf(reports, RPT_ERROR,
"Registering operator class: '%s', invalid bl_idname '%s', must contain 1 '.' character",
identifier, temp_buffers.idname);
return NULL;
}
}
/* end sanity check */
{
const uint idname_len = strlen(temp_buffers.idname) + 4;
const uint name_len = strlen(temp_buffers.name) + 1;
const uint desc_len = strlen(temp_buffers.descr) + 1;
const uint ctxt_len = strlen(temp_buffers.ctxt) + 1;
const uint undo_group_len = strlen(temp_buffers.undo_group) + 1;
/* 2 terminators and 3 to convert a.b -> A_OT_b */
char *ch = MEM_mallocN(
sizeof(char) * (idname_len + name_len + desc_len + ctxt_len + undo_group_len), __func__);
WM_operator_bl_idname(ch, temp_buffers.idname); /* convert the idname from python */
dummyot.idname = ch;
ch += idname_len;
memcpy(ch, temp_buffers.name, name_len);
dummyot.name = ch;
ch += name_len;
memcpy(ch, temp_buffers.descr, desc_len);
dummyot.description = ch;
ch += desc_len;
memcpy(ch, temp_buffers.ctxt, ctxt_len);
dummyot.translation_context = ch;
ch += ctxt_len;
memcpy(ch, temp_buffers.undo_group, undo_group_len);
dummyot.undo_group = ch;
}
dummyot.idname = strings_table[0]; /* allocated string stored here */
dummyot.name = strings_table[1];
dummyot.description = strings_table[2];
dummyot.translation_context = strings_table[3];
dummyot.undo_group = strings_table[4];
BLI_assert(ARRAY_SIZE(strings) == 5);
}
/* XXX, this doubles up with the operator name [#29666]
@@ -1389,8 +1349,8 @@ static StructRNA *rna_MacroOperator_register(
struct {
char idname[OP_MAX_TYPENAME];
char name[OP_MAX_TYPENAME];
char descr[RNA_DYN_DESCR_MAX];
char ctxt[RNA_DYN_DESCR_MAX];
char description[RNA_DYN_DESCR_MAX];
char translation_context[RNA_DYN_DESCR_MAX];
char undo_group[OP_MAX_TYPENAME];
} temp_buffers;
@@ -1398,15 +1358,15 @@ static StructRNA *rna_MacroOperator_register(
dummyop.type = &dummyot;
dummyot.idname = temp_buffers.idname; /* only assigne the pointer, string is NULL'd */
dummyot.name = temp_buffers.name; /* only assigne the pointer, string is NULL'd */
dummyot.description = temp_buffers.descr; /* only assigne the pointer, string is NULL'd */
dummyot.translation_context = temp_buffers.ctxt; /* only assigne the pointer, string is NULL'd */
dummyot.description = temp_buffers.description; /* only assigne the pointer, string is NULL'd */
dummyot.translation_context = temp_buffers.translation_context; /* only assigne the pointer, string is NULL'd */
dummyot.undo_group = temp_buffers.undo_group; /* only assigne the pointer, string is NULL'd */
RNA_pointer_create(NULL, &RNA_Macro, &dummyop, &dummyotr);
/* clear in case they are left unset */
temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.descr[0] = temp_buffers.undo_group[0] = '\0';
temp_buffers.idname[0] = temp_buffers.name[0] = temp_buffers.description[0] = temp_buffers.undo_group[0] = '\0';
/* We have to set default op context! */
strcpy(temp_buffers.ctxt, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
strcpy(temp_buffers.translation_context, BLT_I18NCONTEXT_OPERATOR_DEFAULT);
/* validate the python class */
if (validate(&dummyotr, data, have_function) != 0)
@@ -1427,31 +1387,31 @@ static StructRNA *rna_MacroOperator_register(
if (!RNA_struct_available_or_report(reports, identifier)) {
return NULL;
}
if (!WM_operator_py_idname_ok_or_report(reports, identifier, temp_buffers.idname)) {
return NULL;
}
{ /* convert foo.bar to FOO_OT_bar
* allocate the description and the idname in 1 go */
const uint idname_len = strlen(temp_buffers.idname) + 4;
const uint name_len = strlen(temp_buffers.name) + 1;
const uint desc_len = strlen(temp_buffers.descr) + 1;
const uint ctxt_len = strlen(temp_buffers.ctxt) + 1;
const uint undo_group_len = strlen(temp_buffers.undo_group) + 1;
/* 2 terminators and 3 to convert a.b -> A_OT_b */
char *ch = MEM_mallocN(
sizeof(char) * (idname_len + name_len + desc_len + ctxt_len + undo_group_len), __func__);
WM_operator_bl_idname(ch, temp_buffers.idname); /* convert the idname from python */
dummyot.idname = ch;
ch += idname_len;
memcpy(ch, temp_buffers.name, name_len);
dummyot.name = ch;
ch += name_len;
memcpy(ch, temp_buffers.descr, desc_len);
dummyot.description = ch;
ch += desc_len;
memcpy(ch, temp_buffers.ctxt, ctxt_len);
dummyot.translation_context = ch;
ch += ctxt_len;
memcpy(ch, temp_buffers.undo_group, undo_group_len);
dummyot.undo_group = ch;
/* Convert foo.bar to FOO_OT_bar
* allocate all strings at once. */
{
char idname_conv[sizeof(dummyop.idname)];
WM_operator_bl_idname(idname_conv, temp_buffers.idname); /* convert the idname from python */
const char *strings[] = {
idname_conv,
temp_buffers.name,
temp_buffers.description,
temp_buffers.translation_context,
temp_buffers.undo_group,
};
char *strings_table[ARRAY_SIZE(strings)];
BLI_string_join_array_by_sep_char_with_tableN('\0', strings_table, strings, ARRAY_SIZE(strings));
dummyot.idname = strings_table[0]; /* allocated string stored here */
dummyot.name = strings_table[1];
dummyot.description = strings_table[2];
dummyot.translation_context = strings_table[3];
dummyot.undo_group = strings_table[4];
BLI_assert(ARRAY_SIZE(strings) == 5);
}
/* XXX, this doubles up with the operator name [#29666]

View File

@@ -28,6 +28,7 @@
#define __PY_CAPI_UTILS_H__
#include "BLI_sys_types.h"
#include "BLI_utildefines.h" /* only for _VA_NARGS_COUNT */
void PyC_ObSpit(const char *name, PyObject *var);
void PyC_LineSpit(void);
@@ -52,13 +53,13 @@ PyObject *PyC_Tuple_PackArray_I32FromBool(const int *array, uint len);
PyObject *PyC_Tuple_PackArray_Bool(const bool *array, uint len);
#define PyC_Tuple_Pack_F32(...) \
PyC_Tuple_PackArray_F32(((const float []){__VA_ARGS__}), (sizeof((const float []){__VA_ARGS__}) / sizeof(float)))
PyC_Tuple_PackArray_F32(((const float []){__VA_ARGS__}), _VA_NARGS_COUNT(__VA_ARGS__))
#define PyC_Tuple_Pack_I32(...) \
PyC_Tuple_PackArray_I32(((const int []){__VA_ARGS__}), (sizeof((const int []){__VA_ARGS__}) / sizeof(int)))
PyC_Tuple_PackArray_I32(((const int []){__VA_ARGS__}), _VA_NARGS_COUNT(__VA_ARGS__))
#define PyC_Tuple_Pack_I32FromBool(...) \
PyC_Tuple_PackArray_I32FromBool(((const int []){__VA_ARGS__}), (sizeof((const int []){__VA_ARGS__}) / sizeof(int)))
PyC_Tuple_PackArray_I32FromBool(((const int []){__VA_ARGS__}), _VA_NARGS_COUNT(__VA_ARGS__))
#define PyC_Tuple_Pack_Bool(...) \
PyC_Tuple_PackArray_Bool(((const bool []){__VA_ARGS__}), (sizeof((const bool []){__VA_ARGS__}) / sizeof(bool)))
PyC_Tuple_PackArray_Bool(((const bool []){__VA_ARGS__}), _VA_NARGS_COUNT(__VA_ARGS__))
void PyC_Tuple_Fill(PyObject *tuple, PyObject *value);
void PyC_List_Fill(PyObject *list, PyObject *value);

View File

@@ -379,6 +379,7 @@ bool WM_operator_pystring_abbreviate(char *str, int str_len_max);
char *WM_prop_pystring_assign(struct bContext *C, struct PointerRNA *ptr, struct PropertyRNA *prop, int index);
void WM_operator_bl_idname(char *to, const char *from);
void WM_operator_py_idname(char *to, const char *from);
bool WM_operator_py_idname_ok_or_report(struct ReportList *reports, const char *classname, const char *idname);
/* *************** uilist types ******************** */
void WM_uilisttype_init(void);

View File

@@ -575,6 +575,46 @@ void WM_operator_bl_idname(char *to, const char *from)
to[0] = 0;
}
/**
* Sanity check to ensure #WM_operator_bl_idname won't fail.
* \returns true when there are no problems with \a idname, otherwise report an error.
*/
bool WM_operator_py_idname_ok_or_report(ReportList *reports, const char *classname, const char *idname)
{
const char *ch = idname;
int dot = 0;
int i;
for (i = 0; *ch; i++, ch++) {
if ((*ch >= 'a' && *ch <= 'z') || (*ch >= '0' && *ch <= '9') || *ch == '_') {
/* pass */
}
else if (*ch == '.') {
dot++;
}
else {
BKE_reportf(reports, RPT_ERROR,
"Registering operator class: '%s', invalid bl_idname '%s', at position %d",
classname, idname, i);
return false;
}
}
if (i > (MAX_NAME - 3)) {
BKE_reportf(reports, RPT_ERROR, "Registering operator class: '%s', invalid bl_idname '%s', "
"is too long, maximum length is %d", classname, idname,
MAX_NAME - 3);
return false;
}
if (dot != 1) {
BKE_reportf(reports, RPT_ERROR,
"Registering operator class: '%s', invalid bl_idname '%s', must contain 1 '.' character",
classname, idname);
return false;
}
return true;
}
/**
* Print a string representation of the operator, with the args that it runs so python can run it again.
*