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);
}