static int vGetArgs1Impl()

in ext/Python/getargs.cpp [192:331]


static int vGetArgs1Impl(PyObject* compat_args, PyObject* const* stack,
                         Py_ssize_t nargs, const char* format, va_list* p_va,
                         int flags) {
  DCHECK(nargs == 0 || stack != nullptr,
         "if nargs == 0, stack must be nullptr");

  int compat = flags & FLAG_COMPAT;
  flags = flags & ~FLAG_COMPAT;

  int endfmt = 0;
  const char* formatsave = format;
  const char* fname = nullptr;
  int level = 0;
  int max = 0;
  const char* message = nullptr;
  int min = -1;
  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 && Py_ISALPHA(Py_CHARMASK(c)) && c != 'e') {
          /* skip encoded */
          max++;
        }
        break;
    }
  }

  if (level != 0) Py_FatalError(/* '(' */ "missing ')' in getargs format");

  if (min < 0) min = max;

  freelistentry_t static_entries[STATIC_FREELIST_ENTRIES];
  freelist_t freelist;
  freelist.entries = static_entries;
  freelist.first_available = 0;
  freelist.entries_malloced = 0;
  if (max > STATIC_FREELIST_ENTRIES) {
    freelist.entries = PyMem_NEW(freelistentry_t, max);
    if (freelist.entries == nullptr) {
      PyErr_NoMemory();
      return 0;
    }
    freelist.entries_malloced = 1;
  }

  format = formatsave;
  int levels[32];
  const char* msg;
  char msgbuf[256];
  if (compat) {
    if (max == 0) {
      if (compat_args == nullptr) return 1;
      PyErr_Format(PyExc_TypeError, "%.200s%s takes no arguments",
                   fname == nullptr ? "function" : fname,
                   fname == nullptr ? "" : "()");
      return cleanreturn(0, &freelist);
    }
    if (min == 1 && max == 1) {
      if (compat_args == nullptr) {
        PyErr_Format(PyExc_TypeError, "%.200s%s takes at least one argument",
                     fname == nullptr ? "function" : fname,
                     fname == nullptr ? "" : "()");
        return cleanreturn(0, &freelist);
      }
      msg = convertitem(compat_args, &format, p_va, flags, levels, msgbuf,
                        sizeof(msgbuf), &freelist);
      if (msg == nullptr) return cleanreturn(1, &freelist);
      seterror(levels[0], msg, levels + 1, fname, message);
      return cleanreturn(0, &freelist);
    }
    Thread::current()->raiseWithFmt(
        LayoutId::kSystemError, "old style getargs format uses new features");
    return cleanreturn(0, &freelist);
  }

  if (nargs < min || max < nargs) {
    if (message == nullptr) {
      PyErr_Format(
          PyExc_TypeError, "%.150s%s takes %s %d argument%s (%zd given)",
          fname == nullptr ? "function" : fname, fname == nullptr ? "" : "()",
          min == max    ? "exactly"
          : nargs < min ? "at least"
                        : "at most",
          nargs < min ? min : max, (nargs < min ? min : max) == 1 ? "" : "s",
          nargs);
    } else {
      Thread::current()->raiseWithFmt(LayoutId::kTypeError, message);
    }
    return cleanreturn(0, &freelist);
  }

  for (Py_ssize_t 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(Py_CHARMASK(*format)) && *format != '(' &&
      *format != '|' && *format != ':' && *format != ';') {
    PyErr_Format(PyExc_SystemError, "bad format string: %.200s", formatsave);
    return cleanreturn(0, &freelist);
  }

  return cleanreturn(1, &freelist);
}