/*********************************************************** Copyright (c) 2000, BeOpen.com. Copyright (c) 1995-2000, Corporation for National Research Initiatives. Copyright (c) 1990-1995, Stichting Mathematisch Centrum. All rights reserved. See the file "Misc/COPYRIGHT" for information on usage and redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES. ******************************************************************/ /* New getargs implementation */ /* XXX There are several unchecked sprintf or strcat calls in this file. XXX The only way these can become a danger is if some C code in the XXX Python source (or in an extension) uses ridiculously long names XXX or ridiculously deep nesting in format strings. */ #include "Python.h" #include #ifdef HAVE_LIMITS_H #include #endif int PyArg_Parse(PyObject *, char *, ...); int PyArg_ParseTuple(PyObject *, char *, ...); int PyArg_VaParse(PyObject *, char *, va_list); int PyArg_ParseTupleAndKeywords(PyObject *, PyObject *, char *, char **, ...); /* Forward */ static int vgetargs1(PyObject *, char *, va_list *, int); static void seterror(int, char *, int *, char *, char *); static char *convertitem(PyObject *, char **, va_list *, int *, char *); static char *converttuple(PyObject *, char **, va_list *, int *, char *, int); static char *convertsimple(PyObject *, char **, va_list *, char *); static char *convertsimple1(PyObject *, char **, va_list *); static int vgetargskeywords(PyObject *, PyObject *, char *, char **, va_list *); static char *skipitem(char **, va_list *); int PyArg_Parse(PyObject *args, char *format, ...) { int retval; va_list va; va_start(va, format); retval = vgetargs1(args, format, &va, 1); va_end(va); return retval; } int PyArg_ParseTuple(PyObject *args, char *format, ...) { int retval; va_list va; va_start(va, format); retval = vgetargs1(args, format, &va, 0); va_end(va); return retval; } int PyArg_VaParse(PyObject *args, char *format, va_list va) { va_list lva; #ifdef VA_LIST_IS_ARRAY memcpy(lva, va, sizeof(va_list)); #else lva = va; #endif return vgetargs1(args, format, &lva, 0); } static int vgetargs1(PyObject *args, char *format, va_list *p_va, int compat) { char msgbuf[256]; int levels[32]; char *fname = NULL; char *message = NULL; int min = -1; int max = 0; int level = 0; char *formatsave = format; int i, len; char *msg; for (;;) { int c = *format++; if (c == '(' /* ')' */) { if (level == 0) max++; level++; } else if (/* '(' */ c == ')') { if (level == 0) Py_FatalError(/* '(' */ "excess ')' in getargs format"); else level--; } else if (c == '\0') break; else if (c == ':') { fname = format; break; } else if (c == ';') { message = format; break; } else if (level != 0) ; /* Pass */ else if (c == 'e') ; /* Pass */ else if (isalpha(c)) max++; else if (c == '|') min = max; } if (level != 0) Py_FatalError(/* '(' */ "missing ')' in getargs format"); if (min < 0) min = max; format = formatsave; if (compat) { if (max == 0) { if (args == NULL) return 1; sprintf(msgbuf, "%s requires no arguments", fname==NULL ? "function" : fname); PyErr_SetString(PyExc_TypeError, msgbuf); return 0; } else if (min == 1 && max == 1) { if (args == NULL) { sprintf(msgbuf, "%s requires at least one argument", fname==NULL ? "function" : fname); PyErr_SetString(PyExc_TypeError, msgbuf); return 0; } msg = convertitem(args, &format, p_va, levels, msgbuf); if (msg == NULL) return 1; seterror(levels[0], msg, levels+1, fname, message); return 0; } else { PyErr_SetString(PyExc_SystemError, "old style getargs format uses new features"); return 0; } } if (!PyTuple_Check(args)) { PyErr_SetString(PyExc_SystemError, "new style getargs format but argument is not a tuple"); return 0; } len = PyTuple_Size(args); if (len < min || max < len) { if (message == NULL) { sprintf(msgbuf, "%s requires %s %d argument%s; %d given", fname==NULL ? "function" : fname, min==max ? "exactly" : len < min ? "at least" : "at most", len < min ? min : max, (len < min ? min : max) == 1 ? "" : "s", len); message = msgbuf; } PyErr_SetString(PyExc_TypeError, message); return 0; } for (i = 0; i < len; i++) { if (*format == '|') format++; msg = convertitem(PyTuple_GetItem(args, i), &format, p_va, levels, msgbuf); if (msg) { seterror(i+1, msg, levels, fname, message); return 0; } } if (*format != '\0' && !isalpha((int)(*format)) && *format != '(' && *format != '|' && *format != ':' && *format != ';') { PyErr_Format(PyExc_SystemError, "bad format string: %.200s", formatsave); return 0; } return 1; } static void seterror(int iarg, char *msg, int *levels, char *fname, char *message) { char buf[256]; int i; char *p = buf; if (PyErr_Occurred()) return; if (iarg == 0 && message == NULL) message = msg; else if (message == NULL) { if (fname != NULL) { sprintf(p, "%s, ", fname); p += strlen(p); } sprintf(p, "argument %d", iarg); i = 0; p += strlen(p); while (levels[i] > 0) { sprintf(p, ", item %d", levels[i]-1); p += strlen(p); i++; } sprintf(p, ": expected %s found", msg); message = buf; } 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: ", ", where: is the name of the expected type, and is the name of the actual type, (so you can surround it by "expected ... found"), and msgbuf is returned. */ static char * converttuple(PyObject *arg, char **p_format, va_list *p_va, int *levels, char *msgbuf, int toplevel) { int level = 0; int n = 0; char *format = *p_format; int i; 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 && isalpha(c)) n++; } if (!PySequence_Check(arg)) { levels[0] = 0; sprintf(msgbuf, toplevel ? "%d arguments, %s" : "%d-sequence, %s", n, arg == Py_None ? "None" : arg->ob_type->tp_name); return msgbuf; } if ((i = PySequence_Size(arg)) != n) { levels[0] = 0; sprintf(msgbuf, toplevel ? "%d arguments, %d" : "%d-sequence, %d-sequence", n, i); return msgbuf; } format = *p_format; for (i = 0; i < n; i++) { char *msg; PyObject *item; item = PySequence_GetItem(arg, i); msg = convertitem(item, &format, p_va, levels+1, msgbuf); /* 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 char * convertitem(PyObject *arg, char **p_format, va_list *p_va, int *levels, char *msgbuf) { char *msg; char *format = *p_format; if (*format == '(' /* ')' */) { format++; msg = converttuple(arg, &format, p_va, levels, msgbuf, 0); if (msg == NULL) format++; } else { msg = convertsimple(arg, &format, p_va, msgbuf); if (msg != NULL) levels[0] = 0; } if (msg == NULL) *p_format = format; return msg; } /* Convert a non-tuple argument. Adds to convertsimple1 functionality by appending ", " to error message. */ static char * convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf) { char *msg = convertsimple1(arg, p_format, p_va); if (msg != NULL) { sprintf(msgbuf, "%.50s, %.50s", msg, arg == Py_None ? "None" : arg->ob_type->tp_name); msg = msgbuf; } return msg; } /* Internal API needed by convertsimple1(): */ extern PyObject *_PyUnicode_AsDefaultEncodedString(PyObject *unicode, const char *errors); /* Convert a non-tuple argument. Return NULL if conversion went OK, or a string representing the expected type if the conversion failed. When failing, an exception may or may not have been raised. Don't call if a tuple is expected. */ static char * convertsimple1(PyObject *arg, char **p_format, va_list *p_va) { char *format = *p_format; char c = *format++; switch (c) { case 'b': /* unsigned byte -- very short int */ { char *p = va_arg(*p_va, char *); long ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) return "integer"; else if (ival < 0) { PyErr_SetString(PyExc_OverflowError, "unsigned byte integer is less than minimum"); return "integer"; } else if (ival > UCHAR_MAX) { PyErr_SetString(PyExc_OverflowError, "unsigned byte integer is greater than maximum"); return "integer"; } else *p = (unsigned char) ival; break; } case 'h': /* signed short int */ { short *p = va_arg(*p_va, short *); long ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) return "integer"; else if (ival < SHRT_MIN) { PyErr_SetString(PyExc_OverflowError, "signed short integer is less than minimum"); return "integer"; } else if (ival > SHRT_MAX) { PyErr_SetString(PyExc_OverflowError, "signed short integer is greater than maximum"); return "integer"; } else *p = (short) ival; break; } case 'H': /* unsigned short int */ { unsigned short *p = va_arg(*p_va, unsigned short *); long ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) return "integer"; else if (ival < 0) { PyErr_SetString(PyExc_OverflowError, "unsigned short integer is less than minimum"); return "integer"; } else if (ival > USHRT_MAX) { PyErr_SetString(PyExc_OverflowError, "unsigned short integer is greater than maximum"); return "integer"; } else *p = (unsigned short) ival; break; } case 'i': /* signed int */ { int *p = va_arg(*p_va, int *); long ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) return "integer"; else if (ival > INT_MAX) { PyErr_SetString(PyExc_OverflowError, "signed integer is greater than maximum"); return "integer"; } else if (ival < INT_MIN) { PyErr_SetString(PyExc_OverflowError, "signed integer is less than minimum"); return "integer"; } else *p = ival; break; } case 'l': /* long int */ { long *p = va_arg(*p_va, long *); long ival = PyInt_AsLong(arg); if (ival == -1 && PyErr_Occurred()) return "integer"; else *p = ival; break; } #ifdef HAVE_LONG_LONG case 'L': /* LONG_LONG */ { LONG_LONG *p = va_arg( *p_va, LONG_LONG * ); LONG_LONG ival = PyLong_AsLongLong( arg ); if( ival == (LONG_LONG)-1 && PyErr_Occurred() ) { return "long"; } else { *p = ival; } break; } #endif case 'f': /* float */ { float *p = va_arg(*p_va, float *); double dval = PyFloat_AsDouble(arg); if (PyErr_Occurred()) return "float"; else *p = (float) dval; break; } case 'd': /* double */ { double *p = va_arg(*p_va, double *); double dval = PyFloat_AsDouble(arg); if (PyErr_Occurred()) return "float"; else *p = dval; break; } #ifndef WITHOUT_COMPLEX case 'D': /* complex double */ { Py_complex *p = va_arg(*p_va, Py_complex *); Py_complex cval; cval = PyComplex_AsCComplex(arg); if (PyErr_Occurred()) return "complex"; else *p = cval; break; } #endif /* WITHOUT_COMPLEX */ case 'c': /* char */ { char *p = va_arg(*p_va, char *); if (PyString_Check(arg) && PyString_Size(arg) == 1) *p = PyString_AsString(arg)[0]; else return "char"; break; } case 's': /* string */ { if (*format == '#') { /* any buffer-like object */ void **p = (void **)va_arg(*p_va, char **); PyBufferProcs *pb = arg->ob_type->tp_as_buffer; int *q = va_arg(*p_va, int *); int count; if ( pb == NULL || pb->bf_getreadbuffer == NULL || pb->bf_getsegcount == NULL ) return "read-only buffer"; if ( (*pb->bf_getsegcount)(arg, NULL) != 1 ) return "single-segment read-only buffer"; if ( (count = (*pb->bf_getreadbuffer)(arg, 0, p)) < 0 ) return "(unspecified)"; *q = count; format++; } else { char **p = va_arg(*p_va, char **); if (PyString_Check(arg)) *p = PyString_AS_STRING(arg); else if (PyUnicode_Check(arg)) { arg = _PyUnicode_AsDefaultEncodedString( arg, NULL); if (arg == NULL) return "unicode conversion error"; *p = PyString_AS_STRING(arg); } else return "string"; if ((int)strlen(*p) != PyString_Size(arg)) return "string without null bytes"; } break; } case 'z': /* string, may be NULL (None) */ { if (*format == '#') { /* any buffer-like object */ void **p = (void **)va_arg(*p_va, char **); PyBufferProcs *pb = arg->ob_type->tp_as_buffer; int *q = va_arg(*p_va, int *); int count; if (arg == Py_None) { *p = 0; *q = 0; } else { if ( pb == NULL || pb->bf_getreadbuffer == NULL || pb->bf_getsegcount == NULL ) return "read-only buffer"; if ( (*pb->bf_getsegcount)(arg, NULL) != 1 ) return "single-segment read-only buffer"; if ( (count = (*pb->bf_getreadbuffer) (arg, 0, p)) < 0 ) return "(unspecified)"; *q = count; } format++; } else { char **p = va_arg(*p_va, char **); if (arg == Py_None) *p = 0; else if (PyString_Check(arg)) *p = PyString_AsString(arg); else if (PyUnicode_Check(arg)) { arg = _PyUnicode_AsDefaultEncodedString( arg, NULL); if (arg == NULL) return "unicode conversion error"; *p = PyString_AS_STRING(arg); } else return "None or string"; if (*format == '#') { int *q = va_arg(*p_va, int *); if (arg == Py_None) *q = 0; else *q = PyString_Size(arg); format++; } else if (*p != NULL && (int)strlen(*p) != PyString_Size(arg)) return "None or string without null bytes"; } break; } case 'e': /* encoded string */ { char **buffer; const char *encoding; PyObject *u, *s; int size; /* Get 'e' parameter: the encoding name */ encoding = (const char *)va_arg(*p_va, const char *); if (encoding == NULL) encoding = PyUnicode_GetDefaultEncoding(); /* Get 's' parameter: the output buffer to use */ if (*format != 's') return "(unknown parser marker combination)"; buffer = (char **)va_arg(*p_va, char **); format++; if (buffer == NULL) return "(buffer is NULL)"; /* Convert object to Unicode */ u = PyUnicode_FromObject(arg); if (u == NULL) return "string, unicode or text buffer"; /* Encode object; use default error handling */ s = PyUnicode_AsEncodedString(u, encoding, NULL); Py_DECREF(u); if (s == NULL) return "(encoding failed)"; if (!PyString_Check(s)) { Py_DECREF(s); return "(encoder failed to return a string)"; } size = PyString_GET_SIZE(s); /* 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 *buffer_len = va_arg(*p_va, int *); format++; if (buffer_len == NULL) return "(buffer_len is NULL)"; if (*buffer == NULL) { *buffer = PyMem_NEW(char, size + 1); if (*buffer == NULL) { Py_DECREF(s); return "(memory error)"; } } else { if (size + 1 > *buffer_len) { Py_DECREF(s); return "(buffer overflow)"; } } memcpy(*buffer, PyString_AS_STRING(s), size + 1); *buffer_len = 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 ((int)strlen(PyString_AS_STRING(s)) != size) return "(encoded string without "\ "NULL bytes)"; *buffer = PyMem_NEW(char, size + 1); if (*buffer == NULL) { Py_DECREF(s); return "(memory error)"; } memcpy(*buffer, PyString_AS_STRING(s), size + 1); } Py_DECREF(s); break; } case 'u': /* raw unicode buffer (Py_UNICODE *) */ { if (*format == '#') { /* any buffer-like object */ void **p = (void **)va_arg(*p_va, char **); PyBufferProcs *pb = arg->ob_type->tp_as_buffer; int *q = va_arg(*p_va, int *); int count; if ( pb == NULL || pb->bf_getreadbuffer == NULL || pb->bf_getsegcount == NULL ) return "read-only buffer"; if ( (*pb->bf_getsegcount)(arg, NULL) != 1 ) return "single-segment read-only buffer"; if ( (count = (*pb->bf_getreadbuffer)(arg, 0, p)) < 0 ) return "(unspecified)"; /* buffer interface returns bytes, we want length in characters */ *q = count/(sizeof(Py_UNICODE)); format++; } else { Py_UNICODE **p = va_arg(*p_va, Py_UNICODE **); if (PyUnicode_Check(arg)) *p = PyUnicode_AS_UNICODE(arg); else return "unicode"; } break; } case 'S': /* string object */ { PyObject **p = va_arg(*p_va, PyObject **); if (PyString_Check(arg)) *p = arg; else return "string"; break; } case 'U': /* Unicode object */ { PyObject **p = va_arg(*p_va, PyObject **); if (PyUnicode_Check(arg)) *p = arg; else return "unicode"; break; } case 'O': /* object */ { PyTypeObject *type; PyObject **p; if (*format == '!') { type = va_arg(*p_va, PyTypeObject*); p = va_arg(*p_va, PyObject **); format++; if (arg->ob_type == type) *p = arg; else return type->tp_name; } else if (*format == '?') { inquiry pred = va_arg(*p_va, inquiry); p = va_arg(*p_va, PyObject **); format++; if ((*pred)(arg)) *p = arg; else return "(unspecified)"; } else if (*format == '&') { typedef int (*converter)(PyObject *, void *); converter convert = va_arg(*p_va, converter); void *addr = va_arg(*p_va, void *); format++; if (! (*convert)(arg, addr)) return "(unspecified)"; } else { p = va_arg(*p_va, PyObject **); *p = arg; } break; } case 'w': /* memory buffer, read-write access */ { void **p = va_arg(*p_va, void **); PyBufferProcs *pb = arg->ob_type->tp_as_buffer; int count; if ( pb == NULL || pb->bf_getwritebuffer == NULL || pb->bf_getsegcount == NULL ) return "read-write buffer"; if ( (*pb->bf_getsegcount)(arg, NULL) != 1 ) return "single-segment read-write buffer"; if ( (count = pb->bf_getwritebuffer(arg, 0, p)) < 0 ) return "(unspecified)"; if (*format == '#') { int *q = va_arg(*p_va, int *); *q = count; format++; } break; } case 't': /* 8-bit character buffer, read-only access */ { const char **p = va_arg(*p_va, const char **); PyBufferProcs *pb = arg->ob_type->tp_as_buffer; int count; if ( *format++ != '#' ) return "invalid use of 't' format character"; if ( !PyType_HasFeature( arg->ob_type, Py_TPFLAGS_HAVE_GETCHARBUFFER) || pb == NULL || pb->bf_getcharbuffer == NULL || pb->bf_getsegcount == NULL ) return "read-only character buffer"; if ( (*pb->bf_getsegcount)(arg, NULL) != 1 ) return "single-segment read-only buffer"; if ( (count = pb->bf_getcharbuffer(arg, 0, p)) < 0 ) return "(unspecified)"; *va_arg(*p_va, int *) = count; break; } default: return "impossible"; } *p_format = format; return NULL; } /* Support for keyword arguments donated by Geoff Philbrick */ int PyArg_ParseTupleAndKeywords(PyObject *args, PyObject *keywords, char *format, char **kwlist, ...) { int retval; va_list va; va_start(va, kwlist); retval = vgetargskeywords(args, keywords, format, kwlist, &va); va_end(va); return retval; } static int vgetargskeywords(PyObject *args, PyObject *keywords, char *format, char **kwlist, va_list *p_va) { char msgbuf[256]; int levels[32]; char *fname = NULL; char *message = NULL; int min = -1; int max = 0; char *formatsave = format; int i, len, tplen, kwlen; char *msg, *ks, **p; int nkwds, pos, match, converted; PyObject *key, *value; /* nested tuples cannot be parsed when using keyword arguments */ for (;;) { int c = *format++; if (c == '(') { PyErr_SetString(PyExc_SystemError, "tuple found in format when using keyword arguments"); return 0; } else if (c == '\0') break; else if (c == ':') { fname = format; break; } else if (c == ';') { message = format; break; } else if (isalpha(c)) max++; else if (c == '|') min = max; } if (min < 0) min = max; format = formatsave; if (!PyTuple_Check(args)) { PyErr_SetString(PyExc_SystemError, "new style getargs format but argument is not a tuple"); return 0; } tplen = PyTuple_Size(args); /* do a cursory check of the keywords just to see how many we got */ if (keywords) { if (!PyDict_Check(keywords)) { PyErr_SetString(PyExc_SystemError, "non-dictionary object received when keyword dictionary expected"); return 0; } kwlen = PyDict_Size(keywords); } else { kwlen = 0; } /* make sure there are no duplicate values for an argument; its not clear when to use the term "keyword argument vs. keyword parameter in messages */ if (keywords) { for (i = 0; i < tplen; i++) { if (PyMapping_HasKeyString(keywords, kwlist[i])) { sprintf(msgbuf, "keyword parameter %s redefined", kwlist[i]); PyErr_SetString(PyExc_TypeError, msgbuf); return 0; } } } PyErr_Clear(); /* I'm not which Py functions set the error string */ /* required arguments missing from args can be supplied by keyword arguments */ len = tplen; if (keywords && tplen < min) { for (i = tplen; i < min; i++) { if (PyMapping_HasKeyString(keywords, kwlist[i])) { len++; } } } PyErr_Clear(); /* make sure we got an acceptable number of arguments; the message is a little confusing with keywords since keyword arguments which are supplied, but don't match the required arguments are not included in the "%d given" part of the message */ if (len < min || max < len) { if (message == NULL) { sprintf(msgbuf, "%s requires %s %d argument%s; %d given", fname==NULL ? "function" : fname, min==max ? "exactly" : len < min ? "at least" : "at most", len < min ? min : max, (len < min ? min : max) == 1 ? "" : "s", len); message = msgbuf; } PyErr_SetString(PyExc_TypeError, message); return 0; } for (i = 0; i < tplen; i++) { if (*format == '|') format++; msg = convertitem(PyTuple_GetItem(args, i), &format, p_va, levels, msgbuf); if (msg) { seterror(i+1, msg, levels, fname, message); return 0; } } /* handle no keyword parameters in call */ if (!keywords) return 1; /* make sure the number of keywords in the keyword list matches the number of items in the format string */ nkwds = 0; p = kwlist; for (;;) { if (!*(p++)) break; nkwds++; } if (nkwds != max) { PyErr_SetString(PyExc_SystemError, "number of items in format string and keyword list do not match"); return 0; } /* convert the keyword arguments; this uses the format string where it was left after processing args */ converted = 0; for (i = tplen; i < nkwds; i++) { PyObject *item; if (*format == '|') format++; item = PyMapping_GetItemString(keywords, kwlist[i]); if (item != NULL) { msg = convertitem(item, &format, p_va, levels, msgbuf); if (msg) { seterror(i+1, msg, levels, fname, message); return 0; } converted++; } else { PyErr_Clear(); msg = skipitem(&format, p_va); if (msg) { seterror(i+1, msg, levels, fname, message); return 0; } } } /* make sure there are no extraneous keyword arguments */ pos = 0; if (converted < kwlen) { while (PyDict_Next(keywords, &pos, &key, &value)) { match = 0; ks = PyString_AsString(key); for (i = 0; i < nkwds; i++) { if (!strcmp(ks, kwlist[i])) { match = 1; break; } } if (!match) { sprintf(msgbuf, "%s is an invalid keyword argument for this function", ks); PyErr_SetString(PyExc_TypeError, msgbuf); return 0; } } } return 1; } static char * skipitem(char **p_format, va_list *p_va) { char *format = *p_format; char c = *format++; switch (c) { case 'b': /* byte -- very short int */ { (void) va_arg(*p_va, char *); break; } case 'h': /* short int */ { (void) va_arg(*p_va, short *); break; } case 'H': /* unsigned short int */ { (void) va_arg(*p_va, unsigned short *); break; } case 'i': /* int */ { (void) va_arg(*p_va, int *); break; } case 'l': /* long int */ { (void) va_arg(*p_va, long *); break; } #ifdef HAVE_LONG_LONG case 'L': /* LONG_LONG int */ { (void) va_arg(*p_va, LONG_LONG *); break; } #endif case 'f': /* float */ { (void) va_arg(*p_va, float *); break; } case 'd': /* double */ { (void) va_arg(*p_va, double *); break; } #ifndef WITHOUT_COMPLEX case 'D': /* complex double */ { (void) va_arg(*p_va, Py_complex *); break; } #endif /* WITHOUT_COMPLEX */ case 'c': /* char */ { (void) va_arg(*p_va, char *); break; } case 's': /* string */ { (void) va_arg(*p_va, char **); if (*format == '#') { (void) va_arg(*p_va, int *); format++; } break; } case 'z': /* string */ { (void) va_arg(*p_va, char **); if (*format == '#') { (void) va_arg(*p_va, int *); format++; } break; } case 'S': /* string object */ { (void) va_arg(*p_va, PyObject **); break; } case 'O': /* object */ { if (*format == '!') { format++; (void) va_arg(*p_va, PyTypeObject*); (void) va_arg(*p_va, PyObject **); } #if 0 /* I don't know what this is for */ else if (*format == '?') { inquiry pred = va_arg(*p_va, inquiry); format++; if ((*pred)(arg)) { (void) va_arg(*p_va, PyObject **); } } #endif else if (*format == '&') { typedef int (*converter)(PyObject *, void *); (void) va_arg(*p_va, converter); (void) va_arg(*p_va, void *); format++; } else { (void) va_arg(*p_va, PyObject **); } break; } default: return "impossible"; } *p_format = format; return NULL; }