text: 
  /* New getargs implementation */
  
  #include "Python.h"
  #include "pycore_tupleobject.h"
  
  #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)
  {
      if (ptr) {
          PyMem_FREE(ptr);
      }
      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 %" PY_FORMAT_SIZE_T "d", 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" : arg->ob_type->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 %" PY_FORMAT_SIZE_T "d",
                            n,
                            n == 1 ? "" : "s",
                            len);
          }
          else {
              PyOS_snprintf(msgbuf, bufsize,
                            "must be sequence of length %d, "
                            "not %" PY_FORMAT_SIZE_T "d",
                            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" : arg->ob_type->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" : arg->ob_type->tp_name);
      }
      return msgbuf;
  }
  
  #define CONV_UNICODE "(unicode conversion error)"
  
  /* Explicitly check for float arguments when integers are expected.
     Return 1 for error, 0 if ok.
     XXX Should be removed after the end of the deprecation period in
     _PyLong_FromNbIndexOrNbInt. */
  static int
  float_argument_error(PyObject *arg)
  {
      if (PyFloat_Check(arg)) {
          PyErr_SetString(PyExc_TypeError,
                          "integer argument expected, got float" );
          return 1;
      }
      else
          return 0;
  }
  
  /* 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)
  {
      /* For # codes */
  #define FETCH_SIZE      int *q=NULL;Py_ssize_t *q2=NULL;\
      if (flags & FLAG_SIZE_T) q2=va_arg(*p_va, Py_ssize_t*); \
      else { \
          if (PyErr_WarnEx(PyExc_DeprecationWarning, \
                      "PY_SSIZE_T_CLEAN will be required for '#' formats", 1)) { \
              return NULL; \
          } \
          q=va_arg(*p_va, int*); \
      }
  #define STORE_SIZE(s)   \
      if (flags & FLAG_SIZE_T) \
          *q2=s; \
      else { \
          if (INT_MAX < s) { \
              PyErr_SetString(PyExc_OverflowError, \
                  "size does not fit in an int"); \
              return converterr("", arg, msgbuf, bufsize); \
          } \
          *q = (int)s; \
      }
  #define BUFFER_LEN      ((flags & FLAG_SIZE_T) ? *q2:*q)
  #define RETURN_ERR_OCCURRED return msgbuf
  
      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;
          if (float_argument_error(arg))
              RETURN_ERR_OCCURRED;
          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 *);
          long ival;
          if (float_argument_error(arg))
              RETURN_ERR_OCCURRED;
          ival = PyLong_AsUnsignedLongMask(arg);
          if (ival == -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;
          if (float_argument_error(arg))
              RETURN_ERR_OCCURRED;
          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 *);
          long ival;
          if (float_argument_error(arg))
              RETURN_ERR_OCCURRED;
          ival = PyLong_AsUnsignedLongMask(arg);
          if (ival == -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;
          if (float_argument_error(arg))
              RETURN_ERR_OCCURRED;
          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 int ival;
          if (float_argument_error(arg))
              RETURN_ERR_OCCURRED;
          ival = (unsigned int)PyLong_AsUnsignedLongMask(arg);
          if (ival == (unsigned int)-1 && PyErr_Occurred())
              RETURN_ERR_OCCURRED;
          else
              *p = 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;
          if (float_argument_error(arg))
              RETURN_ERR_OCCURRED;
          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;
          if (float_argument_error(arg))
              RETURN_ERR_OCCURRED;
          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;
          if (float_argument_error(arg))
              RETURN_ERR_OCCURRED;
          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;
          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 == '#') {
              FETCH_SIZE;
              STORE_SIZE(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 **);
              FETCH_SIZE;
  
              if (c == 'z' && arg == Py_None) {
                  *p = NULL;
                  STORE_SIZE(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;
                  STORE_SIZE(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);
                  STORE_SIZE(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 */
      {
          Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **);
  
          if (*format == '#') {
              /* "u#" or "Z#" */
              FETCH_SIZE;
  
              if (c == 'Z' && arg == Py_None) {
                  *p = NULL;
                  STORE_SIZE(0);
              }
              else if (PyUnicode_Check(arg)) {
                  Py_ssize_t len;
                  *p = PyUnicode_AsUnicodeAndSize(arg, &len);
                  if (*p == NULL)
                      RETURN_ERR_OCCURRED;
                  STORE_SIZE(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;
      }
  
      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
  
              */
              int *q = NULL; Py_ssize_t *q2 = NULL;
              if (flags & FLAG_SIZE_T) {
                  q2 = va_arg(*p_va, Py_ssize_t*);
              }
              else {
                  if (PyErr_WarnEx(PyExc_DeprecationWarning,
                              "PY_SSIZE_T_CLEAN will be required for '#' formats", 1))
                  {
                      Py_DECREF(s);
                      return NULL;
                  }
                  q = va_arg(*p_va, int*);
              }
  
              format++;
              if (q == NULL && q2 == 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 > BUFFER_LEN) {
                      Py_DECREF(s);
                      PyErr_Format(PyExc_ValueError,
                                   "encoded string too long "
                                   "(%zd, maximum length %zd)",
                                   (Py_ssize_t)size, (Py_ssize_t)(BUFFER_LEN-1));
                      RETURN_ERR_OCCURRED;
                  }
              }
              memcpy(*buffer, ptr, size+1);
  
              if (flags & FLAG_SIZE_T) {
                  *q2 = size;
              }
              else {
                  if (INT_MAX < size) {
                      Py_DECREF(s);
                      PyErr_SetString(PyExc_OverflowError,
                                      "size does not fit in an int");
                      return converterr("", arg, msgbuf, bufsize);
                  }
                  *q = (int)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(arg->ob_type, 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 FETCH_SIZE
  #undef STORE_SIZE
  #undef BUFFER_LEN
  #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;
  }
  
  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);
              }
          }
      }
  
      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);
  
          /* ptr==ptr should match in most cases since keyword keys
             should be interned strings */
          if (kwname == key) {
              return kwstack[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) {
          Py_ssize_t j;
          /* make sure there are no arguments given by name and position */
          for (i = pos; i < nargs; i++) {
              keyword = PyTuple_GET_ITEM(kwtuple, i - pos);
              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);
              }
          }
          /* make sure there are no extraneous keyword arguments */
          j = 0;
          while (1) {
              int match;
              if (kwargs != NULL) {
                  if (!PyDict_Next(kwargs, &j, &keyword, NULL))
                      break;
              }
              else {
                  if (j >= PyTuple_GET_SIZE(kwnames))
                      break;
                  keyword = PyTuple_GET_ITEM(kwnames, j);
                  j++;
              }
  
              match = PySequence_Contains(kwtuple, keyword);
              if (match <= 0) {
                  if (!match) {
                      PyErr_Format(PyExc_TypeError,
                                   "'%S' is an invalid keyword "
                                   "argument for %.200s%s",
                                   keyword,
                                   (parser->fname == NULL) ? "this function" : parser->fname,
                                   (parser->fname == NULL) ? "" : "()");
                  }
                  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) {
          Py_ssize_t j;
          /* 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;
              }
          }
          /* make sure there are no extraneous keyword arguments */
          j = 0;
          while (1) {
              int match;
              if (kwargs != NULL) {
                  if (!PyDict_Next(kwargs, &j, &keyword, NULL))
                      break;
              }
              else {
                  if (j >= PyTuple_GET_SIZE(kwnames))
                      break;
                  keyword = PyTuple_GET_ITEM(kwnames, j);
                  j++;
              }
  
              match = PySequence_Contains(kwtuple, keyword);
              if (match <= 0) {
                  if (!match) {
                      PyErr_Format(PyExc_TypeError,
                                   "'%S' is an invalid keyword "
                                   "argument for %.200s%s",
                                   keyword,
                                   (parser->fname == NULL) ? "this function" : parser->fname,
                                   (parser->fname == NULL) ? "" : "()");
                  }
                  return NULL;
              }
          }
      }
  
      return buf;
  }
  
  
  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)
                          (void) va_arg(*p_va, Py_ssize_t *);
                      else {
                          if (PyErr_WarnEx(PyExc_DeprecationWarning,
                                      "PY_SSIZE_T_CLEAN will be required for '#' formats", 1)) {
                              return NULL;
                          }
                          (void) va_arg(*p_va, int *);
                      }
                  }
                  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_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;
  }
  
  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
  