diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index 6d47fef371c..11d102399af 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -1245,12 +1245,15 @@ class WM_OT_doc_view_manual(Operator): def _find_reference(rna_id, url_mapping, *, verbose=True): if verbose: print("online manual check for: '%s'... " % rna_id) - from fnmatch import fnmatchcase + # from fnmatch import fnmatchcase + from _bpy import fnmatch_fast + # XXX, for some reason all RNA ID's are stored lowercase # Adding case into all ID's isn't worth the hassle so force lowercase. rna_id = rna_id.lower() for pattern, url_suffix in url_mapping: - if fnmatchcase(rna_id, pattern): + # if fnmatchcase(rna_id, pattern): + if fnmatch_fast(rna_id, pattern, casefold=False): if verbose: print(" match found: '%s' --> '%s'" % (pattern, url_suffix)) return url_suffix diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 36d53d69eff..bbddda7271b 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -13,6 +13,7 @@ #include +#include "BLI_fnmatch.h" #include "BLI_string.h" #include "BLI_string_utils.h" #include "BLI_utildefines.h" @@ -205,6 +206,48 @@ static PyObject *bpy_flip_name(PyObject *UNUSED(self), PyObject *args, PyObject return result; } +PyDoc_STRVAR(bpy_fnmatch_fast_doc, + ".. function:: fnmatch_fast(filename, pattern, casefold=True, exact=False)\n" + "\n" + " TODO." + "\n" + " :arg filename: The name to match.\n" + " :type filename: string\n" + " :arg pattern: Unix style glob pattern.\n" + " :type pattern: bool\n" + " :return: True when the pattern matches.\n" + " :rtype: boolean\n"); +static PyObject *bpy_fnmatch_fast(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + const char *filename = NULL; + const char *pattern = NULL; + bool casefold = true; + + int fnmatch_flags = 0; + + static const char *_keywords[] = {"", "", "casefold", NULL}; + static _PyArg_Parser _parser = { + "s" /* `filename` */ + "s" /* `pattern` */ + "|$" /* Optional, keyword only arguments. */ + "O&" /* `casefold` */ + + ":fnmatch_fast", + _keywords, + 0, + }; + if (!_PyArg_ParseTupleAndKeywordsFast( + args, kw, &_parser, &filename, &pattern, PyC_ParseBool, &casefold)) { + return NULL; + } + if (casefold) { + fnmatch_flags |= FNM_CASEFOLD; + } + + /* Success. */ + return PyBool_FromLong(fnmatch(pattern, filename, fnmatch_flags) == 0); +} + // PyDoc_STRVAR(bpy_user_resource_doc[] = /* now in bpy/utils.py */ static PyObject *bpy_user_resource(PyObject *UNUSED(self), PyObject *args, PyObject *kw) { @@ -556,6 +599,10 @@ static PyMethodDef bpy_methods[] = { METH_VARARGS | METH_KEYWORDS, bpy_blend_paths_doc}, {"flip_name", (PyCFunction)bpy_flip_name, METH_VARARGS | METH_KEYWORDS, bpy_flip_name_doc}, + {"fnmatch_fast", + (PyCFunction)bpy_fnmatch_fast, + METH_VARARGS | METH_KEYWORDS, + bpy_fnmatch_fast_doc}, {"user_resource", (PyCFunction)bpy_user_resource, METH_VARARGS | METH_KEYWORDS, NULL}, {"system_resource", (PyCFunction)bpy_system_resource,