diff options
author | Serhiy Storchaka <storchaka@gmail.com> | 2017-01-25 13:27:44 +0200 |
---|---|---|
committer | Serhiy Storchaka <storchaka@gmail.com> | 2017-01-25 13:27:44 +0200 |
commit | 19b1c3b04e2b01bd3b35b9e14c1735959d3b65e8 (patch) | |
tree | 24ab2ab26f886e3da21f91979512412360abea5d /Python/getargs.c | |
parent | 3f19a274c28567afb39ba46ea8a2ebdeab816b0b (diff) | |
parent | 82e2d87e841850bc39db8ae954321986761492f5 (diff) | |
download | cpython-19b1c3b04e2b01bd3b35b9e14c1735959d3b65e8.tar.gz |
Issue #27867: Function PySlice_GetIndicesEx() is deprecated and replaced with
a macro if Py_LIMITED_API is not set or set to the value between 0x03050400
and 0x03060000 (not including) or 0x03060100 or higher. Added functions
PySlice_Unpack() and PySlice_AdjustIndices().
Diffstat (limited to 'Python/getargs.c')
-rw-r--r-- | Python/getargs.c | 511 |
1 files changed, 287 insertions, 224 deletions
diff --git a/Python/getargs.c b/Python/getargs.c index 616c6eb107..e3be6d9280 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -26,7 +26,9 @@ int _PyArg_VaParseTupleAndKeywordsFast(PyObject *, PyObject *, #ifdef HAVE_DECLSPEC_DLL /* Export functions */ PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...); -PyAPI_FUNC(int) _PyArg_ParseStack_SizeT(PyObject **args, Py_ssize_t nargs, PyObject *kwnames, +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, struct _PyArg_Parser *parser, ...); PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, const char *, ...); PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywords_SizeT(PyObject *, PyObject *, @@ -66,6 +68,8 @@ typedef struct { #define STATIC_FREELIST_ENTRIES 8 /* 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 void seterror(Py_ssize_t, const char *, int *, const char *, const char *); static const char *convertitem(PyObject *, const char **, va_list *, int, int *, @@ -74,7 +78,7 @@ static const char *converttuple(PyObject *, const char **, va_list *, int, int *, char *, size_t, int, freelist_t *); static const char *convertsimple(PyObject *, const char **, va_list *, int, char *, size_t, freelist_t *); -static Py_ssize_t convertbuffer(PyObject *, void **p, const char **); +static Py_ssize_t convertbuffer(PyObject *, const void **p, const char **); static int getbuffer(PyObject *, Py_buffer *, const char**); static int vgetargskeywords(PyObject *, PyObject *, @@ -138,6 +142,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 PyArg_VaParse(PyObject *args, const char *format, va_list va) { va_list lva; @@ -220,7 +249,8 @@ cleanreturn(int retval, freelist_t *freelist) 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]; int levels[32]; @@ -231,17 +261,18 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) int level = 0; int endfmt = 0; const char *formatsave = format; - Py_ssize_t i, len; + Py_ssize_t i; const char *msg; int compat = flags & FLAG_COMPAT; freelistentry_t static_entries[STATIC_FREELIST_ENTRIES]; freelist_t freelist; + assert(nargs == 0 || stack != NULL); + freelist.entries = static_entries; freelist.first_available = 0; freelist.entries_malloced = 0; - assert(compat || (args != (PyObject*)NULL)); flags = flags & ~FLAG_COMPAT; while (endfmt == 0) { @@ -305,7 +336,7 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) if (compat) { if (max == 0) { - if (args == NULL) + if (compat_args == NULL) return 1; PyErr_Format(PyExc_TypeError, "%.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); } else if (min == 1 && max == 1) { - if (args == NULL) { + if (compat_args == NULL) { PyErr_Format(PyExc_TypeError, "%.200s%s takes at least one argument", fname==NULL ? "function" : fname, fname==NULL ? "" : "()"); 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); if (msg == NULL) return cleanreturn(1, &freelist); @@ -335,34 +366,26 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) } } - if (!PyTuple_Check(args)) { - 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 (nargs < min || max < nargs) { if (message == NULL) PyErr_Format(PyExc_TypeError, "%.150s%s takes %s %d argument%s (%ld given)", fname==NULL ? "function" : fname, fname==NULL ? "" : "()", min==max ? "exactly" - : len < min ? "at least" : "at most", - len < min ? min : max, - (len < min ? min : max) == 1 ? "" : "s", - Py_SAFE_DOWNCAST(len, Py_ssize_t, long)); + : nargs < min ? "at least" : "at most", + nargs < min ? min : max, + (nargs < min ? min : max) == 1 ? "" : "s", + Py_SAFE_DOWNCAST(nargs, Py_ssize_t, long)); else PyErr_SetString(PyExc_TypeError, message); return cleanreturn(0, &freelist); } - for (i = 0; i < len; i++) { + for (i = 0; i < nargs; i++) { if (*format == '|') format++; - msg = convertitem(PyTuple_GET_ITEM(args, i), &format, p_va, + msg = convertitem(stack[i], &format, p_va, flags, levels, msgbuf, sizeof(msgbuf), &freelist); if (msg) { @@ -382,6 +405,31 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags) 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 @@ -625,7 +673,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, const char *format = *p_format; char c = *format++; - char *sarg; + const char *sarg; switch (c) { @@ -897,7 +945,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, } break; } - count = convertbuffer(arg, p, &buf); + count = convertbuffer(arg, (const void **)p, &buf); if (count < 0) return converterr(buf, arg, msgbuf, bufsize); if (*format == '#') { @@ -928,7 +976,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, if (sarg == NULL) return converterr(CONV_UNICODE, arg, msgbuf, bufsize); - PyBuffer_FillInfo(p, arg, sarg, len, 1, 0); + PyBuffer_FillInfo(p, arg, (void *)sarg, len, 1, 0); } else { /* any bytes-like object */ const char *buf; @@ -943,7 +991,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, format++; } else if (*format == '#') { /* a string or read-only bytes-like object */ /* "s#" or "z#" */ - void **p = (void **)va_arg(*p_va, char **); + const void **p = (const void **)va_arg(*p_va, const char **); FETCH_SIZE; if (c == 'z' && arg == Py_None) { @@ -970,7 +1018,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, format++; } else { /* "s" or "z" */ - char **p = va_arg(*p_va, char **); + const char **p = va_arg(*p_va, const char **); Py_ssize_t len; sarg = NULL; @@ -1027,7 +1075,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, *p = PyUnicode_AsUnicodeAndSize(arg, &len); if (*p == NULL) RETURN_ERR_OCCURRED; - if (Py_UNICODE_strlen(*p) != (size_t)len) { + if (wcslen(*p) != (size_t)len) { PyErr_SetString(PyExc_ValueError, "embedded null character"); RETURN_ERR_OCCURRED; } @@ -1074,9 +1122,14 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, (PyBytes_Check(arg) || PyByteArray_Check(arg))) { s = arg; Py_INCREF(s); - if (PyObject_AsCharBuffer(s, &ptr, &size) < 0) - return converterr("(AsCharBuffer failed)", - arg, msgbuf, bufsize); + if (PyBytes_Check(arg)) { + size = PyBytes_GET_SIZE(s); + ptr = PyBytes_AS_STRING(s); + } + else { + size = PyByteArray_GET_SIZE(s); + ptr = PyByteArray_AS_STRING(s); + } } else if (PyUnicode_Check(arg)) { /* Encode object; use default error handling */ @@ -1300,7 +1353,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags, } static Py_ssize_t -convertbuffer(PyObject *arg, void **p, const char **errmsg) +convertbuffer(PyObject *arg, const void **p, const char **errmsg) { PyBufferProcs *pb = Py_TYPE(arg)->tp_as_buffer; Py_ssize_t count; @@ -1448,14 +1501,6 @@ _PyArg_ParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords, int retval; va_list va; - if ((args == NULL || !PyTuple_Check(args)) || - (keywords != NULL && !PyDict_Check(keywords)) || - parser == NULL) - { - PyErr_BadInternalCall(); - return 0; - } - va_start(va, parser); retval = vgetargskeywordsfast(args, keywords, parser, &va, 0); va_end(va); @@ -1469,14 +1514,6 @@ _PyArg_ParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords, int retval; va_list va; - if ((args == NULL || !PyTuple_Check(args)) || - (keywords != NULL && !PyDict_Check(keywords)) || - parser == NULL) - { - PyErr_BadInternalCall(); - return 0; - } - va_start(va, parser); retval = vgetargskeywordsfast(args, keywords, parser, &va, FLAG_SIZE_T); va_end(va); @@ -1484,19 +1521,12 @@ _PyArg_ParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords, } int -_PyArg_ParseStack(PyObject **args, Py_ssize_t nargs, PyObject *kwnames, +_PyArg_ParseStackAndKeywords(PyObject **args, Py_ssize_t nargs, PyObject *kwnames, struct _PyArg_Parser *parser, ...) { int retval; va_list va; - if ((kwnames != NULL && !PyTuple_Check(kwnames)) || - parser == NULL) - { - PyErr_BadInternalCall(); - return 0; - } - va_start(va, parser); retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va, 0); va_end(va); @@ -1504,19 +1534,12 @@ _PyArg_ParseStack(PyObject **args, Py_ssize_t nargs, PyObject *kwnames, } int -_PyArg_ParseStack_SizeT(PyObject **args, Py_ssize_t nargs, PyObject *kwnames, +_PyArg_ParseStackAndKeywords_SizeT(PyObject **args, Py_ssize_t nargs, PyObject *kwnames, struct _PyArg_Parser *parser, ...) { int retval; va_list va; - if ((kwnames != NULL && !PyTuple_Check(kwnames)) || - parser == NULL) - { - PyErr_BadInternalCall(); - return 0; - } - va_start(va, parser); retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va, FLAG_SIZE_T); va_end(va); @@ -1531,14 +1554,6 @@ _PyArg_VaParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords, int retval; va_list lva; - if ((args == NULL || !PyTuple_Check(args)) || - (keywords != NULL && !PyDict_Check(keywords)) || - parser == NULL) - { - PyErr_BadInternalCall(); - return 0; - } - va_copy(lva, va); retval = vgetargskeywordsfast(args, keywords, parser, &lva, 0); @@ -1553,14 +1568,6 @@ _PyArg_VaParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords, int retval; va_list lva; - if ((args == NULL || !PyTuple_Check(args)) || - (keywords != NULL && !PyDict_Check(keywords)) || - parser == NULL) - { - PyErr_BadInternalCall(); - return 0; - } - va_copy(lva, va); retval = vgetargskeywordsfast(args, keywords, parser, &lva, FLAG_SIZE_T); @@ -1586,17 +1593,17 @@ PyArg_ValidateKeywordArguments(PyObject *kwargs) #define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':') static int -vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, +vgetargskeywords(PyObject *args, PyObject *kwargs, const char *format, char **kwlist, va_list *p_va, int flags) { char msgbuf[512]; int levels[32]; - const char *fname, *msg, *custom_msg, *keyword; + const char *fname, *msg, *custom_msg; int min = INT_MAX; int max = INT_MAX; int i, pos, len; int skip = 0; - Py_ssize_t nargs, nkeywords; + Py_ssize_t nargs, nkwargs; PyObject *current_arg; freelistentry_t static_entries[STATIC_FREELIST_ENTRIES]; freelist_t freelist; @@ -1606,7 +1613,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, freelist.entries_malloced = 0; assert(args != NULL && PyTuple_Check(args)); - assert(keywords == NULL || PyDict_Check(keywords)); + assert(kwargs == NULL || PyDict_Check(kwargs)); assert(format != NULL); assert(kwlist != NULL); assert(p_va != NULL); @@ -1645,21 +1652,20 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, } nargs = PyTuple_GET_SIZE(args); - nkeywords = (keywords == NULL) ? 0 : PyDict_Size(keywords); - if (nargs + nkeywords > len) { + nkwargs = (kwargs == NULL) ? 0 : PyDict_GET_SIZE(kwargs); + if (nargs + nkwargs > len) { PyErr_Format(PyExc_TypeError, "%s%s takes at most %d argument%s (%zd given)", (fname == NULL) ? "function" : fname, (fname == NULL) ? "" : "()", len, (len == 1) ? "" : "s", - nargs + nkeywords); + nargs + nkwargs); return cleanreturn(0, &freelist); } /* convert tuple args and keyword args in same loop, using kwlist to drive process */ for (i = 0; i < len; i++) { - keyword = kwlist[i]; if (*format == '|') { if (min != INT_MAX) { PyErr_SetString(PyExc_SystemError, @@ -1713,26 +1719,17 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, return cleanreturn(0, &freelist); } if (!skip) { - current_arg = NULL; - if (nkeywords && i >= pos) { - current_arg = PyDict_GetItemString(keywords, keyword); - if (!current_arg && PyErr_Occurred()) { - return cleanreturn(0, &freelist); - } + if (i < nargs) { + current_arg = PyTuple_GET_ITEM(args, i); } - if (current_arg) { - --nkeywords; - if (i < nargs) { - /* arg present in tuple and in dict */ - PyErr_Format(PyExc_TypeError, - "Argument given by name ('%s') " - "and position (%d)", - keyword, i+1); - return cleanreturn(0, &freelist); - } + else if (nkwargs && i >= pos) { + current_arg = PyDict_GetItemString(kwargs, kwlist[i]); + if (current_arg) + --nkwargs; + } + else { + current_arg = NULL; } - else if (i < nargs) - current_arg = PyTuple_GET_ITEM(args, i); if (current_arg) { msg = convertitem(current_arg, &format, p_va, flags, @@ -1756,8 +1753,8 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, } else { PyErr_Format(PyExc_TypeError, "Required argument " - "'%s' (pos %d) not found", - keyword, i+1); + "'%s' (pos %d) not found", + kwlist[i], i+1); return cleanreturn(0, &freelist); } } @@ -1765,7 +1762,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, * fulfilled and no keyword args left, with no further * validation. XXX Maybe skip this in debug build ? */ - if (!nkeywords && !skip) { + if (!nkwargs && !skip) { return cleanreturn(1, &freelist); } } @@ -1796,19 +1793,32 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format, return cleanreturn(0, &freelist); } - /* make sure there are no extraneous keyword arguments */ - if (nkeywords > 0) { - PyObject *key, *value; - Py_ssize_t pos = 0; - while (PyDict_Next(keywords, &pos, &key, &value)) { + if (nkwargs > 0) { + PyObject *key; + Py_ssize_t j; + /* make sure there are no arguments given by name and position */ + for (i = pos; i < nargs; i++) { + current_arg = PyDict_GetItemString(kwargs, kwlist[i]); + if (current_arg) { + /* arg present in tuple and in dict */ + PyErr_Format(PyExc_TypeError, + "Argument given by name ('%s') " + "and position (%d)", + kwlist[i], i+1); + return cleanreturn(0, &freelist); + } + } + /* make sure there are no extraneous keyword arguments */ + j = 0; + while (PyDict_Next(kwargs, &j, &key, NULL)) { int match = 0; if (!PyUnicode_Check(key)) { PyErr_SetString(PyExc_TypeError, "keywords must be strings"); return cleanreturn(0, &freelist); } - for (i = 0; i < len; i++) { - if (*kwlist[i] && _PyUnicode_EqualToASCIIString(key, kwlist[i])) { + for (i = pos; i < len; i++) { + if (_PyUnicode_EqualToASCIIString(key, kwlist[i])) { match = 1; break; } @@ -1956,10 +1966,13 @@ parser_clear(struct _PyArg_Parser *parser) } static PyObject* -find_keyword(PyObject *kwnames, PyObject **kwstack, PyObject *key) +find_keyword(PyObject *kwargs, PyObject *kwnames, PyObject **kwstack, PyObject *key) { Py_ssize_t i, nkwargs; + if (kwargs != NULL) { + return PyDict_GetItem(kwargs, key); + } nkwargs = PyTuple_GET_SIZE(kwnames); for (i=0; i < nkwargs; i++) { PyObject *kwname = PyTuple_GET_ITEM(kwnames, i); @@ -1971,7 +1984,7 @@ find_keyword(PyObject *kwnames, PyObject **kwstack, PyObject *key) } if (!PyUnicode_Check(kwname)) { /* ignore non-string keyword keys: - an error will be raised above */ + an error will be raised below */ continue; } if (_PyUnicode_EQ(kwname, key)) { @@ -1983,7 +1996,7 @@ find_keyword(PyObject *kwnames, PyObject **kwstack, PyObject *key) static int vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, - PyObject *keywords, PyObject *kwnames, + PyObject *kwargs, PyObject *kwnames, struct _PyArg_Parser *parser, va_list *p_va, int flags) { @@ -1994,7 +2007,7 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, const char *msg; PyObject *keyword; int i, pos, len; - Py_ssize_t nkeywords; + Py_ssize_t nkwargs; PyObject *current_arg; freelistentry_t static_entries[STATIC_FREELIST_ENTRIES]; freelist_t freelist; @@ -2004,13 +2017,20 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, freelist.first_available = 0; freelist.entries_malloced = 0; - assert(keywords == NULL || PyDict_Check(keywords)); - assert(kwnames == NULL || PyTuple_Check(kwnames)); - assert((keywords != NULL || kwnames != NULL) - || (keywords == NULL && kwnames == NULL)); - assert(parser != NULL); + assert(kwargs == NULL || PyDict_Check(kwargs)); + assert(kwargs == NULL || kwnames == NULL); assert(p_va != NULL); + if (parser == NULL) { + PyErr_BadInternalCall(); + return 0; + } + + if (kwnames != NULL && !PyTuple_Check(kwnames)) { + PyErr_BadInternalCall(); + return 0; + } + if (!parser_init(parser)) { return 0; } @@ -2028,24 +2048,24 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, freelist.entries_malloced = 1; } - if (keywords != NULL) { - nkeywords = PyDict_Size(keywords); + if (kwargs != NULL) { + nkwargs = PyDict_GET_SIZE(kwargs); } else if (kwnames != NULL) { - nkeywords = PyTuple_GET_SIZE(kwnames); + nkwargs = PyTuple_GET_SIZE(kwnames); kwstack = args + nargs; } else { - nkeywords = 0; + nkwargs = 0; } - if (nargs + nkeywords > len) { + if (nargs + nkwargs > len) { PyErr_Format(PyExc_TypeError, "%s%s takes at most %d argument%s (%zd given)", (parser->fname == NULL) ? "function" : parser->fname, (parser->fname == NULL) ? "" : "()", len, (len == 1) ? "" : "s", - nargs + nkeywords); + nargs + nkwargs); return cleanreturn(0, &freelist); } if (parser->max < nargs) { @@ -2059,7 +2079,6 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, format = parser->format; /* convert tuple args and keyword args in same loop, using kwtuple to drive process */ for (i = 0; i < len; i++) { - keyword = (i >= pos) ? PyTuple_GET_ITEM(kwtuple, i - pos) : NULL; if (*format == '|') { format++; } @@ -2068,31 +2087,17 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, } assert(!IS_END_OF_FORMAT(*format)); - current_arg = NULL; - if (nkeywords && i >= pos) { - if (keywords != NULL) { - current_arg = PyDict_GetItem(keywords, keyword); - if (!current_arg && PyErr_Occurred()) { - return cleanreturn(0, &freelist); - } - } - else { - current_arg = find_keyword(kwnames, kwstack, keyword); - } + if (i < nargs) { + current_arg = args[i]; } - if (current_arg) { - --nkeywords; - if (i < nargs) { - /* arg present in tuple and in dict */ - PyErr_Format(PyExc_TypeError, - "Argument given by name ('%U') " - "and position (%d)", - keyword, i+1); - return cleanreturn(0, &freelist); - } + else if (nkwargs && i >= pos) { + keyword = PyTuple_GET_ITEM(kwtuple, i - pos); + current_arg = find_keyword(kwargs, kwnames, kwstack, keyword); + if (current_arg) + --nkwargs; } - else if (i < nargs) { - current_arg = args[i]; + else { + current_arg = NULL; } if (current_arg) { @@ -2108,13 +2113,15 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, if (i < parser->min) { /* Less arguments than required */ if (i < pos) { + Py_ssize_t min = Py_MIN(pos, parser->min); PyErr_Format(PyExc_TypeError, "Function takes %s %d positional arguments" " (%d given)", - (Py_MIN(pos, parser->min) < parser->max) ? "at least" : "exactly", - Py_MIN(pos, parser->min), nargs); + min < parser->max ? "at least" : "exactly", + min, nargs); } else { + keyword = PyTuple_GET_ITEM(kwtuple, i - pos); PyErr_Format(PyExc_TypeError, "Required argument " "'%U' (pos %d) not found", keyword, i+1); @@ -2125,7 +2132,7 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, * fulfilled and no keyword args left, with no further * validation. XXX Maybe skip this in debug build ? */ - if (!nkeywords) { + if (!nkwargs) { return cleanreturn(1, &freelist); } @@ -2137,54 +2144,50 @@ vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs, assert(IS_END_OF_FORMAT(*format) || (*format == '|') || (*format == '$')); - /* make sure there are no extraneous keyword arguments */ - if (nkeywords > 0) { - if (keywords != NULL) { - PyObject *key, *value; - Py_ssize_t pos = 0; - while (PyDict_Next(keywords, &pos, &key, &value)) { - int match; - if (!PyUnicode_Check(key)) { - PyErr_SetString(PyExc_TypeError, - "keywords must be strings"); - return cleanreturn(0, &freelist); - } - match = PySequence_Contains(kwtuple, key); - if (match <= 0) { - if (!match) { - PyErr_Format(PyExc_TypeError, - "'%U' is an invalid keyword " - "argument for this function", - key); - } - return cleanreturn(0, &freelist); - } + if (nkwargs > 0) { + Py_ssize_t j; + /* make sure there are no arguments given by name and position */ + for (i = pos; i < nargs; i++) { + keyword = PyTuple_GET_ITEM(kwtuple, i - pos); + current_arg = find_keyword(kwargs, kwnames, kwstack, keyword); + if (current_arg) { + /* arg present in tuple and in dict */ + PyErr_Format(PyExc_TypeError, + "Argument given by name ('%U') " + "and position (%d)", + keyword, i+1); + return cleanreturn(0, &freelist); } } - else { - Py_ssize_t j, nkwargs; - - nkwargs = PyTuple_GET_SIZE(kwnames); - for (j=0; j < nkwargs; j++) { - PyObject *key = PyTuple_GET_ITEM(kwnames, j); - int match; - - if (!PyUnicode_Check(key)) { - PyErr_SetString(PyExc_TypeError, - "keywords must be strings"); - return cleanreturn(0, &freelist); - } + /* make sure there are no extraneous keyword arguments */ + j = 0; + while (1) { + int match; + if (kwargs != NULL) { + if (!PyDict_Next(kwargs, &j, &keyword, NULL)) + break; + } + else { + if (j >= PyTuple_GET_SIZE(kwnames)) + break; + keyword = PyTuple_GET_ITEM(kwnames, j); + j++; + } - match = PySequence_Contains(kwtuple, key); - if (match <= 0) { - if (!match) { - PyErr_Format(PyExc_TypeError, - "'%U' is an invalid keyword " - "argument for this function", - key); - } - return cleanreturn(0, &freelist); + if (!PyUnicode_Check(keyword)) { + PyErr_SetString(PyExc_TypeError, + "keywords must be strings"); + return cleanreturn(0, &freelist); + } + match = PySequence_Contains(kwtuple, keyword); + if (match <= 0) { + if (!match) { + PyErr_Format(PyExc_TypeError, + "'%U' is an invalid keyword " + "argument for this function", + keyword); } + return cleanreturn(0, &freelist); } } } @@ -2199,7 +2202,13 @@ vgetargskeywordsfast(PyObject *args, PyObject *keywords, PyObject **stack; Py_ssize_t nargs; - assert(args != NULL && PyTuple_Check(args)); + if (args == NULL + || !PyTuple_Check(args) + || (keywords != NULL && !PyDict_Check(keywords))) + { + PyErr_BadInternalCall(); + return 0; + } stack = &PyTuple_GET_ITEM(args, 0); nargs = PyTuple_GET_SIZE(args); @@ -2342,21 +2351,16 @@ err: } -int -PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...) +static int +PyArg_UnpackStack_impl(PyObject **args, Py_ssize_t l, const char *name, + Py_ssize_t min, Py_ssize_t max, va_list vargs) { - Py_ssize_t i, l; + Py_ssize_t i; PyObject **o; - va_list vargs; assert(min >= 0); assert(min <= max); - if (!PyTuple_Check(args)) { - PyErr_SetString(PyExc_SystemError, - "PyArg_UnpackTuple() argument list is not a tuple"); - return 0; - } - l = PyTuple_GET_SIZE(args); + if (l < min) { if (name != NULL) PyErr_Format( @@ -2371,8 +2375,11 @@ PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t m (min == max ? "" : "at least "), min, l); return 0; } - if (l == 0) + + if (l == 0) { return 1; + } + if (l > max) { if (name != NULL) PyErr_Format( @@ -2388,17 +2395,54 @@ PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t m return 0; } + for (i = 0; i < l; i++) { + o = va_arg(vargs, PyObject **); + *o = args[i]; + } + return 1; +} + +int +PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t max, ...) +{ + PyObject **stack; + Py_ssize_t nargs; + int retval; + va_list vargs; + + if (!PyTuple_Check(args)) { + PyErr_SetString(PyExc_SystemError, + "PyArg_UnpackTuple() argument list is not a tuple"); + return 0; + } + stack = &PyTuple_GET_ITEM(args, 0); + nargs = PyTuple_GET_SIZE(args); + #ifdef HAVE_STDARG_PROTOTYPES va_start(vargs, max); #else va_start(vargs); #endif - for (i = 0; i < l; i++) { - o = va_arg(vargs, PyObject **); - *o = PyTuple_GET_ITEM(args, i); - } + retval = PyArg_UnpackStack_impl(stack, nargs, name, min, max, vargs); va_end(vargs); - return 1; + return retval; +} + +int +_PyArg_UnpackStack(PyObject **args, Py_ssize_t nargs, const char *name, + Py_ssize_t min, Py_ssize_t max, ...) +{ + int retval; + va_list vargs; + +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, max); +#else + va_start(vargs); +#endif + retval = PyArg_UnpackStack_impl(args, nargs, name, min, max, vargs); + va_end(vargs); + return retval; } @@ -2408,16 +2452,35 @@ PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t m * not empty, returns 1 otherwise */ int -_PyArg_NoKeywords(const char *funcname, PyObject *kw) +_PyArg_NoKeywords(const char *funcname, PyObject *kwargs) { - if (kw == NULL) + if (kwargs == NULL) { return 1; - if (!PyDict_CheckExact(kw)) { + } + if (!PyDict_CheckExact(kwargs)) { PyErr_BadInternalCall(); return 0; } - if (PyDict_Size(kw) == 0) + if (PyDict_GET_SIZE(kwargs) == 0) { return 1; + } + + PyErr_Format(PyExc_TypeError, "%s does not take keyword arguments", + funcname); + return 0; +} + + +int +_PyArg_NoStackKeywords(const char *funcname, PyObject *kwnames) +{ + if (kwnames == NULL) { + return 1; + } + assert(PyTuple_CheckExact(kwnames)); + if (PyTuple_GET_SIZE(kwnames) == 0) { + return 1; + } PyErr_Format(PyExc_TypeError, "%s does not take keyword arguments", funcname); |