-
-
Notifications
You must be signed in to change notification settings - Fork 32.4k
gh-121445: C implementation for fnmatch
#121446
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
10a6094
ca03388
adb6ed0
e95c255
9b1c20d
85fa953
363ec36
42b019f
4120a95
36394bb
2c2f9f1
ecf8146
cb16b6a
751c069
9258068
5a7183c
2a80200
36432e8
4a36980
4881f1c
ec5a922
b29ccb4
a91f689
9e93b58
5cfd580
891a368
adc18bd
658fb81
cb29bd3
c1fae24
f9343f3
46d7744
5bc902e
7814028
3f075bb
c78a813
2e166cc
14cd1fd
2a718f4
c7a0685
1340fd2
2b6fe4f
124f8f8
7621d6c
9b94fe6
3903987
21ccc7c
c7422a5
7dbe55c
4a87911
aca2b1b
2ef61ad
13dc17e
dba784b
5374ff4
4ff4f37
178f2d3
9d237b1
b1568d4
84b0b82
8696024
b27b6d8
b564b22
6740b10
d73f66d
6258b71
d595cb4
e4296d8
cc92c4b
527712a
ee27297
0622be6
481fae0
ff60eeb
aff1f97
3727582
90e809a
c89cf47
4fbd06b
3b348f5
da42703
97ed24d
d38a0cb
db88ff5
2caa5b8
ef2de2a
c00c8f9
e93cd87
3a05676
db75626
df76ba3
ac46e2c
fa04ea1
0b4cced
5039bce
afc22b2
e66a602
2b59064
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,246 @@ | ||
/* | ||
* C accelerator for the 'fnmatch' module. | ||
* | ||
* Most functions expect string or bytes instances, and thus the Python | ||
* implementation should first pre-process path-like objects, and possibly | ||
* applying normalizations depending on the platform if needed. | ||
*/ | ||
|
||
#include "Python.h" | ||
|
||
#include "clinic/_fnmatchmodule.c.h" | ||
|
||
/*[clinic input] | ||
module _fnmatch | ||
[clinic start generated code]*/ | ||
/*[clinic end generated code: output=da39a3ee5e6b4b0d input=356e324d57d93f08]*/ | ||
|
||
#include <fnmatch.h> | ||
|
||
static inline int | ||
validate_encoded_object(PyObject *name) | ||
{ | ||
if (!PyBytes_Check(name)) { | ||
PyErr_Format(PyExc_TypeError, | ||
"name must be a bytes object, got %.200s", | ||
Py_TYPE(name)->tp_name); | ||
return 0; | ||
} | ||
return 1; | ||
} | ||
|
||
static inline int | ||
validate_unicode_object(PyObject *name) | ||
{ | ||
if (!PyUnicode_Check(name)) { | ||
PyErr_Format(PyExc_TypeError, | ||
"name must be a string object, got %.200s", | ||
Py_TYPE(name)->tp_name); | ||
return 0; | ||
} | ||
return 1; | ||
} | ||
|
||
static inline int | ||
posix_fnmatch_encoded(const char *pattern, PyObject *name) | ||
{ | ||
if (!validate_encoded_object(name)) { | ||
return -1; | ||
} | ||
// case-insensitive match | ||
picnixz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
#ifdef FNM_CASEFOLD | ||
return fnmatch(pattern, PyBytes_AS_STRING(name), FNM_CASEFOLD) == 0; | ||
#else | ||
// todo: fallback to Python implementation | ||
return -1; | ||
#endif | ||
} | ||
|
||
static inline int | ||
posix_fnmatchcase_encoded(const char *pattern, PyObject *name) | ||
{ | ||
if (!validate_encoded_object(name)) { | ||
return -1; | ||
} | ||
// case-sensitive match | ||
return fnmatch(pattern, PyBytes_AS_STRING(name), 0) == 0; | ||
} | ||
|
||
static inline int | ||
posix_fnmatch_unicode(const char *pattern, PyObject *name) | ||
{ | ||
if (!validate_unicode_object(name)) { | ||
return -1; | ||
} | ||
// case-insensitive match | ||
#ifdef FNM_CASEFOLD | ||
return fnmatch(pattern, PyUnicode_AsUTF8(name), FNM_CASEFOLD) == 0; | ||
#else | ||
// todo: fallback to Python implementation | ||
return -1; | ||
#endif | ||
} | ||
|
||
static inline int | ||
posix_fnmatchcase_unicode(const char *pattern, PyObject *name) | ||
{ | ||
if (!validate_unicode_object(name)) { | ||
return -1; | ||
} | ||
// case-sensitive match | ||
return fnmatch(pattern, PyUnicode_AsUTF8(name), 0) == 0; | ||
} | ||
|
||
static PyObject * | ||
_fnmatch_filter_generic_impl(PyObject *module, | ||
PyObject *names, | ||
const char *pattern, | ||
int (*match)(const char *, PyObject *)) | ||
{ | ||
PyObject *iter = PyObject_GetIter(names); | ||
if (iter == NULL) { | ||
return NULL; | ||
} | ||
|
||
PyObject *res = PyList_New(0); | ||
if (res == NULL) { | ||
Py_DECREF(iter); | ||
return NULL; | ||
} | ||
|
||
PyObject *name = NULL; | ||
while ((name = PyIter_Next(iter))) { | ||
int rc = match(pattern, name); | ||
if (rc < 0) { | ||
goto abort; | ||
} | ||
if (rc == 1) { | ||
if (PyList_Append(res, name) < 0) { | ||
goto abort; | ||
} | ||
} | ||
Py_DECREF(name); | ||
if (PyErr_Occurred()) { | ||
Py_DECREF(res); | ||
Py_DECREF(iter); | ||
return NULL; | ||
} | ||
} | ||
Py_DECREF(iter); | ||
return res; | ||
abort: | ||
Py_DECREF(name); | ||
Py_DECREF(iter); | ||
Py_DECREF(res); | ||
return NULL; | ||
} | ||
|
||
/*[clinic input] | ||
_fnmatch.filter -> object | ||
|
||
names: object | ||
pat: object | ||
|
||
[clinic start generated code]*/ | ||
|
||
static PyObject * | ||
_fnmatch_filter_impl(PyObject *module, PyObject *names, PyObject *pat) | ||
/*[clinic end generated code: output=7f11aa68436d05fc input=1d233174e1c4157a]*/ | ||
{ | ||
// todo: handle os.path.normcase(...) | ||
if (PyBytes_Check(pat)) { | ||
const char *pattern = PyBytes_AS_STRING(pat); | ||
return _fnmatch_filter_generic_impl(module, names, pattern, | ||
&posix_fnmatch_encoded); | ||
} | ||
if (PyUnicode_Check(pat)) { | ||
const char *pattern = PyUnicode_AsUTF8(pat); | ||
return _fnmatch_filter_generic_impl(module, names, pattern, | ||
&posix_fnmatch_unicode); | ||
} | ||
PyErr_Format(PyExc_TypeError, "pattern must be a string or a bytes object"); | ||
return NULL; | ||
} | ||
|
||
/*[clinic input] | ||
_fnmatch.fnmatch -> bool | ||
|
||
name: object | ||
pat: object | ||
|
||
[clinic start generated code]*/ | ||
|
||
static int | ||
_fnmatch_fnmatch_impl(PyObject *module, PyObject *name, PyObject *pat) | ||
/*[clinic end generated code: output=b4cd0bd911e8bc93 input=c45e0366489540b8]*/ | ||
{ | ||
// todo: handle os.path.normcase(...) | ||
if (PyBytes_Check(pat)) { | ||
const char *pattern = PyBytes_AS_STRING(pat); | ||
return posix_fnmatch_encoded(pattern, name); | ||
} | ||
if (PyUnicode_Check(pat)) { | ||
const char *pattern = PyUnicode_AsUTF8(pat); | ||
return posix_fnmatch_unicode(pattern, name); | ||
} | ||
PyErr_Format(PyExc_TypeError, "pattern must be a string or a bytes object"); | ||
return NULL; | ||
Check warning on line 187 in Modules/_fnmatchmodule.c
|
||
} | ||
|
||
/*[clinic input] | ||
_fnmatch.fnmatchcase -> bool | ||
|
||
name: object | ||
pat: object | ||
|
||
Test whether `name` matches `pattern`, including case. | ||
|
||
This is a version of fnmatch() which doesn't case-normalize | ||
its arguments. | ||
|
||
[clinic start generated code]*/ | ||
|
||
static int | ||
_fnmatch_fnmatchcase_impl(PyObject *module, PyObject *name, PyObject *pat) | ||
/*[clinic end generated code: output=4d1283b1b1fc7cb8 input=b02a6a5c8c5a46e2]*/ | ||
{ | ||
if (PyBytes_Check(pat)) { | ||
const char *pattern = PyBytes_AS_STRING(pat); | ||
return posix_fnmatchcase_encoded(pattern, name); | ||
} | ||
if (PyUnicode_Check(pat)) { | ||
const char *pattern = PyUnicode_AsUTF8(pat); | ||
return posix_fnmatchcase_unicode(pattern, name); | ||
} | ||
PyErr_Format(PyExc_TypeError, "pattern must be a string or a bytes object"); | ||
return NULL; | ||
Check warning on line 216 in Modules/_fnmatchmodule.c
|
||
} | ||
|
||
static PyMethodDef _fnmatch_methods[] = { | ||
_FNMATCH_FILTER_METHODDEF | ||
_FNMATCH_FNMATCH_METHODDEF | ||
_FNMATCH_FNMATCHCASE_METHODDEF | ||
{NULL, NULL} | ||
}; | ||
|
||
static struct PyModuleDef_Slot _fnmatch_slots[] = { | ||
{0, NULL} | ||
}; | ||
|
||
static struct PyModuleDef _fnmatchmodule = { | ||
PyModuleDef_HEAD_INIT, | ||
"_fnmatch", | ||
NULL, | ||
0, | ||
_fnmatch_methods, | ||
_fnmatch_slots, | ||
NULL, | ||
NULL, | ||
NULL, | ||
}; | ||
|
||
PyMODINIT_FUNC | ||
PyInit__fnmatch(void) | ||
{ | ||
return PyModuleDef_Init(&_fnmatchmodule); | ||
} |
Uh oh!
There was an error while loading. Please reload this page.