summaryrefslogtreecommitdiff
path: root/Python/getargs.c
diff options
context:
space:
mode:
Diffstat (limited to 'Python/getargs.c')
-rw-r--r--Python/getargs.c867
1 files changed, 731 insertions, 136 deletions
diff --git a/Python/getargs.c b/Python/getargs.c
index b10e7769e8..616c6eb107 100644
--- a/Python/getargs.c
+++ b/Python/getargs.c
@@ -18,16 +18,28 @@ int PyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
int PyArg_VaParseTupleAndKeywords(PyObject *, PyObject *,
const char *, char **, va_list);
+int _PyArg_ParseTupleAndKeywordsFast(PyObject *, PyObject *,
+ struct _PyArg_Parser *, ...);
+int _PyArg_VaParseTupleAndKeywordsFast(PyObject *, PyObject *,
+ struct _PyArg_Parser *, va_list);
+
#ifdef HAVE_DECLSPEC_DLL
/* Export functions */
-PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, char *, ...);
-PyAPI_FUNC(int) _PyArg_ParseTuple_SizeT(PyObject *, char *, ...);
+PyAPI_FUNC(int) _PyArg_Parse_SizeT(PyObject *, const char *, ...);
+PyAPI_FUNC(int) _PyArg_ParseStack_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 *,
const char *, char **, ...);
PyAPI_FUNC(PyObject *) _Py_BuildValue_SizeT(const char *, ...);
-PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, char *, va_list);
+PyAPI_FUNC(int) _PyArg_VaParse_SizeT(PyObject *, const char *, va_list);
PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *, PyObject *,
const char *, char **, va_list);
+
+PyAPI_FUNC(int) _PyArg_ParseTupleAndKeywordsFast_SizeT(PyObject *, PyObject *,
+ struct _PyArg_Parser *, ...);
+PyAPI_FUNC(int) _PyArg_VaParseTupleAndKeywordsFast_SizeT(PyObject *, PyObject *,
+ struct _PyArg_Parser *, va_list);
#endif
#define FLAG_COMPAT 1
@@ -56,18 +68,24 @@ typedef struct {
/* Forward */
static int vgetargs1(PyObject *, const char *, va_list *, int);
static void seterror(Py_ssize_t, const char *, int *, const char *, const char *);
-static char *convertitem(PyObject *, const char **, va_list *, int, int *,
- char *, size_t, freelist_t *);
-static char *converttuple(PyObject *, const char **, va_list *, int,
- int *, char *, size_t, int, freelist_t *);
-static char *convertsimple(PyObject *, const char **, va_list *, int, char *,
- size_t, freelist_t *);
-static Py_ssize_t convertbuffer(PyObject *, void **p, char **);
-static int getbuffer(PyObject *, Py_buffer *, char**);
+static const char *convertitem(PyObject *, const char **, va_list *, int, int *,
+ char *, size_t, freelist_t *);
+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 int getbuffer(PyObject *, Py_buffer *, const char**);
static int vgetargskeywords(PyObject *, PyObject *,
const char *, char **, va_list *, int);
-static char *skipitem(const char **, va_list *, int);
+static int vgetargskeywordsfast(PyObject *, PyObject *,
+ struct _PyArg_Parser *, va_list *, int);
+static int vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
+ PyObject *keywords, PyObject *kwnames,
+ struct _PyArg_Parser *parser,
+ va_list *p_va, int flags);
+static const char *skipitem(const char **, va_list *, int);
int
PyArg_Parse(PyObject *args, const char *format, ...)
@@ -82,7 +100,7 @@ PyArg_Parse(PyObject *args, const char *format, ...)
}
int
-_PyArg_Parse_SizeT(PyObject *args, char *format, ...)
+_PyArg_Parse_SizeT(PyObject *args, const char *format, ...)
{
int retval;
va_list va;
@@ -107,7 +125,7 @@ PyArg_ParseTuple(PyObject *args, const char *format, ...)
}
int
-_PyArg_ParseTuple_SizeT(PyObject *args, char *format, ...)
+_PyArg_ParseTuple_SizeT(PyObject *args, const char *format, ...)
{
int retval;
va_list va;
@@ -123,20 +141,26 @@ int
PyArg_VaParse(PyObject *args, const char *format, va_list va)
{
va_list lva;
+ int retval;
- Py_VA_COPY(lva, va);
+ va_copy(lva, va);
- return vgetargs1(args, format, &lva, 0);
+ retval = vgetargs1(args, format, &lva, 0);
+ va_end(lva);
+ return retval;
}
int
-_PyArg_VaParse_SizeT(PyObject *args, char *format, va_list va)
+_PyArg_VaParse_SizeT(PyObject *args, const char *format, va_list va)
{
va_list lva;
+ int retval;
- Py_VA_COPY(lva, va);
+ va_copy(lva, va);
- return vgetargs1(args, format, &lva, FLAG_SIZE_T);
+ retval = vgetargs1(args, format, &lva, FLAG_SIZE_T);
+ va_end(lva);
+ return retval;
}
@@ -208,7 +232,7 @@ vgetargs1(PyObject *args, const char *format, va_list *p_va, int flags)
int endfmt = 0;
const char *formatsave = format;
Py_ssize_t i, len;
- char *msg;
+ const char *msg;
int compat = flags & FLAG_COMPAT;
freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
freelist_t freelist;
@@ -394,7 +418,12 @@ seterror(Py_ssize_t iarg, const char *msg, int *levels, const char *fname,
PyOS_snprintf(p, sizeof(buf) - (p - buf), " %.256s", msg);
message = buf;
}
- PyErr_SetString(PyExc_TypeError, message);
+ if (msg[0] == '(') {
+ PyErr_SetString(PyExc_SystemError, message);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, message);
+ }
}
@@ -416,7 +445,7 @@ seterror(Py_ssize_t iarg, const char *msg, int *levels, const char *fname,
and msgbuf is returned.
*/
-static char *
+static const char *
converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
int *levels, char *msgbuf, size_t bufsize, int toplevel,
freelist_t *freelist)
@@ -474,7 +503,7 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
format = *p_format;
for (i = 0; i < n; i++) {
- char *msg;
+ const char *msg;
PyObject *item;
item = PySequence_GetItem(arg, i);
if (item == NULL) {
@@ -501,11 +530,11 @@ converttuple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
/* Convert a single item. */
-static char *
+static const char *
convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags,
int *levels, char *msgbuf, size_t bufsize, freelist_t *freelist)
{
- char *msg;
+ const char *msg;
const char *format = *p_format;
if (*format == '(' /* ')' */) {
@@ -530,7 +559,7 @@ convertitem(PyObject *arg, const char **p_format, va_list *p_va, int flags,
/* Format an error message generated by convertsimple(). */
-static char *
+static const char *
converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize)
{
assert(expected != NULL);
@@ -572,7 +601,7 @@ float_argument_error(PyObject *arg)
When you add new format codes, please don't forget poor skipitem() below.
*/
-static char *
+static const char *
convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
char *msgbuf, size_t bufsize, freelist_t *freelist)
{
@@ -752,14 +781,13 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
break;
}
-#ifdef HAVE_LONG_LONG
- case 'L': {/* PY_LONG_LONG */
- PY_LONG_LONG *p = va_arg( *p_va, PY_LONG_LONG * );
- PY_LONG_LONG ival;
+ case 'L': {/* long long */
+ long long *p = va_arg( *p_va, long long * );
+ long long ival;
if (float_argument_error(arg))
RETURN_ERR_OCCURRED;
ival = PyLong_AsLongLong(arg);
- if (ival == (PY_LONG_LONG)-1 && PyErr_Occurred())
+ if (ival == (long long)-1 && PyErr_Occurred())
RETURN_ERR_OCCURRED;
else
*p = ival;
@@ -767,8 +795,8 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
}
case 'K': { /* long long sized bitfield */
- unsigned PY_LONG_LONG *p = va_arg(*p_va, unsigned PY_LONG_LONG *);
- unsigned PY_LONG_LONG ival;
+ unsigned long long *p = va_arg(*p_va, unsigned long long *);
+ unsigned long long ival;
if (PyLong_Check(arg))
ival = PyLong_AsUnsignedLongLongMask(arg);
else
@@ -776,7 +804,6 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
*p = ival;
break;
}
-#endif
case 'f': {/* float */
float *p = va_arg(*p_va, float *);
@@ -857,7 +884,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
case 'y': {/* any bytes-like object */
void **p = (void **)va_arg(*p_va, char **);
- char *buf;
+ const char *buf;
Py_ssize_t count;
if (*format == '*') {
if (getbuffer(arg, (Py_buffer*)p, &buf) < 0)
@@ -904,7 +931,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
PyBuffer_FillInfo(p, arg, sarg, len, 1, 0);
}
else { /* any bytes-like object */
- char *buf;
+ const char *buf;
if (getbuffer(arg, p, &buf) < 0)
return converterr(buf, arg, msgbuf, bufsize);
}
@@ -934,7 +961,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
}
else { /* read-only bytes-like object */
/* XXX Really? */
- char *buf;
+ const char *buf;
Py_ssize_t count = convertbuffer(arg, p, &buf);
if (count < 0)
return converterr(buf, arg, msgbuf, bufsize);
@@ -1051,35 +1078,25 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
return converterr("(AsCharBuffer failed)",
arg, msgbuf, bufsize);
}
- else {
- PyObject *u;
-
- /* Convert object to Unicode */
- u = PyUnicode_FromObject(arg);
- if (u == NULL)
- return converterr(
- "string or unicode or text buffer",
- arg, msgbuf, bufsize);
-
+ else if (PyUnicode_Check(arg)) {
/* Encode object; use default error handling */
- s = PyUnicode_AsEncodedString(u,
+ s = PyUnicode_AsEncodedString(arg,
encoding,
NULL);
- Py_DECREF(u);
if (s == NULL)
return converterr("(encoding failed)",
arg, msgbuf, bufsize);
- if (!PyBytes_Check(s)) {
- Py_DECREF(s);
- return converterr(
- "(encoder failed to return bytes)",
- arg, msgbuf, bufsize);
- }
+ assert(PyBytes_Check(s));
size = PyBytes_GET_SIZE(s);
ptr = PyBytes_AS_STRING(s);
if (ptr == NULL)
ptr = "";
}
+ else {
+ return converterr(
+ recode_strings ? "str" : "str, bytes or bytearray",
+ arg, msgbuf, bufsize);
+ }
/* Write output; output is guaranteed to be 0-terminated */
if (*format == '#') {
@@ -1129,7 +1146,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
} else {
if (size + 1 > BUFFER_LEN) {
Py_DECREF(s);
- PyErr_Format(PyExc_TypeError,
+ PyErr_Format(PyExc_ValueError,
"encoded string too long "
"(%zd, maximum length %zd)",
(Py_ssize_t)size, (Py_ssize_t)(BUFFER_LEN-1));
@@ -1283,7 +1300,7 @@ convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
}
static Py_ssize_t
-convertbuffer(PyObject *arg, void **p, char **errmsg)
+convertbuffer(PyObject *arg, void **p, const char **errmsg)
{
PyBufferProcs *pb = Py_TYPE(arg)->tp_as_buffer;
Py_ssize_t count;
@@ -1305,7 +1322,7 @@ convertbuffer(PyObject *arg, void **p, char **errmsg)
}
static int
-getbuffer(PyObject *arg, Py_buffer *view, char **errmsg)
+getbuffer(PyObject *arg, Py_buffer *view, const char **errmsg)
{
if (PyObject_GetBuffer(arg, view, PyBUF_SIMPLE) != 0) {
*errmsg = "bytes-like object";
@@ -1391,9 +1408,10 @@ PyArg_VaParseTupleAndKeywords(PyObject *args,
return 0;
}
- Py_VA_COPY(lva, va);
+ va_copy(lva, va);
retval = vgetargskeywords(args, keywords, format, kwlist, &lva, 0);
+ va_end(lva);
return retval;
}
@@ -1415,10 +1433,138 @@ _PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args,
return 0;
}
- Py_VA_COPY(lva, va);
+ va_copy(lva, va);
retval = vgetargskeywords(args, keywords, format,
kwlist, &lva, FLAG_SIZE_T);
+ va_end(lva);
+ return retval;
+}
+
+int
+_PyArg_ParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, ...)
+{
+ 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);
+ return retval;
+}
+
+int
+_PyArg_ParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, ...)
+{
+ 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);
+ return retval;
+}
+
+int
+_PyArg_ParseStack(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);
+ return retval;
+}
+
+int
+_PyArg_ParseStack_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);
+ return retval;
+}
+
+
+int
+_PyArg_VaParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, va_list va)
+{
+ 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);
+ va_end(lva);
+ return retval;
+}
+
+int
+_PyArg_VaParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, va_list va)
+{
+ 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);
+ va_end(lva);
return retval;
}
@@ -1448,7 +1594,8 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
const char *fname, *msg, *custom_msg, *keyword;
int min = INT_MAX;
int max = INT_MAX;
- int i, len;
+ int i, pos, len;
+ int skip = 0;
Py_ssize_t nargs, nkeywords;
PyObject *current_arg;
freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
@@ -1476,9 +1623,17 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
custom_msg++;
}
+ /* scan kwlist and count the number of positional-only parameters */
+ for (pos = 0; kwlist[pos] && !*kwlist[pos]; pos++) {
+ }
/* scan kwlist and get greatest possible nbr of args */
- for (len=0; kwlist[len]; len++)
- continue;
+ for (len = pos; kwlist[len]; len++) {
+ if (!*kwlist[len]) {
+ PyErr_SetString(PyExc_SystemError,
+ "Empty keyword parameter name");
+ return cleanreturn(0, &freelist);
+ }
+ }
if (len > STATIC_FREELIST_ENTRIES) {
freelist.entries = PyMem_NEW(freelistentry_t, len);
@@ -1507,7 +1662,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
keyword = kwlist[i];
if (*format == '|') {
if (min != INT_MAX) {
- PyErr_SetString(PyExc_RuntimeError,
+ PyErr_SetString(PyExc_SystemError,
"Invalid format string (| specified twice)");
return cleanreturn(0, &freelist);
}
@@ -1516,14 +1671,14 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
format++;
if (max != INT_MAX) {
- PyErr_SetString(PyExc_RuntimeError,
+ PyErr_SetString(PyExc_SystemError,
"Invalid format string ($ before |)");
return cleanreturn(0, &freelist);
}
}
if (*format == '$') {
if (max != INT_MAX) {
- PyErr_SetString(PyExc_RuntimeError,
+ PyErr_SetString(PyExc_SystemError,
"Invalid format string ($ specified twice)");
return cleanreturn(0, &freelist);
}
@@ -1531,6 +1686,17 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
max = i;
format++;
+ if (max < pos) {
+ PyErr_SetString(PyExc_SystemError,
+ "Empty parameter name after $");
+ return cleanreturn(0, &freelist);
+ }
+ if (skip) {
+ /* Now we know the minimal and the maximal numbers of
+ * positional arguments and can raise an exception with
+ * informative message (see below). */
+ break;
+ }
if (max < nargs) {
PyErr_Format(PyExc_TypeError,
"Function takes %s %d positional arguments"
@@ -1541,66 +1707,90 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
}
}
if (IS_END_OF_FORMAT(*format)) {
- PyErr_Format(PyExc_RuntimeError,
+ PyErr_Format(PyExc_SystemError,
"More keyword list entries (%d) than "
"format specifiers (%d)", len, i);
return cleanreturn(0, &freelist);
}
- current_arg = NULL;
- if (nkeywords) {
- current_arg = PyDict_GetItemString(keywords, keyword);
- }
- 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);
+ if (!skip) {
+ current_arg = NULL;
+ if (nkeywords && i >= pos) {
+ current_arg = PyDict_GetItemString(keywords, keyword);
+ if (!current_arg && PyErr_Occurred()) {
+ return cleanreturn(0, &freelist);
+ }
}
- }
- else if (nkeywords && PyErr_Occurred())
- return cleanreturn(0, &freelist);
- else if (i < nargs)
- current_arg = PyTuple_GET_ITEM(args, i);
-
- if (current_arg) {
- msg = convertitem(current_arg, &format, p_va, flags,
- levels, msgbuf, sizeof(msgbuf), &freelist);
- if (msg) {
- seterror(i+1, msg, levels, fname, custom_msg);
- return cleanreturn(0, &freelist);
+ 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 (i < nargs)
+ current_arg = PyTuple_GET_ITEM(args, i);
+
+ if (current_arg) {
+ msg = convertitem(current_arg, &format, p_va, flags,
+ levels, msgbuf, sizeof(msgbuf), &freelist);
+ if (msg) {
+ seterror(i+1, msg, levels, fname, custom_msg);
+ return cleanreturn(0, &freelist);
+ }
+ continue;
}
- continue;
- }
- if (i < min) {
- PyErr_Format(PyExc_TypeError, "Required argument "
- "'%s' (pos %d) not found",
- keyword, i+1);
- return cleanreturn(0, &freelist);
+ if (i < min) {
+ if (i < pos) {
+ assert (min == INT_MAX);
+ assert (max == INT_MAX);
+ skip = 1;
+ /* At that moment we still don't know the minimal and
+ * the maximal numbers of positional arguments. Raising
+ * an exception is deferred until we encounter | and $
+ * or the end of the format. */
+ }
+ else {
+ PyErr_Format(PyExc_TypeError, "Required argument "
+ "'%s' (pos %d) not found",
+ keyword, i+1);
+ return cleanreturn(0, &freelist);
+ }
+ }
+ /* current code reports success when all required args
+ * fulfilled and no keyword args left, with no further
+ * validation. XXX Maybe skip this in debug build ?
+ */
+ if (!nkeywords && !skip) {
+ return cleanreturn(1, &freelist);
+ }
}
- /* current code reports success when all required args
- * fulfilled and no keyword args left, with no further
- * validation. XXX Maybe skip this in debug build ?
- */
- if (!nkeywords)
- return cleanreturn(1, &freelist);
/* We are into optional args, skip thru to any remaining
* keyword args */
msg = skipitem(&format, p_va, flags);
if (msg) {
- PyErr_Format(PyExc_RuntimeError, "%s: '%s'", msg,
+ PyErr_Format(PyExc_SystemError, "%s: '%s'", msg,
format);
return cleanreturn(0, &freelist);
}
}
+ if (skip) {
+ PyErr_Format(PyExc_TypeError,
+ "Function takes %s %d positional arguments"
+ " (%d given)",
+ (Py_MIN(pos, min) < i) ? "at least" : "exactly",
+ Py_MIN(pos, min), nargs);
+ return cleanreturn(0, &freelist);
+ }
+
if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) {
- PyErr_Format(PyExc_RuntimeError,
+ PyErr_Format(PyExc_SystemError,
"more argument specifiers than keyword list entries "
"(remaining format:'%s')", format);
return cleanreturn(0, &freelist);
@@ -1618,7 +1808,7 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
return cleanreturn(0, &freelist);
}
for (i = 0; i < len; i++) {
- if (_PyUnicode_EqualToASCIIString(key, kwlist[i])) {
+ if (*kwlist[i] && _PyUnicode_EqualToASCIIString(key, kwlist[i])) {
match = 1;
break;
}
@@ -1637,7 +1827,388 @@ vgetargskeywords(PyObject *args, PyObject *keywords, const char *format,
}
-static char *
+/* List of static parsers. */
+static struct _PyArg_Parser *static_arg_parsers = NULL;
+
+static int
+parser_init(struct _PyArg_Parser *parser)
+{
+ const char * const *keywords;
+ const char *format, *msg;
+ int i, len, min, max, nkw;
+ PyObject *kwtuple;
+
+ assert(parser->format != NULL);
+ assert(parser->keywords != NULL);
+ if (parser->kwtuple != NULL) {
+ return 1;
+ }
+
+ /* grab the function name or custom error msg first (mutually exclusive) */
+ parser->fname = strchr(parser->format, ':');
+ if (parser->fname) {
+ parser->fname++;
+ parser->custom_msg = NULL;
+ }
+ else {
+ parser->custom_msg = strchr(parser->format,';');
+ if (parser->custom_msg)
+ parser->custom_msg++;
+ }
+
+ keywords = parser->keywords;
+ /* scan keywords and count the number of positional-only parameters */
+ for (i = 0; keywords[i] && !*keywords[i]; i++) {
+ }
+ parser->pos = i;
+ /* scan keywords and get greatest possible nbr of args */
+ for (; keywords[i]; i++) {
+ if (!*keywords[i]) {
+ PyErr_SetString(PyExc_SystemError,
+ "Empty keyword parameter name");
+ return 0;
+ }
+ }
+ len = i;
+
+ min = max = INT_MAX;
+ format = parser->format;
+ for (i = 0; i < len; i++) {
+ if (*format == '|') {
+ if (min != INT_MAX) {
+ PyErr_SetString(PyExc_SystemError,
+ "Invalid format string (| specified twice)");
+ return 0;
+ }
+ if (max != INT_MAX) {
+ PyErr_SetString(PyExc_SystemError,
+ "Invalid format string ($ before |)");
+ return 0;
+ }
+ min = i;
+ format++;
+ }
+ if (*format == '$') {
+ if (max != INT_MAX) {
+ PyErr_SetString(PyExc_SystemError,
+ "Invalid format string ($ specified twice)");
+ return 0;
+ }
+ if (i < parser->pos) {
+ PyErr_SetString(PyExc_SystemError,
+ "Empty parameter name after $");
+ return 0;
+ }
+ max = i;
+ format++;
+ }
+ if (IS_END_OF_FORMAT(*format)) {
+ PyErr_Format(PyExc_SystemError,
+ "More keyword list entries (%d) than "
+ "format specifiers (%d)", len, i);
+ return 0;
+ }
+
+ msg = skipitem(&format, NULL, 0);
+ if (msg) {
+ PyErr_Format(PyExc_SystemError, "%s: '%s'", msg,
+ format);
+ return 0;
+ }
+ }
+ parser->min = Py_MIN(min, len);
+ parser->max = Py_MIN(max, len);
+
+ if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) {
+ PyErr_Format(PyExc_SystemError,
+ "more argument specifiers than keyword list entries "
+ "(remaining format:'%s')", format);
+ return 0;
+ }
+
+ nkw = len - parser->pos;
+ kwtuple = PyTuple_New(nkw);
+ if (kwtuple == NULL) {
+ return 0;
+ }
+ keywords = parser->keywords + parser->pos;
+ for (i = 0; i < nkw; i++) {
+ PyObject *str = PyUnicode_FromString(keywords[i]);
+ if (str == NULL) {
+ Py_DECREF(kwtuple);
+ return 0;
+ }
+ PyUnicode_InternInPlace(&str);
+ PyTuple_SET_ITEM(kwtuple, i, str);
+ }
+ parser->kwtuple = kwtuple;
+
+ assert(parser->next == NULL);
+ parser->next = static_arg_parsers;
+ static_arg_parsers = parser;
+ return 1;
+}
+
+static void
+parser_clear(struct _PyArg_Parser *parser)
+{
+ Py_CLEAR(parser->kwtuple);
+}
+
+static PyObject*
+find_keyword(PyObject *kwnames, PyObject **kwstack, PyObject *key)
+{
+ Py_ssize_t i, nkwargs;
+
+ nkwargs = PyTuple_GET_SIZE(kwnames);
+ for (i=0; i < nkwargs; i++) {
+ PyObject *kwname = PyTuple_GET_ITEM(kwnames, i);
+
+ /* ptr==ptr should match in most cases since keyword keys
+ should be interned strings */
+ if (kwname == key) {
+ return kwstack[i];
+ }
+ if (!PyUnicode_Check(kwname)) {
+ /* ignore non-string keyword keys:
+ an error will be raised above */
+ continue;
+ }
+ if (_PyUnicode_EQ(kwname, key)) {
+ return kwstack[i];
+ }
+ }
+ return NULL;
+}
+
+static int
+vgetargskeywordsfast_impl(PyObject **args, Py_ssize_t nargs,
+ PyObject *keywords, PyObject *kwnames,
+ struct _PyArg_Parser *parser,
+ va_list *p_va, int flags)
+{
+ PyObject *kwtuple;
+ char msgbuf[512];
+ int levels[32];
+ const char *format;
+ const char *msg;
+ PyObject *keyword;
+ int i, pos, len;
+ Py_ssize_t nkeywords;
+ PyObject *current_arg;
+ freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
+ freelist_t freelist;
+ PyObject **kwstack = NULL;
+
+ freelist.entries = static_entries;
+ 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(p_va != NULL);
+
+ if (!parser_init(parser)) {
+ return 0;
+ }
+
+ kwtuple = parser->kwtuple;
+ pos = parser->pos;
+ len = pos + PyTuple_GET_SIZE(kwtuple);
+
+ if (len > STATIC_FREELIST_ENTRIES) {
+ freelist.entries = PyMem_NEW(freelistentry_t, len);
+ if (freelist.entries == NULL) {
+ PyErr_NoMemory();
+ return 0;
+ }
+ freelist.entries_malloced = 1;
+ }
+
+ if (keywords != NULL) {
+ nkeywords = PyDict_Size(keywords);
+ }
+ else if (kwnames != NULL) {
+ nkeywords = PyTuple_GET_SIZE(kwnames);
+ kwstack = args + nargs;
+ }
+ else {
+ nkeywords = 0;
+ }
+ if (nargs + nkeywords > 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);
+ return cleanreturn(0, &freelist);
+ }
+ if (parser->max < nargs) {
+ PyErr_Format(PyExc_TypeError,
+ "Function takes %s %d positional arguments (%d given)",
+ (parser->min != INT_MAX) ? "at most" : "exactly",
+ parser->max, nargs);
+ return cleanreturn(0, &freelist);
+ }
+
+ 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++;
+ }
+ if (*format == '$') {
+ format++;
+ }
+ 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 (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 (i < nargs) {
+ current_arg = args[i];
+ }
+
+ if (current_arg) {
+ msg = convertitem(current_arg, &format, p_va, flags,
+ levels, msgbuf, sizeof(msgbuf), &freelist);
+ if (msg) {
+ seterror(i+1, msg, levels, parser->fname, parser->custom_msg);
+ return cleanreturn(0, &freelist);
+ }
+ continue;
+ }
+
+ if (i < parser->min) {
+ /* Less arguments than required */
+ if (i < pos) {
+ 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);
+ }
+ else {
+ PyErr_Format(PyExc_TypeError, "Required argument "
+ "'%U' (pos %d) not found",
+ keyword, i+1);
+ }
+ return cleanreturn(0, &freelist);
+ }
+ /* current code reports success when all required args
+ * fulfilled and no keyword args left, with no further
+ * validation. XXX Maybe skip this in debug build ?
+ */
+ if (!nkeywords) {
+ return cleanreturn(1, &freelist);
+ }
+
+ /* We are into optional args, skip thru to any remaining
+ * keyword args */
+ msg = skipitem(&format, p_va, flags);
+ assert(msg == NULL);
+ }
+
+ 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);
+ }
+ }
+ }
+ 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);
+ }
+
+ 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);
+ }
+ }
+ }
+ }
+
+ return cleanreturn(1, &freelist);
+}
+
+static int
+vgetargskeywordsfast(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, va_list *p_va, int flags)
+{
+ PyObject **stack;
+ Py_ssize_t nargs;
+
+ assert(args != NULL && PyTuple_Check(args));
+
+ stack = &PyTuple_GET_ITEM(args, 0);
+ nargs = PyTuple_GET_SIZE(args);
+ return vgetargskeywordsfast_impl(stack, nargs, keywords, NULL,
+ parser, p_va, flags);
+}
+
+
+static const char *
skipitem(const char **p_format, va_list *p_va, int flags)
{
const char *format = *p_format;
@@ -1658,10 +2229,8 @@ skipitem(const char **p_format, va_list *p_va, int flags)
case 'I': /* int sized bitfield */
case 'l': /* long int */
case 'k': /* long int sized bitfield */
-#ifdef HAVE_LONG_LONG
- case 'L': /* PY_LONG_LONG */
- case 'K': /* PY_LONG_LONG sized bitfield */
-#endif
+ case 'L': /* long long */
+ case 'K': /* long long sized bitfield */
case 'n': /* Py_ssize_t */
case 'f': /* float */
case 'd': /* double */
@@ -1673,7 +2242,9 @@ skipitem(const char **p_format, va_list *p_va, int flags)
case 'Y': /* string object */
case 'U': /* unicode string object */
{
- (void) va_arg(*p_va, void *);
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, void *);
+ }
break;
}
@@ -1681,7 +2252,9 @@ skipitem(const char **p_format, va_list *p_va, int flags)
case 'e': /* string with encoding */
{
- (void) va_arg(*p_va, const char *);
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, const char *);
+ }
if (!(*format == 's' || *format == 't'))
/* after 'e', only 's' and 't' is allowed */
goto err;
@@ -1696,12 +2269,16 @@ skipitem(const char **p_format, va_list *p_va, int flags)
case 'Z': /* unicode string or None */
case 'w': /* buffer, read-write */
{
- (void) va_arg(*p_va, char **);
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, char **);
+ }
if (*format == '#') {
- if (flags & FLAG_SIZE_T)
- (void) va_arg(*p_va, Py_ssize_t *);
- else
- (void) va_arg(*p_va, int *);
+ if (p_va != NULL) {
+ if (flags & FLAG_SIZE_T)
+ (void) va_arg(*p_va, Py_ssize_t *);
+ else
+ (void) va_arg(*p_va, int *);
+ }
format++;
} else if ((c == 's' || c == 'z' || c == 'y') && *format == '*') {
format++;
@@ -1713,24 +2290,30 @@ skipitem(const char **p_format, va_list *p_va, int flags)
{
if (*format == '!') {
format++;
- (void) va_arg(*p_va, PyTypeObject*);
- (void) va_arg(*p_va, PyObject **);
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, PyTypeObject*);
+ (void) va_arg(*p_va, PyObject **);
+ }
}
else if (*format == '&') {
typedef int (*converter)(PyObject *, void *);
- (void) va_arg(*p_va, converter);
- (void) va_arg(*p_va, void *);
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, converter);
+ (void) va_arg(*p_va, void *);
+ }
format++;
}
else {
- (void) va_arg(*p_va, PyObject **);
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, PyObject **);
+ }
}
break;
}
case '(': /* bypass tuple, not handled at all previously */
{
- char *msg;
+ const char *msg;
for (;;) {
if (*format==')')
break;
@@ -1766,16 +2349,9 @@ PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t m
PyObject **o;
va_list vargs;
-#ifdef HAVE_STDARG_PROTOTYPES
- va_start(vargs, max);
-#else
- va_start(vargs);
-#endif
-
assert(min >= 0);
assert(min <= max);
if (!PyTuple_Check(args)) {
- va_end(vargs);
PyErr_SetString(PyExc_SystemError,
"PyArg_UnpackTuple() argument list is not a tuple");
return 0;
@@ -1793,9 +2369,10 @@ PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t m
"unpacked tuple should have %s%zd elements,"
" but has %zd",
(min == max ? "" : "at least "), min, l);
- va_end(vargs);
return 0;
}
+ if (l == 0)
+ return 1;
if (l > max) {
if (name != NULL)
PyErr_Format(
@@ -1808,9 +2385,14 @@ PyArg_UnpackTuple(PyObject *args, const char *name, Py_ssize_t min, Py_ssize_t m
"unpacked tuple should have %s%zd elements,"
" but has %zd",
(min == max ? "" : "at most "), max, l);
- va_end(vargs);
return 0;
}
+
+#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);
@@ -1860,6 +2442,19 @@ _PyArg_NoPositional(const char *funcname, PyObject *args)
return 0;
}
+void
+_PyArg_Fini(void)
+{
+ struct _PyArg_Parser *tmp, *s = static_arg_parsers;
+ while (s) {
+ tmp = s->next;
+ s->next = NULL;
+ parser_clear(s);
+ s = tmp;
+ }
+ static_arg_parsers = NULL;
+}
+
#ifdef __cplusplus
};
#endif