aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/tools/python3/src/Python/getargs.c
diff options
context:
space:
mode:
authornkozlovskiy <nmk@ydb.tech>2023-09-29 12:24:06 +0300
committernkozlovskiy <nmk@ydb.tech>2023-09-29 12:41:34 +0300
commite0e3e1717e3d33762ce61950504f9637a6e669ed (patch)
treebca3ff6939b10ed60c3d5c12439963a1146b9711 /contrib/tools/python3/src/Python/getargs.c
parent38f2c5852db84c7b4d83adfcb009eb61541d1ccd (diff)
downloadydb-e0e3e1717e3d33762ce61950504f9637a6e669ed.tar.gz
add ydb deps
Diffstat (limited to 'contrib/tools/python3/src/Python/getargs.c')
-rw-r--r--contrib/tools/python3/src/Python/getargs.c2942
1 files changed, 2942 insertions, 0 deletions
diff --git a/contrib/tools/python3/src/Python/getargs.c b/contrib/tools/python3/src/Python/getargs.c
new file mode 100644
index 0000000000..3105bd556c
--- /dev/null
+++ b/contrib/tools/python3/src/Python/getargs.c
@@ -0,0 +1,2942 @@
+
+/* New getargs implementation */
+
+#include "Python.h"
+#include "pycore_tuple.h" // _PyTuple_ITEMS()
+#include "pycore_pylifecycle.h" // _PyArg_Fini
+
+#include <ctype.h>
+#include <float.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+int PyArg_Parse(PyObject *, const char *, ...);
+int PyArg_ParseTuple(PyObject *, const char *, ...);
+int PyArg_VaParse(PyObject *, const char *, va_list);
+
+int PyArg_ParseTupleAndKeywords(PyObject *, PyObject *,
+ const char *, char **, ...);
+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 *, const char *, ...);
+PyAPI_FUNC(int) _PyArg_ParseStack_SizeT(PyObject *const *args, Py_ssize_t nargs,
+ const char *format, ...);
+PyAPI_FUNC(int) _PyArg_ParseStackAndKeywords_SizeT(PyObject *const *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 *, 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
+#define FLAG_SIZE_T 2
+
+typedef int (*destr_t)(PyObject *, void *);
+
+
+/* Keep track of "objects" that have been allocated or initialized and
+ which will need to be deallocated or cleaned up somehow if overall
+ parsing fails.
+*/
+typedef struct {
+ void *item;
+ destr_t destructor;
+} freelistentry_t;
+
+typedef struct {
+ freelistentry_t *entries;
+ int first_available;
+ int entries_malloced;
+} freelist_t;
+
+#define STATIC_FREELIST_ENTRIES 8
+
+/* Forward */
+static int vgetargs1_impl(PyObject *args, PyObject *const *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 *,
+ 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 *, const void **p, const char **);
+static int getbuffer(PyObject *, Py_buffer *, const char**);
+
+static int vgetargskeywords(PyObject *, PyObject *,
+ const char *, char **, va_list *, int);
+static int vgetargskeywordsfast(PyObject *, PyObject *,
+ struct _PyArg_Parser *, va_list *, int);
+static int vgetargskeywordsfast_impl(PyObject *const *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, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, format);
+ retval = vgetargs1(args, format, &va, FLAG_COMPAT);
+ va_end(va);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_Parse_SizeT(PyObject *args, const char *format, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, format);
+ retval = vgetargs1(args, format, &va, FLAG_COMPAT|FLAG_SIZE_T);
+ va_end(va);
+ return retval;
+}
+
+
+int
+PyArg_ParseTuple(PyObject *args, const char *format, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, format);
+ retval = vgetargs1(args, format, &va, 0);
+ va_end(va);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_ParseTuple_SizeT(PyObject *args, const char *format, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, format);
+ retval = vgetargs1(args, format, &va, FLAG_SIZE_T);
+ va_end(va);
+ return retval;
+}
+
+
+int
+_PyArg_ParseStack(PyObject *const *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;
+}
+
+PyAPI_FUNC(int)
+_PyArg_ParseStack_SizeT(PyObject *const *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;
+ int retval;
+
+ va_copy(lva, va);
+
+ retval = vgetargs1(args, format, &lva, 0);
+ va_end(lva);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_VaParse_SizeT(PyObject *args, const char *format, va_list va)
+{
+ va_list lva;
+ int retval;
+
+ va_copy(lva, va);
+
+ retval = vgetargs1(args, format, &lva, FLAG_SIZE_T);
+ va_end(lva);
+ return retval;
+}
+
+
+/* Handle cleanup of allocated memory in case of exception */
+
+static int
+cleanup_ptr(PyObject *self, void *ptr)
+{
+ void **pptr = (void **)ptr;
+ PyMem_Free(*pptr);
+ *pptr = NULL;
+ return 0;
+}
+
+static int
+cleanup_buffer(PyObject *self, void *ptr)
+{
+ Py_buffer *buf = (Py_buffer *)ptr;
+ if (buf) {
+ PyBuffer_Release(buf);
+ }
+ return 0;
+}
+
+static int
+addcleanup(void *ptr, freelist_t *freelist, destr_t destructor)
+{
+ int index;
+
+ index = freelist->first_available;
+ freelist->first_available += 1;
+
+ freelist->entries[index].item = ptr;
+ freelist->entries[index].destructor = destructor;
+
+ return 0;
+}
+
+static int
+cleanreturn(int retval, freelist_t *freelist)
+{
+ int index;
+
+ if (retval == 0) {
+ /* A failure occurred, therefore execute all of the cleanup
+ functions.
+ */
+ for (index = 0; index < freelist->first_available; ++index) {
+ freelist->entries[index].destructor(NULL,
+ freelist->entries[index].item);
+ }
+ }
+ if (freelist->entries_malloced)
+ PyMem_Free(freelist->entries);
+ return retval;
+}
+
+
+static int
+vgetargs1_impl(PyObject *compat_args, PyObject *const *stack, Py_ssize_t nargs, const char *format,
+ va_list *p_va, int flags)
+{
+ char msgbuf[256];
+ int levels[32];
+ const char *fname = NULL;
+ const char *message = NULL;
+ int min = -1;
+ int max = 0;
+ int level = 0;
+ int endfmt = 0;
+ const char *formatsave = format;
+ 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;
+
+ flags = flags & ~FLAG_COMPAT;
+
+ while (endfmt == 0) {
+ int c = *format++;
+ switch (c) {
+ case '(':
+ if (level == 0)
+ max++;
+ level++;
+ if (level >= 30)
+ Py_FatalError("too many tuple nesting levels "
+ "in argument format string");
+ break;
+ case ')':
+ if (level == 0)
+ Py_FatalError("excess ')' in getargs format");
+ else
+ level--;
+ break;
+ case '\0':
+ endfmt = 1;
+ break;
+ case ':':
+ fname = format;
+ endfmt = 1;
+ break;
+ case ';':
+ message = format;
+ endfmt = 1;
+ break;
+ case '|':
+ if (level == 0)
+ min = max;
+ break;
+ default:
+ if (level == 0) {
+ if (Py_ISALPHA(c))
+ if (c != 'e') /* skip encoded */
+ max++;
+ }
+ break;
+ }
+ }
+
+ if (level != 0)
+ Py_FatalError(/* '(' */ "missing ')' in getargs format");
+
+ if (min < 0)
+ min = max;
+
+ format = formatsave;
+
+ if (max > STATIC_FREELIST_ENTRIES) {
+ freelist.entries = PyMem_NEW(freelistentry_t, max);
+ if (freelist.entries == NULL) {
+ PyErr_NoMemory();
+ return 0;
+ }
+ freelist.entries_malloced = 1;
+ }
+
+ if (compat) {
+ if (max == 0) {
+ if (compat_args == NULL)
+ return 1;
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes no arguments",
+ fname==NULL ? "function" : fname,
+ fname==NULL ? "" : "()");
+ return cleanreturn(0, &freelist);
+ }
+ else if (min == 1 && max == 1) {
+ 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(compat_args, &format, p_va, flags, levels,
+ msgbuf, sizeof(msgbuf), &freelist);
+ if (msg == NULL)
+ return cleanreturn(1, &freelist);
+ seterror(levels[0], msg, levels+1, fname, message);
+ return cleanreturn(0, &freelist);
+ }
+ else {
+ PyErr_SetString(PyExc_SystemError,
+ "old style getargs format uses new features");
+ return cleanreturn(0, &freelist);
+ }
+ }
+
+ if (nargs < min || max < nargs) {
+ if (message == NULL)
+ PyErr_Format(PyExc_TypeError,
+ "%.150s%s takes %s %d argument%s (%zd given)",
+ fname==NULL ? "function" : fname,
+ fname==NULL ? "" : "()",
+ min==max ? "exactly"
+ : nargs < min ? "at least" : "at most",
+ nargs < min ? min : max,
+ (nargs < min ? min : max) == 1 ? "" : "s",
+ nargs);
+ else
+ PyErr_SetString(PyExc_TypeError, message);
+ return cleanreturn(0, &freelist);
+ }
+
+ for (i = 0; i < nargs; i++) {
+ if (*format == '|')
+ format++;
+ msg = convertitem(stack[i], &format, p_va,
+ flags, levels, msgbuf,
+ sizeof(msgbuf), &freelist);
+ if (msg) {
+ seterror(i+1, msg, levels, fname, message);
+ return cleanreturn(0, &freelist);
+ }
+ }
+
+ if (*format != '\0' && !Py_ISALPHA(*format) &&
+ *format != '(' &&
+ *format != '|' && *format != ':' && *format != ';') {
+ PyErr_Format(PyExc_SystemError,
+ "bad format string: %.200s", formatsave);
+ return cleanreturn(0, &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_ITEMS(args);
+ nargs = PyTuple_GET_SIZE(args);
+ }
+ else {
+ stack = NULL;
+ nargs = 0;
+ }
+
+ return vgetargs1_impl(args, stack, nargs, format, p_va, flags);
+}
+
+
+static void
+seterror(Py_ssize_t iarg, const char *msg, int *levels, const char *fname,
+ const char *message)
+{
+ char buf[512];
+ int i;
+ char *p = buf;
+
+ if (PyErr_Occurred())
+ return;
+ else if (message == NULL) {
+ if (fname != NULL) {
+ PyOS_snprintf(p, sizeof(buf), "%.200s() ", fname);
+ p += strlen(p);
+ }
+ if (iarg != 0) {
+ PyOS_snprintf(p, sizeof(buf) - (p - buf),
+ "argument %zd", iarg);
+ i = 0;
+ p += strlen(p);
+ while (i < 32 && levels[i] > 0 && (int)(p-buf) < 220) {
+ PyOS_snprintf(p, sizeof(buf) - (p - buf),
+ ", item %d", levels[i]-1);
+ p += strlen(p);
+ i++;
+ }
+ }
+ else {
+ PyOS_snprintf(p, sizeof(buf) - (p - buf), "argument");
+ p += strlen(p);
+ }
+ PyOS_snprintf(p, sizeof(buf) - (p - buf), " %.256s", msg);
+ message = buf;
+ }
+ if (msg[0] == '(') {
+ PyErr_SetString(PyExc_SystemError, message);
+ }
+ else {
+ PyErr_SetString(PyExc_TypeError, message);
+ }
+}
+
+
+/* Convert a tuple argument.
+ On entry, *p_format points to the character _after_ the opening '('.
+ On successful exit, *p_format points to the closing ')'.
+ If successful:
+ *p_format and *p_va are updated,
+ *levels and *msgbuf are untouched,
+ and NULL is returned.
+ If the argument is invalid:
+ *p_format is unchanged,
+ *p_va is undefined,
+ *levels is a 0-terminated list of item numbers,
+ *msgbuf contains an error message, whose format is:
+ "must be <typename1>, not <typename2>", where:
+ <typename1> is the name of the expected type, and
+ <typename2> is the name of the actual type,
+ and msgbuf is returned.
+*/
+
+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)
+{
+ int level = 0;
+ int n = 0;
+ const char *format = *p_format;
+ int i;
+ Py_ssize_t len;
+
+ for (;;) {
+ int c = *format++;
+ if (c == '(') {
+ if (level == 0)
+ n++;
+ level++;
+ }
+ else if (c == ')') {
+ if (level == 0)
+ break;
+ level--;
+ }
+ else if (c == ':' || c == ';' || c == '\0')
+ break;
+ else if (level == 0 && Py_ISALPHA(c))
+ n++;
+ }
+
+ if (!PySequence_Check(arg) || PyBytes_Check(arg)) {
+ levels[0] = 0;
+ PyOS_snprintf(msgbuf, bufsize,
+ toplevel ? "expected %d arguments, not %.50s" :
+ "must be %d-item sequence, not %.50s",
+ n,
+ arg == Py_None ? "None" : Py_TYPE(arg)->tp_name);
+ return msgbuf;
+ }
+
+ len = PySequence_Size(arg);
+ if (len != n) {
+ levels[0] = 0;
+ if (toplevel) {
+ PyOS_snprintf(msgbuf, bufsize,
+ "expected %d argument%s, not %zd",
+ n,
+ n == 1 ? "" : "s",
+ len);
+ }
+ else {
+ PyOS_snprintf(msgbuf, bufsize,
+ "must be sequence of length %d, not %zd",
+ n, len);
+ }
+ return msgbuf;
+ }
+
+ format = *p_format;
+ for (i = 0; i < n; i++) {
+ const char *msg;
+ PyObject *item;
+ item = PySequence_GetItem(arg, i);
+ if (item == NULL) {
+ PyErr_Clear();
+ levels[0] = i+1;
+ levels[1] = 0;
+ strncpy(msgbuf, "is not retrievable", bufsize);
+ return msgbuf;
+ }
+ msg = convertitem(item, &format, p_va, flags, levels+1,
+ msgbuf, bufsize, freelist);
+ /* PySequence_GetItem calls tp->sq_item, which INCREFs */
+ Py_XDECREF(item);
+ if (msg != NULL) {
+ levels[0] = i+1;
+ return msg;
+ }
+ }
+
+ *p_format = format;
+ return NULL;
+}
+
+
+/* Convert a single item. */
+
+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)
+{
+ const char *msg;
+ const char *format = *p_format;
+
+ if (*format == '(' /* ')' */) {
+ format++;
+ msg = converttuple(arg, &format, p_va, flags, levels, msgbuf,
+ bufsize, 0, freelist);
+ if (msg == NULL)
+ format++;
+ }
+ else {
+ msg = convertsimple(arg, &format, p_va, flags,
+ msgbuf, bufsize, freelist);
+ if (msg != NULL)
+ levels[0] = 0;
+ }
+ if (msg == NULL)
+ *p_format = format;
+ return msg;
+}
+
+
+
+/* Format an error message generated by convertsimple().
+ displayname must be UTF-8 encoded.
+*/
+
+void
+_PyArg_BadArgument(const char *fname, const char *displayname,
+ const char *expected, PyObject *arg)
+{
+ PyErr_Format(PyExc_TypeError,
+ "%.200s() %.200s must be %.50s, not %.50s",
+ fname, displayname, expected,
+ arg == Py_None ? "None" : Py_TYPE(arg)->tp_name);
+}
+
+static const char *
+converterr(const char *expected, PyObject *arg, char *msgbuf, size_t bufsize)
+{
+ assert(expected != NULL);
+ assert(arg != NULL);
+ if (expected[0] == '(') {
+ PyOS_snprintf(msgbuf, bufsize,
+ "%.100s", expected);
+ }
+ else {
+ PyOS_snprintf(msgbuf, bufsize,
+ "must be %.50s, not %.50s", expected,
+ arg == Py_None ? "None" : Py_TYPE(arg)->tp_name);
+ }
+ return msgbuf;
+}
+
+#define CONV_UNICODE "(unicode conversion error)"
+
+/* Convert a non-tuple argument. Return NULL if conversion went OK,
+ or a string with a message describing the failure. The message is
+ formatted as "must be <desired type>, not <actual type>".
+ When failing, an exception may or may not have been raised.
+ Don't call if a tuple is expected.
+
+ When you add new format codes, please don't forget poor skipitem() below.
+*/
+
+static const char *
+convertsimple(PyObject *arg, const char **p_format, va_list *p_va, int flags,
+ char *msgbuf, size_t bufsize, freelist_t *freelist)
+{
+#define RETURN_ERR_OCCURRED return msgbuf
+ /* For # codes */
+#define REQUIRE_PY_SSIZE_T_CLEAN \
+ if (!(flags & FLAG_SIZE_T)) { \
+ PyErr_SetString(PyExc_SystemError, \
+ "PY_SSIZE_T_CLEAN macro must be defined for '#' formats"); \
+ RETURN_ERR_OCCURRED; \
+ }
+
+ const char *format = *p_format;
+ char c = *format++;
+ const char *sarg;
+
+ switch (c) {
+
+ case 'b': { /* unsigned byte -- very short int */
+ char *p = va_arg(*p_va, char *);
+ long ival = PyLong_AsLong(arg);
+ if (ival == -1 && PyErr_Occurred())
+ RETURN_ERR_OCCURRED;
+ else if (ival < 0) {
+ PyErr_SetString(PyExc_OverflowError,
+ "unsigned byte integer is less than minimum");
+ RETURN_ERR_OCCURRED;
+ }
+ else if (ival > UCHAR_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "unsigned byte integer is greater than maximum");
+ RETURN_ERR_OCCURRED;
+ }
+ else
+ *p = (unsigned char) ival;
+ break;
+ }
+
+ case 'B': {/* byte sized bitfield - both signed and unsigned
+ values allowed */
+ char *p = va_arg(*p_va, char *);
+ unsigned long ival = PyLong_AsUnsignedLongMask(arg);
+ if (ival == (unsigned long)-1 && PyErr_Occurred())
+ RETURN_ERR_OCCURRED;
+ else
+ *p = (unsigned char) ival;
+ break;
+ }
+
+ case 'h': {/* signed short int */
+ short *p = va_arg(*p_va, short *);
+ long ival = PyLong_AsLong(arg);
+ if (ival == -1 && PyErr_Occurred())
+ RETURN_ERR_OCCURRED;
+ else if (ival < SHRT_MIN) {
+ PyErr_SetString(PyExc_OverflowError,
+ "signed short integer is less than minimum");
+ RETURN_ERR_OCCURRED;
+ }
+ else if (ival > SHRT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "signed short integer is greater than maximum");
+ RETURN_ERR_OCCURRED;
+ }
+ else
+ *p = (short) ival;
+ break;
+ }
+
+ case 'H': { /* short int sized bitfield, both signed and
+ unsigned allowed */
+ unsigned short *p = va_arg(*p_va, unsigned short *);
+ unsigned long ival = PyLong_AsUnsignedLongMask(arg);
+ if (ival == (unsigned long)-1 && PyErr_Occurred())
+ RETURN_ERR_OCCURRED;
+ else
+ *p = (unsigned short) ival;
+ break;
+ }
+
+ case 'i': {/* signed int */
+ int *p = va_arg(*p_va, int *);
+ long ival = PyLong_AsLong(arg);
+ if (ival == -1 && PyErr_Occurred())
+ RETURN_ERR_OCCURRED;
+ else if (ival > INT_MAX) {
+ PyErr_SetString(PyExc_OverflowError,
+ "signed integer is greater than maximum");
+ RETURN_ERR_OCCURRED;
+ }
+ else if (ival < INT_MIN) {
+ PyErr_SetString(PyExc_OverflowError,
+ "signed integer is less than minimum");
+ RETURN_ERR_OCCURRED;
+ }
+ else
+ *p = ival;
+ break;
+ }
+
+ case 'I': { /* int sized bitfield, both signed and
+ unsigned allowed */
+ unsigned int *p = va_arg(*p_va, unsigned int *);
+ unsigned long ival = PyLong_AsUnsignedLongMask(arg);
+ if (ival == (unsigned long)-1 && PyErr_Occurred())
+ RETURN_ERR_OCCURRED;
+ else
+ *p = (unsigned int) ival;
+ break;
+ }
+
+ case 'n': /* Py_ssize_t */
+ {
+ PyObject *iobj;
+ Py_ssize_t *p = va_arg(*p_va, Py_ssize_t *);
+ Py_ssize_t ival = -1;
+ iobj = _PyNumber_Index(arg);
+ if (iobj != NULL) {
+ ival = PyLong_AsSsize_t(iobj);
+ Py_DECREF(iobj);
+ }
+ if (ival == -1 && PyErr_Occurred())
+ RETURN_ERR_OCCURRED;
+ *p = ival;
+ break;
+ }
+ case 'l': {/* long int */
+ long *p = va_arg(*p_va, long *);
+ long ival = PyLong_AsLong(arg);
+ if (ival == -1 && PyErr_Occurred())
+ RETURN_ERR_OCCURRED;
+ else
+ *p = ival;
+ break;
+ }
+
+ case 'k': { /* long sized bitfield */
+ unsigned long *p = va_arg(*p_va, unsigned long *);
+ unsigned long ival;
+ if (PyLong_Check(arg))
+ ival = PyLong_AsUnsignedLongMask(arg);
+ else
+ return converterr("int", arg, msgbuf, bufsize);
+ *p = ival;
+ break;
+ }
+
+ case 'L': {/* long long */
+ long long *p = va_arg( *p_va, long long * );
+ long long ival = PyLong_AsLongLong(arg);
+ if (ival == (long long)-1 && PyErr_Occurred())
+ RETURN_ERR_OCCURRED;
+ else
+ *p = ival;
+ break;
+ }
+
+ case 'K': { /* long long sized bitfield */
+ unsigned long long *p = va_arg(*p_va, unsigned long long *);
+ unsigned long long ival;
+ if (PyLong_Check(arg))
+ ival = PyLong_AsUnsignedLongLongMask(arg);
+ else
+ return converterr("int", arg, msgbuf, bufsize);
+ *p = ival;
+ break;
+ }
+
+ case 'f': {/* float */
+ float *p = va_arg(*p_va, float *);
+ double dval = PyFloat_AsDouble(arg);
+ if (dval == -1.0 && PyErr_Occurred())
+ RETURN_ERR_OCCURRED;
+ else
+ *p = (float) dval;
+ break;
+ }
+
+ case 'd': {/* double */
+ double *p = va_arg(*p_va, double *);
+ double dval = PyFloat_AsDouble(arg);
+ if (dval == -1.0 && PyErr_Occurred())
+ RETURN_ERR_OCCURRED;
+ else
+ *p = dval;
+ break;
+ }
+
+ case 'D': {/* complex double */
+ Py_complex *p = va_arg(*p_va, Py_complex *);
+ Py_complex cval;
+ cval = PyComplex_AsCComplex(arg);
+ if (PyErr_Occurred())
+ RETURN_ERR_OCCURRED;
+ else
+ *p = cval;
+ break;
+ }
+
+ case 'c': {/* char */
+ char *p = va_arg(*p_va, char *);
+ if (PyBytes_Check(arg) && PyBytes_Size(arg) == 1)
+ *p = PyBytes_AS_STRING(arg)[0];
+ else if (PyByteArray_Check(arg) && PyByteArray_Size(arg) == 1)
+ *p = PyByteArray_AS_STRING(arg)[0];
+ else
+ return converterr("a byte string of length 1", arg, msgbuf, bufsize);
+ break;
+ }
+
+ case 'C': {/* unicode char */
+ int *p = va_arg(*p_va, int *);
+ int kind;
+ const void *data;
+
+ if (!PyUnicode_Check(arg))
+ return converterr("a unicode character", arg, msgbuf, bufsize);
+
+ if (PyUnicode_READY(arg))
+ RETURN_ERR_OCCURRED;
+
+ if (PyUnicode_GET_LENGTH(arg) != 1)
+ return converterr("a unicode character", arg, msgbuf, bufsize);
+
+ kind = PyUnicode_KIND(arg);
+ data = PyUnicode_DATA(arg);
+ *p = PyUnicode_READ(kind, data, 0);
+ break;
+ }
+
+ case 'p': {/* boolean *p*redicate */
+ int *p = va_arg(*p_va, int *);
+ int val = PyObject_IsTrue(arg);
+ if (val > 0)
+ *p = 1;
+ else if (val == 0)
+ *p = 0;
+ else
+ RETURN_ERR_OCCURRED;
+ break;
+ }
+
+ /* XXX WAAAAH! 's', 'y', 'z', 'u', 'Z', 'e', 'w' codes all
+ need to be cleaned up! */
+
+ case 'y': {/* any bytes-like object */
+ void **p = (void **)va_arg(*p_va, char **);
+ const char *buf;
+ Py_ssize_t count;
+ if (*format == '*') {
+ if (getbuffer(arg, (Py_buffer*)p, &buf) < 0)
+ return converterr(buf, arg, msgbuf, bufsize);
+ format++;
+ if (addcleanup(p, freelist, cleanup_buffer)) {
+ return converterr(
+ "(cleanup problem)",
+ arg, msgbuf, bufsize);
+ }
+ break;
+ }
+ count = convertbuffer(arg, (const void **)p, &buf);
+ if (count < 0)
+ return converterr(buf, arg, msgbuf, bufsize);
+ if (*format == '#') {
+ REQUIRE_PY_SSIZE_T_CLEAN;
+ Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*);
+ *psize = count;
+ format++;
+ } else {
+ if (strlen(*p) != (size_t)count) {
+ PyErr_SetString(PyExc_ValueError, "embedded null byte");
+ RETURN_ERR_OCCURRED;
+ }
+ }
+ break;
+ }
+
+ case 's': /* text string or bytes-like object */
+ case 'z': /* text string, bytes-like object or None */
+ {
+ if (*format == '*') {
+ /* "s*" or "z*" */
+ Py_buffer *p = (Py_buffer *)va_arg(*p_va, Py_buffer *);
+
+ if (c == 'z' && arg == Py_None)
+ PyBuffer_FillInfo(p, NULL, NULL, 0, 1, 0);
+ else if (PyUnicode_Check(arg)) {
+ Py_ssize_t len;
+ sarg = PyUnicode_AsUTF8AndSize(arg, &len);
+ if (sarg == NULL)
+ return converterr(CONV_UNICODE,
+ arg, msgbuf, bufsize);
+ PyBuffer_FillInfo(p, arg, (void *)sarg, len, 1, 0);
+ }
+ else { /* any bytes-like object */
+ const char *buf;
+ if (getbuffer(arg, p, &buf) < 0)
+ return converterr(buf, arg, msgbuf, bufsize);
+ }
+ if (addcleanup(p, freelist, cleanup_buffer)) {
+ return converterr(
+ "(cleanup problem)",
+ arg, msgbuf, bufsize);
+ }
+ format++;
+ } else if (*format == '#') { /* a string or read-only bytes-like object */
+ /* "s#" or "z#" */
+ const void **p = (const void **)va_arg(*p_va, const char **);
+ REQUIRE_PY_SSIZE_T_CLEAN;
+ Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*);
+
+ if (c == 'z' && arg == Py_None) {
+ *p = NULL;
+ *psize = 0;
+ }
+ else if (PyUnicode_Check(arg)) {
+ Py_ssize_t len;
+ sarg = PyUnicode_AsUTF8AndSize(arg, &len);
+ if (sarg == NULL)
+ return converterr(CONV_UNICODE,
+ arg, msgbuf, bufsize);
+ *p = sarg;
+ *psize = len;
+ }
+ else { /* read-only bytes-like object */
+ /* XXX Really? */
+ const char *buf;
+ Py_ssize_t count = convertbuffer(arg, p, &buf);
+ if (count < 0)
+ return converterr(buf, arg, msgbuf, bufsize);
+ *psize = count;
+ }
+ format++;
+ } else {
+ /* "s" or "z" */
+ const char **p = va_arg(*p_va, const char **);
+ Py_ssize_t len;
+ sarg = NULL;
+
+ if (c == 'z' && arg == Py_None)
+ *p = NULL;
+ else if (PyUnicode_Check(arg)) {
+ sarg = PyUnicode_AsUTF8AndSize(arg, &len);
+ if (sarg == NULL)
+ return converterr(CONV_UNICODE,
+ arg, msgbuf, bufsize);
+ if (strlen(sarg) != (size_t)len) {
+ PyErr_SetString(PyExc_ValueError, "embedded null character");
+ RETURN_ERR_OCCURRED;
+ }
+ *p = sarg;
+ }
+ else
+ return converterr(c == 'z' ? "str or None" : "str",
+ arg, msgbuf, bufsize);
+ }
+ break;
+ }
+
+ case 'u': /* raw unicode buffer (Py_UNICODE *) */
+ case 'Z': /* raw unicode buffer or None */
+ {
+ if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
+ "getargs: The '%c' format is deprecated. Use 'U' instead.", c)) {
+ RETURN_ERR_OCCURRED;
+ }
+_Py_COMP_DIAG_PUSH
+_Py_COMP_DIAG_IGNORE_DEPR_DECLS
+ Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **);
+
+ if (*format == '#') {
+ /* "u#" or "Z#" */
+ REQUIRE_PY_SSIZE_T_CLEAN;
+ Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*);
+
+ if (c == 'Z' && arg == Py_None) {
+ *p = NULL;
+ *psize = 0;
+ }
+ else if (PyUnicode_Check(arg)) {
+ Py_ssize_t len;
+ *p = PyUnicode_AsUnicodeAndSize(arg, &len);
+ if (*p == NULL)
+ RETURN_ERR_OCCURRED;
+ *psize = len;
+ }
+ else
+ return converterr(c == 'Z' ? "str or None" : "str",
+ arg, msgbuf, bufsize);
+ format++;
+ } else {
+ /* "u" or "Z" */
+ if (c == 'Z' && arg == Py_None)
+ *p = NULL;
+ else if (PyUnicode_Check(arg)) {
+ Py_ssize_t len;
+ *p = PyUnicode_AsUnicodeAndSize(arg, &len);
+ if (*p == NULL)
+ RETURN_ERR_OCCURRED;
+ if (wcslen(*p) != (size_t)len) {
+ PyErr_SetString(PyExc_ValueError, "embedded null character");
+ RETURN_ERR_OCCURRED;
+ }
+ } else
+ return converterr(c == 'Z' ? "str or None" : "str",
+ arg, msgbuf, bufsize);
+ }
+ break;
+_Py_COMP_DIAG_POP
+ }
+
+ case 'e': {/* encoded string */
+ char **buffer;
+ const char *encoding;
+ PyObject *s;
+ int recode_strings;
+ Py_ssize_t size;
+ const char *ptr;
+
+ /* Get 'e' parameter: the encoding name */
+ encoding = (const char *)va_arg(*p_va, const char *);
+ if (encoding == NULL)
+ encoding = PyUnicode_GetDefaultEncoding();
+
+ /* Get output buffer parameter:
+ 's' (recode all objects via Unicode) or
+ 't' (only recode non-string objects)
+ */
+ if (*format == 's')
+ recode_strings = 1;
+ else if (*format == 't')
+ recode_strings = 0;
+ else
+ return converterr(
+ "(unknown parser marker combination)",
+ arg, msgbuf, bufsize);
+ buffer = (char **)va_arg(*p_va, char **);
+ format++;
+ if (buffer == NULL)
+ return converterr("(buffer is NULL)",
+ arg, msgbuf, bufsize);
+
+ /* Encode object */
+ if (!recode_strings &&
+ (PyBytes_Check(arg) || PyByteArray_Check(arg))) {
+ s = arg;
+ Py_INCREF(s);
+ 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 */
+ s = PyUnicode_AsEncodedString(arg,
+ encoding,
+ NULL);
+ if (s == NULL)
+ return converterr("(encoding failed)",
+ 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 == '#') {
+ /* Using buffer length parameter '#':
+
+ - if *buffer is NULL, a new buffer of the
+ needed size is allocated and the data
+ copied into it; *buffer is updated to point
+ to the new buffer; the caller is
+ responsible for PyMem_Free()ing it after
+ usage
+
+ - if *buffer is not NULL, the data is
+ copied to *buffer; *buffer_len has to be
+ set to the size of the buffer on input;
+ buffer overflow is signalled with an error;
+ buffer has to provide enough room for the
+ encoded string plus the trailing 0-byte
+
+ - in both cases, *buffer_len is updated to
+ the size of the buffer /excluding/ the
+ trailing 0-byte
+
+ */
+ REQUIRE_PY_SSIZE_T_CLEAN;
+ Py_ssize_t *psize = va_arg(*p_va, Py_ssize_t*);
+
+ format++;
+ if (psize == NULL) {
+ Py_DECREF(s);
+ return converterr(
+ "(buffer_len is NULL)",
+ arg, msgbuf, bufsize);
+ }
+ if (*buffer == NULL) {
+ *buffer = PyMem_NEW(char, size + 1);
+ if (*buffer == NULL) {
+ Py_DECREF(s);
+ PyErr_NoMemory();
+ RETURN_ERR_OCCURRED;
+ }
+ if (addcleanup(buffer, freelist, cleanup_ptr)) {
+ Py_DECREF(s);
+ return converterr(
+ "(cleanup problem)",
+ arg, msgbuf, bufsize);
+ }
+ } else {
+ if (size + 1 > *psize) {
+ Py_DECREF(s);
+ PyErr_Format(PyExc_ValueError,
+ "encoded string too long "
+ "(%zd, maximum length %zd)",
+ (Py_ssize_t)size, (Py_ssize_t)(*psize - 1));
+ RETURN_ERR_OCCURRED;
+ }
+ }
+ memcpy(*buffer, ptr, size+1);
+
+ *psize = size;
+ }
+ else {
+ /* Using a 0-terminated buffer:
+
+ - the encoded string has to be 0-terminated
+ for this variant to work; if it is not, an
+ error raised
+
+ - a new buffer of the needed size is
+ allocated and the data copied into it;
+ *buffer is updated to point to the new
+ buffer; the caller is responsible for
+ PyMem_Free()ing it after usage
+
+ */
+ if ((Py_ssize_t)strlen(ptr) != size) {
+ Py_DECREF(s);
+ return converterr(
+ "encoded string without null bytes",
+ arg, msgbuf, bufsize);
+ }
+ *buffer = PyMem_NEW(char, size + 1);
+ if (*buffer == NULL) {
+ Py_DECREF(s);
+ PyErr_NoMemory();
+ RETURN_ERR_OCCURRED;
+ }
+ if (addcleanup(buffer, freelist, cleanup_ptr)) {
+ Py_DECREF(s);
+ return converterr("(cleanup problem)",
+ arg, msgbuf, bufsize);
+ }
+ memcpy(*buffer, ptr, size+1);
+ }
+ Py_DECREF(s);
+ break;
+ }
+
+ case 'S': { /* PyBytes object */
+ PyObject **p = va_arg(*p_va, PyObject **);
+ if (PyBytes_Check(arg))
+ *p = arg;
+ else
+ return converterr("bytes", arg, msgbuf, bufsize);
+ break;
+ }
+
+ case 'Y': { /* PyByteArray object */
+ PyObject **p = va_arg(*p_va, PyObject **);
+ if (PyByteArray_Check(arg))
+ *p = arg;
+ else
+ return converterr("bytearray", arg, msgbuf, bufsize);
+ break;
+ }
+
+ case 'U': { /* PyUnicode object */
+ PyObject **p = va_arg(*p_va, PyObject **);
+ if (PyUnicode_Check(arg)) {
+ if (PyUnicode_READY(arg) == -1)
+ RETURN_ERR_OCCURRED;
+ *p = arg;
+ }
+ else
+ return converterr("str", arg, msgbuf, bufsize);
+ break;
+ }
+
+ case 'O': { /* object */
+ PyTypeObject *type;
+ PyObject **p;
+ if (*format == '!') {
+ type = va_arg(*p_va, PyTypeObject*);
+ p = va_arg(*p_va, PyObject **);
+ format++;
+ if (PyType_IsSubtype(Py_TYPE(arg), type))
+ *p = arg;
+ else
+ return converterr(type->tp_name, arg, msgbuf, bufsize);
+
+ }
+ else if (*format == '&') {
+ typedef int (*converter)(PyObject *, void *);
+ converter convert = va_arg(*p_va, converter);
+ void *addr = va_arg(*p_va, void *);
+ int res;
+ format++;
+ if (! (res = (*convert)(arg, addr)))
+ return converterr("(unspecified)",
+ arg, msgbuf, bufsize);
+ if (res == Py_CLEANUP_SUPPORTED &&
+ addcleanup(addr, freelist, convert) == -1)
+ return converterr("(cleanup problem)",
+ arg, msgbuf, bufsize);
+ }
+ else {
+ p = va_arg(*p_va, PyObject **);
+ *p = arg;
+ }
+ break;
+ }
+
+
+ case 'w': { /* "w*": memory buffer, read-write access */
+ void **p = va_arg(*p_va, void **);
+
+ if (*format != '*')
+ return converterr(
+ "(invalid use of 'w' format character)",
+ arg, msgbuf, bufsize);
+ format++;
+
+ /* Caller is interested in Py_buffer, and the object
+ supports it directly. */
+ if (PyObject_GetBuffer(arg, (Py_buffer*)p, PyBUF_WRITABLE) < 0) {
+ PyErr_Clear();
+ return converterr("read-write bytes-like object",
+ arg, msgbuf, bufsize);
+ }
+ if (!PyBuffer_IsContiguous((Py_buffer*)p, 'C')) {
+ PyBuffer_Release((Py_buffer*)p);
+ return converterr("contiguous buffer", arg, msgbuf, bufsize);
+ }
+ if (addcleanup(p, freelist, cleanup_buffer)) {
+ return converterr(
+ "(cleanup problem)",
+ arg, msgbuf, bufsize);
+ }
+ break;
+ }
+
+ default:
+ return converterr("(impossible<bad format char>)", arg, msgbuf, bufsize);
+
+ }
+
+ *p_format = format;
+ return NULL;
+
+#undef REQUIRE_PY_SSIZE_T_CLEAN
+#undef RETURN_ERR_OCCURRED
+}
+
+static Py_ssize_t
+convertbuffer(PyObject *arg, const void **p, const char **errmsg)
+{
+ PyBufferProcs *pb = Py_TYPE(arg)->tp_as_buffer;
+ Py_ssize_t count;
+ Py_buffer view;
+
+ *errmsg = NULL;
+ *p = NULL;
+ if (pb != NULL && pb->bf_releasebuffer != NULL) {
+ *errmsg = "read-only bytes-like object";
+ return -1;
+ }
+
+ if (getbuffer(arg, &view, errmsg) < 0)
+ return -1;
+ count = view.len;
+ *p = view.buf;
+ PyBuffer_Release(&view);
+ return count;
+}
+
+static int
+getbuffer(PyObject *arg, Py_buffer *view, const char **errmsg)
+{
+ if (PyObject_GetBuffer(arg, view, PyBUF_SIMPLE) != 0) {
+ *errmsg = "bytes-like object";
+ return -1;
+ }
+ if (!PyBuffer_IsContiguous(view, 'C')) {
+ PyBuffer_Release(view);
+ *errmsg = "contiguous buffer";
+ return -1;
+ }
+ return 0;
+}
+
+/* Support for keyword arguments donated by
+ Geoff Philbrick <philbric@delphi.hks.com> */
+
+/* Return false (0) for error, else true. */
+int
+PyArg_ParseTupleAndKeywords(PyObject *args,
+ PyObject *keywords,
+ const char *format,
+ char **kwlist, ...)
+{
+ int retval;
+ va_list va;
+
+ if ((args == NULL || !PyTuple_Check(args)) ||
+ (keywords != NULL && !PyDict_Check(keywords)) ||
+ format == NULL ||
+ kwlist == NULL)
+ {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+
+ va_start(va, kwlist);
+ retval = vgetargskeywords(args, keywords, format, kwlist, &va, 0);
+ va_end(va);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_ParseTupleAndKeywords_SizeT(PyObject *args,
+ PyObject *keywords,
+ const char *format,
+ char **kwlist, ...)
+{
+ int retval;
+ va_list va;
+
+ if ((args == NULL || !PyTuple_Check(args)) ||
+ (keywords != NULL && !PyDict_Check(keywords)) ||
+ format == NULL ||
+ kwlist == NULL)
+ {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+
+ va_start(va, kwlist);
+ retval = vgetargskeywords(args, keywords, format,
+ kwlist, &va, FLAG_SIZE_T);
+ va_end(va);
+ return retval;
+}
+
+
+int
+PyArg_VaParseTupleAndKeywords(PyObject *args,
+ PyObject *keywords,
+ const char *format,
+ char **kwlist, va_list va)
+{
+ int retval;
+ va_list lva;
+
+ if ((args == NULL || !PyTuple_Check(args)) ||
+ (keywords != NULL && !PyDict_Check(keywords)) ||
+ format == NULL ||
+ kwlist == NULL)
+ {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+
+ va_copy(lva, va);
+
+ retval = vgetargskeywords(args, keywords, format, kwlist, &lva, 0);
+ va_end(lva);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_VaParseTupleAndKeywords_SizeT(PyObject *args,
+ PyObject *keywords,
+ const char *format,
+ char **kwlist, va_list va)
+{
+ int retval;
+ va_list lva;
+
+ if ((args == NULL || !PyTuple_Check(args)) ||
+ (keywords != NULL && !PyDict_Check(keywords)) ||
+ format == NULL ||
+ kwlist == NULL)
+ {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+
+ va_copy(lva, va);
+
+ retval = vgetargskeywords(args, keywords, format,
+ kwlist, &lva, FLAG_SIZE_T);
+ va_end(lva);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_ParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, parser);
+ retval = vgetargskeywordsfast(args, keywords, parser, &va, 0);
+ va_end(va);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_ParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, parser);
+ retval = vgetargskeywordsfast(args, keywords, parser, &va, FLAG_SIZE_T);
+ va_end(va);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_ParseStackAndKeywords(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames,
+ struct _PyArg_Parser *parser, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, parser);
+ retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va, 0);
+ va_end(va);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_ParseStackAndKeywords_SizeT(PyObject *const *args, Py_ssize_t nargs, PyObject *kwnames,
+ struct _PyArg_Parser *parser, ...)
+{
+ int retval;
+ va_list va;
+
+ va_start(va, parser);
+ retval = vgetargskeywordsfast_impl(args, nargs, NULL, kwnames, parser, &va, FLAG_SIZE_T);
+ va_end(va);
+ return retval;
+}
+
+
+PyAPI_FUNC(int)
+_PyArg_VaParseTupleAndKeywordsFast(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, va_list va)
+{
+ int retval;
+ va_list lva;
+
+ va_copy(lva, va);
+
+ retval = vgetargskeywordsfast(args, keywords, parser, &lva, 0);
+ va_end(lva);
+ return retval;
+}
+
+PyAPI_FUNC(int)
+_PyArg_VaParseTupleAndKeywordsFast_SizeT(PyObject *args, PyObject *keywords,
+ struct _PyArg_Parser *parser, va_list va)
+{
+ int retval;
+ va_list lva;
+
+ va_copy(lva, va);
+
+ retval = vgetargskeywordsfast(args, keywords, parser, &lva, FLAG_SIZE_T);
+ va_end(lva);
+ return retval;
+}
+
+static void
+error_unexpected_keyword_arg(PyObject *kwargs, PyObject *kwnames, PyObject *kwtuple, const char *fname)
+{
+ /* make sure there are no extraneous keyword arguments */
+ Py_ssize_t j = 0;
+ while (1) {
+ PyObject *keyword;
+ 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++;
+ }
+ if (!PyUnicode_Check(keyword)) {
+ PyErr_SetString(PyExc_TypeError,
+ "keywords must be strings");
+ return;
+ }
+
+ int match = PySequence_Contains(kwtuple, keyword);
+ if (match <= 0) {
+ if (!match) {
+ PyErr_Format(PyExc_TypeError,
+ "'%S' is an invalid keyword "
+ "argument for %.200s%s",
+ keyword,
+ (fname == NULL) ? "this function" : fname,
+ (fname == NULL) ? "" : "()");
+ }
+ return;
+ }
+ }
+ /* Something wrong happened. There are extraneous keyword arguments,
+ * but we don't know what. And we don't bother. */
+ PyErr_Format(PyExc_TypeError,
+ "invalid keyword argument for %.200s%s",
+ (fname == NULL) ? "this function" : fname,
+ (fname == NULL) ? "" : "()");
+}
+
+int
+PyArg_ValidateKeywordArguments(PyObject *kwargs)
+{
+ if (!PyDict_Check(kwargs)) {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+ if (!_PyDict_HasOnlyStringKeys(kwargs)) {
+ PyErr_SetString(PyExc_TypeError,
+ "keywords must be strings");
+ return 0;
+ }
+ return 1;
+}
+
+#define IS_END_OF_FORMAT(c) (c == '\0' || c == ';' || c == ':')
+
+static int
+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;
+ int min = INT_MAX;
+ int max = INT_MAX;
+ int i, pos, len;
+ int skip = 0;
+ Py_ssize_t nargs, nkwargs;
+ PyObject *current_arg;
+ freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
+ freelist_t freelist;
+
+ freelist.entries = static_entries;
+ freelist.first_available = 0;
+ freelist.entries_malloced = 0;
+
+ assert(args != NULL && PyTuple_Check(args));
+ assert(kwargs == NULL || PyDict_Check(kwargs));
+ assert(format != NULL);
+ assert(kwlist != NULL);
+ assert(p_va != NULL);
+
+ /* grab the function name or custom error msg first (mutually exclusive) */
+ fname = strchr(format, ':');
+ if (fname) {
+ fname++;
+ custom_msg = NULL;
+ }
+ else {
+ custom_msg = strchr(format,';');
+ if (custom_msg)
+ 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 = 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);
+ if (freelist.entries == NULL) {
+ PyErr_NoMemory();
+ return 0;
+ }
+ freelist.entries_malloced = 1;
+ }
+
+ nargs = PyTuple_GET_SIZE(args);
+ nkwargs = (kwargs == NULL) ? 0 : PyDict_GET_SIZE(kwargs);
+ if (nargs + nkwargs > len) {
+ /* Adding "keyword" (when nargs == 0) prevents producing wrong error
+ messages in some special cases (see bpo-31229). */
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes at most %d %sargument%s (%zd given)",
+ (fname == NULL) ? "function" : fname,
+ (fname == NULL) ? "" : "()",
+ len,
+ (nargs == 0) ? "keyword " : "",
+ (len == 1) ? "" : "s",
+ 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++) {
+ if (*format == '|') {
+ if (min != INT_MAX) {
+ PyErr_SetString(PyExc_SystemError,
+ "Invalid format string (| specified twice)");
+ return cleanreturn(0, &freelist);
+ }
+
+ min = i;
+ format++;
+
+ if (max != INT_MAX) {
+ PyErr_SetString(PyExc_SystemError,
+ "Invalid format string ($ before |)");
+ return cleanreturn(0, &freelist);
+ }
+ }
+ if (*format == '$') {
+ if (max != INT_MAX) {
+ PyErr_SetString(PyExc_SystemError,
+ "Invalid format string ($ specified twice)");
+ return cleanreturn(0, &freelist);
+ }
+
+ 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) {
+ if (max == 0) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes no positional arguments",
+ (fname == NULL) ? "function" : fname,
+ (fname == NULL) ? "" : "()");
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes %s %d positional argument%s"
+ " (%zd given)",
+ (fname == NULL) ? "function" : fname,
+ (fname == NULL) ? "" : "()",
+ (min != INT_MAX) ? "at most" : "exactly",
+ max,
+ max == 1 ? "" : "s",
+ nargs);
+ }
+ return cleanreturn(0, &freelist);
+ }
+ }
+ if (IS_END_OF_FORMAT(*format)) {
+ PyErr_Format(PyExc_SystemError,
+ "More keyword list entries (%d) than "
+ "format specifiers (%d)", len, i);
+ return cleanreturn(0, &freelist);
+ }
+ if (!skip) {
+ if (i < nargs) {
+ current_arg = PyTuple_GET_ITEM(args, i);
+ }
+ else if (nkwargs && i >= pos) {
+ current_arg = _PyDict_GetItemStringWithError(kwargs, kwlist[i]);
+ if (current_arg) {
+ --nkwargs;
+ }
+ else if (PyErr_Occurred()) {
+ return cleanreturn(0, &freelist);
+ }
+ }
+ else {
+ current_arg = NULL;
+ }
+
+ 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;
+ }
+
+ 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, "%.200s%s missing required "
+ "argument '%s' (pos %d)",
+ (fname == NULL) ? "function" : fname,
+ (fname == NULL) ? "" : "()",
+ kwlist[i], 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 (!nkwargs && !skip) {
+ return cleanreturn(1, &freelist);
+ }
+ }
+
+ /* We are into optional args, skip through to any remaining
+ * keyword args */
+ msg = skipitem(&format, p_va, flags);
+ if (msg) {
+ PyErr_Format(PyExc_SystemError, "%s: '%s'", msg,
+ format);
+ return cleanreturn(0, &freelist);
+ }
+ }
+
+ if (skip) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes %s %d positional argument%s"
+ " (%zd given)",
+ (fname == NULL) ? "function" : fname,
+ (fname == NULL) ? "" : "()",
+ (Py_MIN(pos, min) < i) ? "at least" : "exactly",
+ Py_MIN(pos, min),
+ Py_MIN(pos, min) == 1 ? "" : "s",
+ nargs);
+ return cleanreturn(0, &freelist);
+ }
+
+ if (!IS_END_OF_FORMAT(*format) && (*format != '|') && (*format != '$')) {
+ PyErr_Format(PyExc_SystemError,
+ "more argument specifiers than keyword list entries "
+ "(remaining format:'%s')", format);
+ return cleanreturn(0, &freelist);
+ }
+
+ 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_GetItemStringWithError(kwargs, kwlist[i]);
+ if (current_arg) {
+ /* arg present in tuple and in dict */
+ PyErr_Format(PyExc_TypeError,
+ "argument for %.200s%s given by name ('%s') "
+ "and position (%d)",
+ (fname == NULL) ? "function" : fname,
+ (fname == NULL) ? "" : "()",
+ kwlist[i], i+1);
+ return cleanreturn(0, &freelist);
+ }
+ else if (PyErr_Occurred()) {
+ 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 = pos; i < len; i++) {
+ if (_PyUnicode_EqualToASCIIString(key, kwlist[i])) {
+ match = 1;
+ break;
+ }
+ }
+ if (!match) {
+ PyErr_Format(PyExc_TypeError,
+ "'%U' is an invalid keyword "
+ "argument for %.200s%s",
+ key,
+ (fname == NULL) ? "this function" : fname,
+ (fname == NULL) ? "" : "()");
+ return cleanreturn(0, &freelist);
+ }
+ }
+ /* Something wrong happened. There are extraneous keyword arguments,
+ * but we don't know what. And we don't bother. */
+ PyErr_Format(PyExc_TypeError,
+ "invalid keyword argument for %.200s%s",
+ (fname == NULL) ? "this function" : fname,
+ (fname == NULL) ? "" : "()");
+ return cleanreturn(0, &freelist);
+ }
+
+ return cleanreturn(1, &freelist);
+}
+
+
+/* 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->keywords != NULL);
+ if (parser->kwtuple != NULL) {
+ return 1;
+ }
+
+ 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;
+
+ format = parser->format;
+ if (format) {
+ /* 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++;
+ }
+
+ min = max = INT_MAX;
+ 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 *const *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);
+
+ /* kwname == key will normally find a match in since keyword keys
+ should be interned strings; if not retry below in a new loop. */
+ if (kwname == key) {
+ return kwstack[i];
+ }
+ }
+
+ for (i = 0; i < nkwargs; i++) {
+ PyObject *kwname = PyTuple_GET_ITEM(kwnames, i);
+ assert(PyUnicode_Check(kwname));
+ if (_PyUnicode_EQ(kwname, key)) {
+ return kwstack[i];
+ }
+ }
+ return NULL;
+}
+
+static int
+vgetargskeywordsfast_impl(PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwargs, 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 nkwargs;
+ PyObject *current_arg;
+ freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
+ freelist_t freelist;
+ PyObject *const *kwstack = NULL;
+
+ freelist.entries = static_entries;
+ freelist.first_available = 0;
+ freelist.entries_malloced = 0;
+
+ 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;
+ }
+
+ kwtuple = parser->kwtuple;
+ pos = parser->pos;
+ len = pos + (int)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 (kwargs != NULL) {
+ nkwargs = PyDict_GET_SIZE(kwargs);
+ }
+ else if (kwnames != NULL) {
+ nkwargs = PyTuple_GET_SIZE(kwnames);
+ kwstack = args + nargs;
+ }
+ else {
+ nkwargs = 0;
+ }
+ if (nargs + nkwargs > len) {
+ /* Adding "keyword" (when nargs == 0) prevents producing wrong error
+ messages in some special cases (see bpo-31229). */
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes at most %d %sargument%s (%zd given)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ len,
+ (nargs == 0) ? "keyword " : "",
+ (len == 1) ? "" : "s",
+ nargs + nkwargs);
+ return cleanreturn(0, &freelist);
+ }
+ if (parser->max < nargs) {
+ if (parser->max == 0) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes no positional arguments",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()");
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes %s %d positional argument%s (%zd given)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ (parser->min < parser->max) ? "at most" : "exactly",
+ parser->max,
+ parser->max == 1 ? "" : "s",
+ 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++) {
+ if (*format == '|') {
+ format++;
+ }
+ if (*format == '$') {
+ format++;
+ }
+ assert(!IS_END_OF_FORMAT(*format));
+
+ if (i < nargs) {
+ current_arg = args[i];
+ }
+ else if (nkwargs && i >= pos) {
+ keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
+ if (kwargs != NULL) {
+ current_arg = PyDict_GetItemWithError(kwargs, keyword);
+ if (!current_arg && PyErr_Occurred()) {
+ return cleanreturn(0, &freelist);
+ }
+ }
+ else {
+ current_arg = find_keyword(kwnames, kwstack, keyword);
+ }
+ if (current_arg) {
+ --nkwargs;
+ }
+ }
+ else {
+ current_arg = NULL;
+ }
+
+ 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) {
+ Py_ssize_t min = Py_MIN(pos, parser->min);
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes %s %d positional argument%s"
+ " (%zd given)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ min < parser->max ? "at least" : "exactly",
+ min,
+ min == 1 ? "" : "s",
+ nargs);
+ }
+ else {
+ keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
+ PyErr_Format(PyExc_TypeError, "%.200s%s missing required "
+ "argument '%U' (pos %d)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ 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 (!nkwargs) {
+ return cleanreturn(1, &freelist);
+ }
+
+ /* We are into optional args, skip through to any remaining
+ * keyword args */
+ msg = skipitem(&format, p_va, flags);
+ assert(msg == NULL);
+ }
+
+ assert(IS_END_OF_FORMAT(*format) || (*format == '|') || (*format == '$'));
+
+ if (nkwargs > 0) {
+ /* make sure there are no arguments given by name and position */
+ for (i = pos; i < nargs; i++) {
+ keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
+ if (kwargs != NULL) {
+ current_arg = PyDict_GetItemWithError(kwargs, keyword);
+ if (!current_arg && PyErr_Occurred()) {
+ return cleanreturn(0, &freelist);
+ }
+ }
+ else {
+ current_arg = find_keyword(kwnames, kwstack, keyword);
+ }
+ if (current_arg) {
+ /* arg present in tuple and in dict */
+ PyErr_Format(PyExc_TypeError,
+ "argument for %.200s%s given by name ('%U') "
+ "and position (%d)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ keyword, i+1);
+ return cleanreturn(0, &freelist);
+ }
+ }
+
+ error_unexpected_keyword_arg(kwargs, kwnames, kwtuple, parser->fname);
+ 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;
+
+ if (args == NULL
+ || !PyTuple_Check(args)
+ || (keywords != NULL && !PyDict_Check(keywords)))
+ {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+
+ stack = _PyTuple_ITEMS(args);
+ nargs = PyTuple_GET_SIZE(args);
+ return vgetargskeywordsfast_impl(stack, nargs, keywords, NULL,
+ parser, p_va, flags);
+}
+
+
+#undef _PyArg_UnpackKeywords
+
+PyObject * const *
+_PyArg_UnpackKeywords(PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwargs, PyObject *kwnames,
+ struct _PyArg_Parser *parser,
+ int minpos, int maxpos, int minkw,
+ PyObject **buf)
+{
+ PyObject *kwtuple;
+ PyObject *keyword;
+ int i, posonly, minposonly, maxargs;
+ int reqlimit = minkw ? maxpos + minkw : minpos;
+ Py_ssize_t nkwargs;
+ PyObject *current_arg;
+ PyObject * const *kwstack = NULL;
+
+ assert(kwargs == NULL || PyDict_Check(kwargs));
+ assert(kwargs == NULL || kwnames == NULL);
+
+ if (parser == NULL) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ if (kwnames != NULL && !PyTuple_Check(kwnames)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ if (args == NULL && nargs == 0) {
+ args = buf;
+ }
+
+ if (!parser_init(parser)) {
+ return NULL;
+ }
+
+ kwtuple = parser->kwtuple;
+ posonly = parser->pos;
+ minposonly = Py_MIN(posonly, minpos);
+ maxargs = posonly + (int)PyTuple_GET_SIZE(kwtuple);
+
+ if (kwargs != NULL) {
+ nkwargs = PyDict_GET_SIZE(kwargs);
+ }
+ else if (kwnames != NULL) {
+ nkwargs = PyTuple_GET_SIZE(kwnames);
+ kwstack = args + nargs;
+ }
+ else {
+ nkwargs = 0;
+ }
+ if (nkwargs == 0 && minkw == 0 && minpos <= nargs && nargs <= maxpos) {
+ /* Fast path. */
+ return args;
+ }
+ if (nargs + nkwargs > maxargs) {
+ /* Adding "keyword" (when nargs == 0) prevents producing wrong error
+ messages in some special cases (see bpo-31229). */
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes at most %d %sargument%s (%zd given)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ maxargs,
+ (nargs == 0) ? "keyword " : "",
+ (maxargs == 1) ? "" : "s",
+ nargs + nkwargs);
+ return NULL;
+ }
+ if (nargs > maxpos) {
+ if (maxpos == 0) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes no positional arguments",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()");
+ }
+ else {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes %s %d positional argument%s (%zd given)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ (minpos < maxpos) ? "at most" : "exactly",
+ maxpos,
+ (maxpos == 1) ? "" : "s",
+ nargs);
+ }
+ return NULL;
+ }
+ if (nargs < minposonly) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes %s %d positional argument%s"
+ " (%zd given)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ minposonly < maxpos ? "at least" : "exactly",
+ minposonly,
+ minposonly == 1 ? "" : "s",
+ nargs);
+ return NULL;
+ }
+
+ /* copy tuple args */
+ for (i = 0; i < nargs; i++) {
+ buf[i] = args[i];
+ }
+
+ /* copy keyword args using kwtuple to drive process */
+ for (i = Py_MAX((int)nargs, posonly); i < maxargs; i++) {
+ if (nkwargs) {
+ keyword = PyTuple_GET_ITEM(kwtuple, i - posonly);
+ if (kwargs != NULL) {
+ current_arg = PyDict_GetItemWithError(kwargs, keyword);
+ if (!current_arg && PyErr_Occurred()) {
+ return NULL;
+ }
+ }
+ else {
+ current_arg = find_keyword(kwnames, kwstack, keyword);
+ }
+ }
+ else if (i >= reqlimit) {
+ break;
+ }
+ else {
+ current_arg = NULL;
+ }
+
+ buf[i] = current_arg;
+
+ if (current_arg) {
+ --nkwargs;
+ }
+ else if (i < minpos || (maxpos <= i && i < reqlimit)) {
+ /* Less arguments than required */
+ keyword = PyTuple_GET_ITEM(kwtuple, i - posonly);
+ PyErr_Format(PyExc_TypeError, "%.200s%s missing required "
+ "argument '%U' (pos %d)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ keyword, i+1);
+ return NULL;
+ }
+ }
+
+ if (nkwargs > 0) {
+ /* make sure there are no arguments given by name and position */
+ for (i = posonly; i < nargs; i++) {
+ keyword = PyTuple_GET_ITEM(kwtuple, i - posonly);
+ if (kwargs != NULL) {
+ current_arg = PyDict_GetItemWithError(kwargs, keyword);
+ if (!current_arg && PyErr_Occurred()) {
+ return NULL;
+ }
+ }
+ else {
+ current_arg = find_keyword(kwnames, kwstack, keyword);
+ }
+ if (current_arg) {
+ /* arg present in tuple and in dict */
+ PyErr_Format(PyExc_TypeError,
+ "argument for %.200s%s given by name ('%U') "
+ "and position (%d)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ keyword, i+1);
+ return NULL;
+ }
+ }
+
+ error_unexpected_keyword_arg(kwargs, kwnames, kwtuple, parser->fname);
+ return NULL;
+ }
+
+ return buf;
+}
+
+PyObject * const *
+_PyArg_UnpackKeywordsWithVararg(PyObject *const *args, Py_ssize_t nargs,
+ PyObject *kwargs, PyObject *kwnames,
+ struct _PyArg_Parser *parser,
+ int minpos, int maxpos, int minkw,
+ int vararg, PyObject **buf)
+{
+ PyObject *kwtuple;
+ PyObject *keyword;
+ Py_ssize_t varargssize = 0;
+ int i, posonly, minposonly, maxargs;
+ int reqlimit = minkw ? maxpos + minkw : minpos;
+ Py_ssize_t nkwargs;
+ PyObject *current_arg;
+ PyObject * const *kwstack = NULL;
+
+ assert(kwargs == NULL || PyDict_Check(kwargs));
+ assert(kwargs == NULL || kwnames == NULL);
+
+ if (parser == NULL) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ if (kwnames != NULL && !PyTuple_Check(kwnames)) {
+ PyErr_BadInternalCall();
+ return NULL;
+ }
+
+ if (args == NULL && nargs == 0) {
+ args = buf;
+ }
+
+ if (!parser_init(parser)) {
+ return NULL;
+ }
+
+ kwtuple = parser->kwtuple;
+ posonly = parser->pos;
+ minposonly = Py_MIN(posonly, minpos);
+ maxargs = posonly + (int)PyTuple_GET_SIZE(kwtuple);
+ if (kwargs != NULL) {
+ nkwargs = PyDict_GET_SIZE(kwargs);
+ }
+ else if (kwnames != NULL) {
+ nkwargs = PyTuple_GET_SIZE(kwnames);
+ kwstack = args + nargs;
+ }
+ else {
+ nkwargs = 0;
+ }
+ if (nargs < minposonly) {
+ PyErr_Format(PyExc_TypeError,
+ "%.200s%s takes %s %d positional argument%s"
+ " (%zd given)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ minposonly < maxpos ? "at least" : "exactly",
+ minposonly,
+ minposonly == 1 ? "" : "s",
+ nargs);
+ return NULL;
+ }
+
+ /* create varargs tuple */
+ varargssize = nargs - maxpos;
+ if (varargssize < 0) {
+ varargssize = 0;
+ }
+ buf[vararg] = PyTuple_New(varargssize);
+ if (!buf[vararg]) {
+ return NULL;
+ }
+
+ /* copy tuple args */
+ for (i = 0; i < nargs; i++) {
+ if (i >= vararg) {
+ Py_INCREF(args[i]);
+ PyTuple_SET_ITEM(buf[vararg], i - vararg, args[i]);
+ continue;
+ }
+ else {
+ buf[i] = args[i];
+ }
+ }
+
+ /* copy keyword args using kwtuple to drive process */
+ for (i = Py_MAX((int)nargs, posonly) -
+ Py_SAFE_DOWNCAST(varargssize, Py_ssize_t, int); i < maxargs; i++) {
+ if (nkwargs) {
+ keyword = PyTuple_GET_ITEM(kwtuple, i - posonly);
+ if (kwargs != NULL) {
+ current_arg = PyDict_GetItemWithError(kwargs, keyword);
+ if (!current_arg && PyErr_Occurred()) {
+ goto exit;
+ }
+ }
+ else {
+ current_arg = find_keyword(kwnames, kwstack, keyword);
+ }
+ }
+ else {
+ current_arg = NULL;
+ }
+
+ /* If an arguments is passed in as a keyword argument,
+ * it should be placed before `buf[vararg]`.
+ *
+ * For example:
+ * def f(a, /, b, *args):
+ * pass
+ * f(1, b=2)
+ *
+ * This `buf` array should be: [1, 2, NULL].
+ * In this case, nargs < vararg.
+ *
+ * Otherwise, we leave a place at `buf[vararg]` for vararg tuple
+ * so the index is `i + 1`. */
+ if (nargs < vararg) {
+ buf[i] = current_arg;
+ }
+ else {
+ buf[i + 1] = current_arg;
+ }
+
+ if (current_arg) {
+ --nkwargs;
+ }
+ else if (i < minpos || (maxpos <= i && i < reqlimit)) {
+ /* Less arguments than required */
+ keyword = PyTuple_GET_ITEM(kwtuple, i - posonly);
+ PyErr_Format(PyExc_TypeError, "%.200s%s missing required "
+ "argument '%U' (pos %d)",
+ (parser->fname == NULL) ? "function" : parser->fname,
+ (parser->fname == NULL) ? "" : "()",
+ keyword, i+1);
+ goto exit;
+ }
+ }
+
+ if (nkwargs > 0) {
+ error_unexpected_keyword_arg(kwargs, kwnames, kwtuple, parser->fname);
+ goto exit;
+ }
+
+ return buf;
+
+exit:
+ Py_XDECREF(buf[vararg]);
+ return NULL;
+}
+
+
+static const char *
+skipitem(const char **p_format, va_list *p_va, int flags)
+{
+ const char *format = *p_format;
+ char c = *format++;
+
+ switch (c) {
+
+ /*
+ * codes that take a single data pointer as an argument
+ * (the type of the pointer is irrelevant)
+ */
+
+ case 'b': /* byte -- very short int */
+ case 'B': /* byte as bitfield */
+ case 'h': /* short int */
+ case 'H': /* short int as bitfield */
+ case 'i': /* int */
+ case 'I': /* int sized bitfield */
+ case 'l': /* long int */
+ case 'k': /* long int sized bitfield */
+ case 'L': /* long long */
+ case 'K': /* long long sized bitfield */
+ case 'n': /* Py_ssize_t */
+ case 'f': /* float */
+ case 'd': /* double */
+ case 'D': /* complex double */
+ case 'c': /* char */
+ case 'C': /* unicode char */
+ case 'p': /* boolean predicate */
+ case 'S': /* string object */
+ case 'Y': /* string object */
+ case 'U': /* unicode string object */
+ {
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, void *);
+ }
+ break;
+ }
+
+ /* string codes */
+
+ case 'e': /* string with encoding */
+ {
+ 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;
+ format++;
+ }
+ /* fall through */
+
+ case 's': /* string */
+ case 'z': /* string or None */
+ case 'y': /* bytes */
+ case 'u': /* unicode string */
+ case 'Z': /* unicode string or None */
+ case 'w': /* buffer, read-write */
+ {
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, char **);
+ }
+ if (*format == '#') {
+ if (p_va != NULL) {
+ if (!(flags & FLAG_SIZE_T)) {
+ return "PY_SSIZE_T_CLEAN macro must be defined for '#' formats";
+ }
+ (void) va_arg(*p_va, Py_ssize_t *);
+ }
+ format++;
+ } else if ((c == 's' || c == 'z' || c == 'y' || c == 'w')
+ && *format == '*')
+ {
+ format++;
+ }
+ break;
+ }
+
+ case 'O': /* object */
+ {
+ if (*format == '!') {
+ format++;
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, PyTypeObject*);
+ (void) va_arg(*p_va, PyObject **);
+ }
+ }
+ else if (*format == '&') {
+ typedef int (*converter)(PyObject *, void *);
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, converter);
+ (void) va_arg(*p_va, void *);
+ }
+ format++;
+ }
+ else {
+ if (p_va != NULL) {
+ (void) va_arg(*p_va, PyObject **);
+ }
+ }
+ break;
+ }
+
+ case '(': /* bypass tuple, not handled at all previously */
+ {
+ const char *msg;
+ for (;;) {
+ if (*format==')')
+ break;
+ if (IS_END_OF_FORMAT(*format))
+ return "Unmatched left paren in format "
+ "string";
+ msg = skipitem(&format, p_va, flags);
+ if (msg)
+ return msg;
+ }
+ format++;
+ break;
+ }
+
+ case ')':
+ return "Unmatched right paren in format string";
+
+ default:
+err:
+ return "impossible<bad format char>";
+
+ }
+
+ *p_format = format;
+ return NULL;
+}
+
+
+#undef _PyArg_CheckPositional
+
+int
+_PyArg_CheckPositional(const char *name, Py_ssize_t nargs,
+ Py_ssize_t min, Py_ssize_t max)
+{
+ assert(min >= 0);
+ assert(min <= max);
+
+ if (nargs < min) {
+ if (name != NULL)
+ PyErr_Format(
+ PyExc_TypeError,
+ "%.200s expected %s%zd argument%s, got %zd",
+ name, (min == max ? "" : "at least "), min, min == 1 ? "" : "s", nargs);
+ else
+ PyErr_Format(
+ PyExc_TypeError,
+ "unpacked tuple should have %s%zd element%s,"
+ " but has %zd",
+ (min == max ? "" : "at least "), min, min == 1 ? "" : "s", nargs);
+ return 0;
+ }
+
+ if (nargs == 0) {
+ return 1;
+ }
+
+ if (nargs > max) {
+ if (name != NULL)
+ PyErr_Format(
+ PyExc_TypeError,
+ "%.200s expected %s%zd argument%s, got %zd",
+ name, (min == max ? "" : "at most "), max, max == 1 ? "" : "s", nargs);
+ else
+ PyErr_Format(
+ PyExc_TypeError,
+ "unpacked tuple should have %s%zd element%s,"
+ " but has %zd",
+ (min == max ? "" : "at most "), max, max == 1 ? "" : "s", nargs);
+ return 0;
+ }
+
+ return 1;
+}
+
+static int
+unpack_stack(PyObject *const *args, Py_ssize_t nargs, const char *name,
+ Py_ssize_t min, Py_ssize_t max, va_list vargs)
+{
+ Py_ssize_t i;
+ PyObject **o;
+
+ if (!_PyArg_CheckPositional(name, nargs, min, max)) {
+ return 0;
+ }
+
+ for (i = 0; i < nargs; 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_ITEMS(args);
+ nargs = PyTuple_GET_SIZE(args);
+
+#ifdef HAVE_STDARG_PROTOTYPES
+ va_start(vargs, max);
+#else
+ va_start(vargs);
+#endif
+ retval = unpack_stack(stack, nargs, name, min, max, vargs);
+ va_end(vargs);
+ return retval;
+}
+
+int
+_PyArg_UnpackStack(PyObject *const *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 = unpack_stack(args, nargs, name, min, max, vargs);
+ va_end(vargs);
+ return retval;
+}
+
+
+#undef _PyArg_NoKeywords
+#undef _PyArg_NoKwnames
+#undef _PyArg_NoPositional
+
+/* For type constructors that don't take keyword args
+ *
+ * Sets a TypeError and returns 0 if the args/kwargs is
+ * not empty, returns 1 otherwise
+ */
+int
+_PyArg_NoKeywords(const char *funcname, PyObject *kwargs)
+{
+ if (kwargs == NULL) {
+ return 1;
+ }
+ if (!PyDict_CheckExact(kwargs)) {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+ if (PyDict_GET_SIZE(kwargs) == 0) {
+ return 1;
+ }
+
+ PyErr_Format(PyExc_TypeError, "%.200s() takes no keyword arguments",
+ funcname);
+ return 0;
+}
+
+int
+_PyArg_NoPositional(const char *funcname, PyObject *args)
+{
+ if (args == NULL)
+ return 1;
+ if (!PyTuple_CheckExact(args)) {
+ PyErr_BadInternalCall();
+ return 0;
+ }
+ if (PyTuple_GET_SIZE(args) == 0)
+ return 1;
+
+ PyErr_Format(PyExc_TypeError, "%.200s() takes no positional arguments",
+ funcname);
+ return 0;
+}
+
+int
+_PyArg_NoKwnames(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() takes no keyword arguments", funcname);
+ 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