Add _PyArg_ParseStack() helper function

Issue #29286. Function similar to PyArg_ParseTuple(), but uses a C array of
PyObject* to pass arguments. Don't support the compatibility mode.
This commit is contained in:
Victor Stinner 2017-01-17 01:29:49 +01:00
parent 3e1fad6913
commit 6518a93cb1
2 changed files with 82 additions and 24 deletions

View File

@ -79,17 +79,27 @@ typedef struct _PyArg_Parser {
} _PyArg_Parser; } _PyArg_Parser;
#ifdef PY_SSIZE_T_CLEAN #ifdef PY_SSIZE_T_CLEAN
#define _PyArg_ParseTupleAndKeywordsFast _PyArg_ParseTupleAndKeywordsFast_SizeT #define _PyArg_ParseTupleAndKeywordsFast _PyArg_ParseTupleAndKeywordsFast_SizeT
#define _PyArg_ParseStack _PyArg_ParseStack_SizeT
#define _PyArg_ParseStackAndKeywords _PyArg_ParseStackAndKeywords_SizeT #define _PyArg_ParseStackAndKeywords _PyArg_ParseStackAndKeywords_SizeT
#define _PyArg_VaParseTupleAndKeywordsFast _PyArg_VaParseTupleAndKeywordsFast_SizeT #define _PyArg_VaParseTupleAndKeywordsFast _PyArg_VaParseTupleAndKeywordsFast_SizeT
#endif #endif
PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywordsFast(PyObject *, PyObject *, PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywordsFast(PyObject *, PyObject *,
struct _PyArg_Parser *, ...); struct _PyArg_Parser *, ...);
PyAPI_FUNC(int) _PyArg_ParseStackAndKeywords(PyObject **args, Py_ssize_t nargs, PyObject *kwnames, PyAPI_FUNC(int) _PyArg_ParseStack(
struct _PyArg_Parser *, ...); PyObject **args,
Py_ssize_t nargs,
const char *format,
...);
PyAPI_FUNC(int) _PyArg_ParseStackAndKeywords(
PyObject **args,
Py_ssize_t nargs,
PyObject *kwnames,
struct _PyArg_Parser *,
...);
PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywordsFast(PyObject *, PyObject *, PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywordsFast(PyObject *, PyObject *,
struct _PyArg_Parser *, va_list); struct _PyArg_Parser *, va_list);
void _PyArg_Fini(void); void _PyArg_Fini(void);
#endif #endif /* Py_LIMITED_API */
PyAPI_FUNC(int) PyModule_AddObject(PyObject *, const char *, PyObject *); PyAPI_FUNC(int) PyModule_AddObject(PyObject *, const char *, PyObject *);
PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long); PyAPI_FUNC(int) PyModule_AddIntConstant(PyObject *, const char *, long);

View File

@ -26,6 +26,8 @@ int _PyArg_VaParseTupleAndKeywordsFast(PyObject *, PyObject *,
#ifdef HAVE_DECLSPEC_DLL #ifdef HAVE_DECLSPEC_DLL
/* Export functions */ /* Export functions */
PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...); PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...);
PyAPI_FUNC(int) _PyArg_ParseStack_SizeT(PyObject **args, Py_ssize_t nargs,
const char *format, ...);
PyAPI_FUNC(int) _PyArg_ParseStackAndKeywords_SizeT(PyObject **args, Py_ssize_t nargs, PyObject *kwnames, PyAPI_FUNC(int) _PyArg_ParseStackAndKeywords_SizeT(PyObject **args, Py_ssize_t nargs, PyObject *kwnames,
struct _PyArg_Parser *parser, ...); struct _PyArg_Parser *parser, ...);
PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, const char *, ...); PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, const char *, ...);
@ -66,6 +68,8 @@ typedef struct {
#define STATIC_FREELIST_ENTRIES 8 #define STATIC_FREELIST_ENTRIES 8
/* Forward */ /* Forward */
static int vgetargs1_impl(PyObject *args, PyObject **stack, Py_ssize_t nargs,
const char *format, va_list *p_va, int flags);
static int vgetargs1(PyObject *, const char *, va_list *, int); static int vgetargs1(PyObject *, const char *, va_list *, int);
static void seterror(Py_ssize_t, const char *, int *, const char *, const char *); static void seterror(Py_ssize_t, const char *, int *, const char *, const char *);
static const char *convertitem(PyObject *, const char **, va_list *, int, int *, static const char *convertitem(PyObject *, const char **, va_list *, int, int *,
@ -137,6 +141,31 @@ _PyArg_ParseTuple_SizeT(PyObject *args, const char *format, ...)
} }
int
_PyArg_ParseStack(PyObject **args, Py_ssize_t nargs, const char *format, ...)
{
int retval;
va_list va;
va_start(va, format);
retval = vgetargs1_impl(NULL, args, nargs, format, &va, 0);
va_end(va);
return retval;
}
int
_PyArg_ParseStack_SizeT(PyObject **args, Py_ssize_t nargs, const char *format, ...)
{
int retval;
va_list va;
va_start(va, format);
retval = vgetargs1_impl(NULL, args, nargs, format, &va, FLAG_SIZE_T);
va_end(va);
return retval;
}
int int
PyArg_VaParse(PyObject *args, const char *format, va_list va) PyArg_VaParse(PyObject *args, const char *format, va_list va)
{ {
@ -220,7 +249,8 @@ cleanreturn(int retval, freelist_t *freelist)
static int static int
vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) vgetargs1_impl(PyObject *compat_args, PyObject **stack, Py_ssize_t nargs, const char *format,
va_list *p_va, int flags)
{ {
char msgbuf[256]; char msgbuf[256];
int levels[32]; int levels[32];
@ -231,17 +261,18 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
int level = 0; int level = 0;
int endfmt = 0; int endfmt = 0;
const char *formatsave = format; const char *formatsave = format;
Py_ssize_t i, len; Py_ssize_t i;
const char *msg; const char *msg;
int compat = flags & FLAG_COMPAT; int compat = flags & FLAG_COMPAT;
freelistentry_t static_entries[STATIC_FREELIST_ENTRIES]; freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
freelist_t freelist; freelist_t freelist;
assert(nargs == 0 || stack != NULL);
freelist.entries = static_entries; freelist.entries = static_entries;
freelist.first_available = 0; freelist.first_available = 0;
freelist.entries_malloced = 0; freelist.entries_malloced = 0;
assert(compat || (args != (PyObject*)NULL));
flags = flags & ~FLAG_COMPAT; flags = flags & ~FLAG_COMPAT;
while (endfmt == 0) { while (endfmt == 0) {
@ -305,7 +336,7 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
if (compat) { if (compat) {
if (max == 0) { if (max == 0) {
if (args == NULL) if (compat_args == NULL)
return 1; return 1;
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%.200s%s takes no arguments", "%.200s%s takes no arguments",
@ -314,14 +345,14 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
return cleanreturn(0, &freelist); return cleanreturn(0, &freelist);
} }
else if (min == 1 && max == 1) { else if (min == 1 && max == 1) {
if (args == NULL) { if (compat_args == NULL) {
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%.200s%s takes at least one argument", "%.200s%s takes at least one argument",
fname==NULL ? "function" : fname, fname==NULL ? "function" : fname,
fname==NULL ? "" : "()"); fname==NULL ? "" : "()");
return cleanreturn(0, &freelist); return cleanreturn(0, &freelist);
} }
msg = convertitem(args, &format, p_va, flags, levels, msg = convertitem(compat_args, &format, p_va, flags, levels,
msgbuf, sizeof(msgbuf), &freelist); msgbuf, sizeof(msgbuf), &freelist);
if (msg == NULL) if (msg == NULL)
return cleanreturn(1, &freelist); return cleanreturn(1, &freelist);
@ -335,34 +366,26 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
} }
} }
if (!PyTuple_Check(args)) { if (nargs < min || max < nargs) {
PyErr_SetString(PyExc_SystemError,
"new style getargs format but argument is not a tuple");
return cleanreturn(0, &freelist);
}
len = PyTuple_GET_SIZE(args);
if (len < min || max < len) {
if (message == NULL) if (message == NULL)
PyErr_Format(PyExc_TypeError, PyErr_Format(PyExc_TypeError,
"%.150s%s takes %s %d argument%s (%ld given)", "%.150s%s takes %s %d argument%s (%ld given)",
fname==NULL ? "function" : fname, fname==NULL ? "function" : fname,
fname==NULL ? "" : "()", fname==NULL ? "" : "()",
min==max ? "exactly" min==max ? "exactly"
: len < min ? "at least" : "at most", : nargs < min ? "at least" : "at most",
len < min ? min : max, nargs < min ? min : max,
(len < min ? min : max) == 1 ? "" : "s", (nargs < min ? min : max) == 1 ? "" : "s",
Py_SAFE_DOWNCAST(len, Py_ssize_t, long)); Py_SAFE_DOWNCAST(nargs, Py_ssize_t, long));
else else
PyErr_SetString(PyExc_TypeError, message); PyErr_SetString(PyExc_TypeError, message);
return cleanreturn(0, &freelist); return cleanreturn(0, &freelist);
} }
for (i = 0; i < len; i++) { for (i = 0; i < nargs; i++) {
if (*format == '|') if (*format == '|')
format++; format++;
msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va, msg = convertitem(stack[i], &format, p_va,
flags, levels, msgbuf, flags, levels, msgbuf,
sizeof(msgbuf), &freelist); sizeof(msgbuf), &freelist);
if (msg) { if (msg) {
@ -382,6 +405,31 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
return cleanreturn(1, &freelist); return cleanreturn(1, &freelist);
} }
static int
vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
{
PyObject **stack;
Py_ssize_t nargs;
if (!(flags & FLAG_COMPAT)) {
assert(args != NULL);
if (!PyTuple_Check(args)) {
PyErr_SetString(PyExc_SystemError,
"new style getargs format but argument is not a tuple");
return 0;
}
stack = &PyTuple_GET_ITEM(args, 0);
nargs = PyTuple_GET_SIZE(args);
}
else {
stack = NULL;
nargs = 0;
}
return vgetargs1_impl(args, stack, nargs, format, p_va, flags);
}
static void static void