From 1cb7aa3e6e0a7cf94938701ac1a027e1b5b25c1f Mon Sep 17 00:00:00 2001 From: Jeremy Hylton Date: Tue, 29 May 2001 17:37:05 +0000 Subject: Internal refactoring of convertsimple() and friends. Note that lots of code was re-indented. Replace two-step of convertsimple() and convertsimple1() with convertsimple() and helper converterr(), which is called to format error messages when convertsimple() fails. The old code did all the real work in convertsimple1(), but deferred error message formatting to conversimple(). The result was paying the price of a second function call on every call just to format error messages in the failure cases. Factor out of the buffer-handling code in convertsimple() and package it as convertbuffer(). Add two macros to ease readability of Unicode coversions, UNICODE_DEFAULT_ENCODING() and CONV_UNICODE, an error string. The convertsimple() routine had awful indentation problems, primarily because there were two tabs between the case line and the body of the case statements. This patch reformats the entire function to have a single tab between case line and case body, which makes the code easier to read (and consistent with ceval). The introduction of converterr() exacerbated the problem and prompted this fix. Also, eliminate non-standard whitespace after opening paren and before closing paren in a few if statements. (This checkin is part of SF patch 426072.) --- Python/getargs.c | 1029 +++++++++++++++++++++++++++--------------------------- 1 file changed, 514 insertions(+), 515 deletions(-) diff --git a/Python/getargs.c b/Python/getargs.c index b25b20a..c112386 100644 --- a/Python/getargs.c +++ b/Python/getargs.c @@ -25,7 +25,7 @@ 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 convertbuffer(PyObject *, void **p, char **); static int vgetargskeywords(PyObject *, PyObject *, char *, char **, va_list *); @@ -352,374 +352,361 @@ convertitem(PyObject *arg, char **p_format, va_list *p_va, int *levels, } -/* Convert a non-tuple argument. Adds to convertsimple1 functionality - by formatting messages as "must be , not ". */ + +/* Internal API needed by convertsimple() and a helper macro. */ +extern +PyObject *_PyUnicode_AsDefaultEncodedString(PyObject *unicode, + const char *errors); + +#define UNICODE_DEFAULT_ENCODING(arg) \ + _PyUnicode_AsDefaultEncodedString(arg, NULL) + +/* Format an error message generated by convertsimple(). */ static char * -convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf) +converterr(char *expected, PyObject *arg, char *msgbuf) { - char *msg = convertsimple1(arg, p_format, p_va); - if (msg != NULL) { - sprintf(msgbuf, "must be %.50s, not %.50s", msg, - arg == Py_None ? "None" : arg->ob_type->tp_name); - msg = msgbuf; - } - return msg; + assert (expected != NULL); + sprintf(msgbuf, "must be %.50s, not %.50s", expected, + arg == Py_None ? "None" : arg->ob_type->tp_name); + return msgbuf; } - -/* Internal API needed by convertsimple1(): */ -extern -PyObject *_PyUnicode_AsDefaultEncodedString(PyObject *unicode, - const char *errors); +#define CONV_UNICODE "(unicode conversion error)" /* Convert a non-tuple argument. Return NULL if conversion went OK, - or a string representing the expected type if the conversion failed. + or a string with a message describing the failure. The message is + formatted as "must be , not ". When failing, an exception may or may not have been raised. - Don't call if a tuple is expected. */ + Don't call if a tuple is expected. +*/ static char * -convertsimple1(PyObject *arg, char **p_format, va_list *p_va) +convertsimple(PyObject *arg, char **p_format, va_list *p_va, char *msgbuf) { 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 'b': { /* unsigned byte -- very short int */ + char *p = va_arg(*p_va, char *); + long ival = PyInt_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) + return converterr("integer", arg, msgbuf); + else if (ival < 0) { + PyErr_SetString(PyExc_OverflowError, + "unsigned byte integer is less than minimum"); + return converterr("integer", arg, msgbuf); + } + else if (ival > UCHAR_MAX) { + PyErr_SetString(PyExc_OverflowError, + "unsigned byte integer is greater than maximum"); + return converterr("integer", arg, msgbuf); } + 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 = PyInt_AsLong(arg); - if (ival == -1 && PyErr_Occurred()) - return "integer"; - else if (ival < SCHAR_MIN) { - PyErr_SetString(PyExc_OverflowError, - "byte-sized integer bitfield is less than minimum"); - return "integer"; - } - else if (ival > (int)UCHAR_MAX) { - PyErr_SetString(PyExc_OverflowError, - "byte-sized integer bitfield is greater than maximum"); - return "integer"; - } - 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 = PyInt_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) + return converterr("integer", arg, msgbuf); + else if (ival < SCHAR_MIN) { + PyErr_SetString(PyExc_OverflowError, + "byte-sized integer bitfield is less than minimum"); + return converterr("integer", arg, msgbuf); } + else if (ival > (int)UCHAR_MAX) { + PyErr_SetString(PyExc_OverflowError, + "byte-sized integer bitfield is greater than maximum"); + return converterr("integer", arg, msgbuf); + } + 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': {/* signed short int */ + short *p = va_arg(*p_va, short *); + long ival = PyInt_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) + return converterr("integer", arg, msgbuf); + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is less than minimum"); + return converterr("integer", arg, msgbuf); } + else if (ival > SHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed short integer is greater than maximum"); + return converterr("integer", arg, msgbuf); + } + 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 = PyInt_AsLong(arg); - if (ival == -1 && PyErr_Occurred()) - return "integer"; - else if (ival < SHRT_MIN) { - PyErr_SetString(PyExc_OverflowError, - "short integer bitfield is less than minimum"); - return "integer"; - } - else if (ival > USHRT_MAX) { - PyErr_SetString(PyExc_OverflowError, - "short integer bitfield is greater than maximum"); - return "integer"; - } - else - *p = (unsigned 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 = PyInt_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) + return converterr("integer", arg, msgbuf); + else if (ival < SHRT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "short integer bitfield is less than minimum"); + return converterr("integer", arg, msgbuf); + } + else if (ival > USHRT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "short integer bitfield is greater than maximum"); + return converterr("integer", arg, msgbuf); } + 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 'i': {/* signed int */ + int *p = va_arg(*p_va, int *); + long ival = PyInt_AsLong(arg); + if (ival == -1 && PyErr_Occurred()) + return converterr("integer", arg, msgbuf); + else if (ival > INT_MAX) { + PyErr_SetString(PyExc_OverflowError, + "signed integer is greater than maximum"); + return converterr("integer", arg, msgbuf); } - 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; + else if (ival < INT_MIN) { + PyErr_SetString(PyExc_OverflowError, + "signed integer is less than minimum"); + return converterr("integer", arg, msgbuf); } + 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 converterr("integer", arg, msgbuf); + 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; + 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 converterr("long", arg, msgbuf); + } 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 'f': {/* float */ + float *p = va_arg(*p_va, float *); + double dval = PyFloat_AsDouble(arg); + if (PyErr_Occurred()) + return converterr("float", arg, msgbuf); + 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; - } + case 'd': {/* double */ + double *p = va_arg(*p_va, double *); + double dval = PyFloat_AsDouble(arg); + if (PyErr_Occurred()) + return converterr("float", arg, msgbuf); + 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; - } + case 'D': {/* complex double */ + Py_complex *p = va_arg(*p_va, Py_complex *); + Py_complex cval; + cval = PyComplex_AsCComplex(arg); + if (PyErr_Occurred()) + return converterr("complex", arg, msgbuf); + 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 'c': {/* char */ + char *p = va_arg(*p_va, char *); + if (PyString_Check(arg) && PyString_Size(arg) == 1) + *p = PyString_AsString(arg)[0]; + else + return converterr("char", arg, msgbuf); + break; + } - case 's': /* string */ - { - if (*format == '#') { - void **p = (void **)va_arg(*p_va, char **); - int *q = va_arg(*p_va, int *); - - if (PyString_Check(arg)) { - *p = PyString_AS_STRING(arg); - *q = PyString_GET_SIZE(arg); - } - else if (PyUnicode_Check(arg)) { - arg = _PyUnicode_AsDefaultEncodedString( - arg, NULL); - if (arg == NULL) - return "(unicode conversion error)"; - *p = PyString_AS_STRING(arg); - *q = PyString_GET_SIZE(arg); - } - else { /* any buffer-like object */ - PyBufferProcs *pb = arg->ob_type->tp_as_buffer; - int count; - if ( pb == NULL || - pb->bf_getreadbuffer == NULL || - pb->bf_getsegcount == NULL ) - return "string or read-only buffer"; - if ( (*pb->bf_getsegcount)(arg, NULL) != 1 ) - return "string or 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 **); + case 's': {/* string */ + if (*format == '#') { + void **p = (void **)va_arg(*p_va, char **); + int *q = va_arg(*p_va, int *); - 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"; + if (PyString_Check(arg)) { + *p = PyString_AS_STRING(arg); + *q = PyString_GET_SIZE(arg); } - break; + else if (PyUnicode_Check(arg)) { + arg = UNICODE_DEFAULT_ENCODING(arg); + if (arg == NULL) + return converterr(CONV_UNICODE, + arg, msgbuf); + *p = PyString_AS_STRING(arg); + *q = PyString_GET_SIZE(arg); + } + else { /* any buffer-like object */ + char *buf; + int count = convertbuffer(arg, p, &buf); + if (count < 0) + return converterr(buf, arg, msgbuf); + *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 = UNICODE_DEFAULT_ENCODING(arg); + if (arg == NULL) + return converterr(CONV_UNICODE, + arg, msgbuf); + *p = PyString_AS_STRING(arg); + } + else + return converterr("string", arg, msgbuf); + if ((int)strlen(*p) != PyString_Size(arg)) + return converterr("string without null bytes", + arg, msgbuf); } + break; + } - case 'z': /* string, may be NULL (None) */ - { - if (*format == '#') { /* any buffer-like object */ - void **p = (void **)va_arg(*p_va, char **); - int *q = va_arg(*p_va, int *); + case 'z': {/* string, may be NULL (None) */ + if (*format == '#') { /* any buffer-like object */ + void **p = (void **)va_arg(*p_va, char **); + int *q = va_arg(*p_va, int *); + + if (arg == Py_None) { + *p = 0; + *q = 0; + } + else if (PyString_Check(arg)) { + *p = PyString_AS_STRING(arg); + *q = PyString_GET_SIZE(arg); + } + else if (PyUnicode_Check(arg)) { + arg = UNICODE_DEFAULT_ENCODING(arg); + if (arg == NULL) + return converterr(CONV_UNICODE, + arg, msgbuf); + *p = PyString_AS_STRING(arg); + *q = PyString_GET_SIZE(arg); + } + else { /* any buffer-like object */ + char *buf; + int count = convertbuffer(arg, p, &buf); - if (arg == Py_None) { - *p = 0; - *q = 0; - } - else if (PyString_Check(arg)) { - *p = PyString_AS_STRING(arg); - *q = PyString_GET_SIZE(arg); - } - else if (PyUnicode_Check(arg)) { - arg = _PyUnicode_AsDefaultEncodedString( - arg, NULL); - if (arg == NULL) - return "(unicode conversion error)"; - *p = PyString_AS_STRING(arg); - *q = PyString_GET_SIZE(arg); - } - else { /* any buffer-like object */ - PyBufferProcs *pb = arg->ob_type->tp_as_buffer; - int count; - if ( pb == NULL || - pb->bf_getreadbuffer == NULL || - pb->bf_getsegcount == NULL ) - return "string or read-only buffer"; - if ( (*pb->bf_getsegcount)(arg, NULL) != 1 ) - return "string or 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 (count < 0) + return converterr(buf, arg, msgbuf); + *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 = UNICODE_DEFAULT_ENCODING(arg); + if (arg == NULL) + return converterr(CONV_UNICODE, + arg, msgbuf); + *p = PyString_AS_STRING(arg); + } + else + return converterr("string or None", + arg, msgbuf); + if (*format == '#') { + int *q = va_arg(*p_va, int *); 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); - } + *q = 0; else - return "string or None"; - 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 "string without null bytes or None"; + *q = PyString_Size(arg); + format++; } - break; + else if (*p != NULL && + (int)strlen(*p) != PyString_Size(arg)) + return converterr( + "string without null bytes or None", + arg, msgbuf); } + break; + } - case 'e': /* encoded string */ - { - char **buffer; - const char *encoding; - PyObject *u, *s; - int size, recode_strings; - - /* Get 'e' parameter: the encoding name */ - encoding = (const char *)va_arg(*p_va, const char *); - if (encoding == NULL) - encoding = PyUnicode_GetDefaultEncoding(); + case 'e': {/* encoded string */ + char **buffer; + const char *encoding; + PyObject *u, *s; + int size, recode_strings; + + /* 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 "(unknown parser marker combination)"; - buffer = (char **)va_arg(*p_va, char **); - format++; - if (buffer == NULL) - return "(buffer is NULL)"; + /* 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); + buffer = (char **)va_arg(*p_va, char **); + format++; + if (buffer == NULL) + return converterr("(buffer is NULL)", + arg, msgbuf); - /* Encode object */ - if (!recode_strings && PyString_Check(arg)) { - s = arg; - Py_INCREF(s); - } - else { + /* Encode object */ + if (!recode_strings && PyString_Check(arg)) { + s = arg; + Py_INCREF(s); + } + else { /* Convert object to Unicode */ u = PyUnicode_FromObject(arg); if (u == NULL) - return \ - "string or unicode or text buffer"; + return converterr( + "string or unicode or text buffer", + arg, msgbuf); /* Encode object; use default error handling */ s = PyUnicode_AsEncodedString(u, @@ -727,234 +714,227 @@ convertsimple1(PyObject *arg, char **p_format, va_list *p_va) NULL); Py_DECREF(u); if (s == NULL) - return "(encoding failed)"; + return converterr("(encoding failed)", + arg, msgbuf); if (!PyString_Check(s)) { Py_DECREF(s); - return \ - "(encoder failed to return a string)"; - } + return converterr( + "(encoder failed to return a string)", + arg, msgbuf); } - 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 *); + } + 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)"; + format++; + if (buffer_len == NULL) + return converterr( + "(buffer_len is NULL)", + arg, msgbuf); + if (*buffer == NULL) { + *buffer = PyMem_NEW(char, size + 1); 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)"; - } + Py_DECREF(s); + return converterr( + "(memory error)", + arg, msgbuf); } - 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) { + if (size + 1 > *buffer_len) { Py_DECREF(s); - return "(memory error)"; + return converterr( + "(buffer overflow)", + arg, msgbuf); } - memcpy(*buffer, - PyString_AS_STRING(s), - size + 1); } - Py_DECREF(s); - break; - } + 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 - 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 "unicode or read-only buffer"; - if ( (*pb->bf_getsegcount)(arg, NULL) != 1 ) - return "unicode or 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"; + */ + if ((int)strlen(PyString_AS_STRING(s)) != size) + return converterr( + "(encoded string without NULL bytes)", + arg, msgbuf); + *buffer = PyMem_NEW(char, size + 1); + if (*buffer == NULL) { + Py_DECREF(s); + return converterr("(memory error)", + arg, msgbuf); } - break; + memcpy(*buffer, + PyString_AS_STRING(s), + size + 1); } + Py_DECREF(s); + break; + } - case 'S': /* string object */ - { - PyObject **p = va_arg(*p_va, PyObject **); - if (PyString_Check(arg)) - *p = arg; + case 'u': {/* raw unicode buffer (Py_UNICODE *) */ + if (*format == '#') { /* any buffer-like object */ + void **p = (void **)va_arg(*p_va, char **); + int *q = va_arg(*p_va, int *); + char *buf; + int count = convertbuffer(arg, p, &buf); + + if (count < 0) + return converterr(buf, arg, msgbuf); + *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 "string"; - break; + return converterr("unicode", arg, msgbuf); } + break; + } + + case 'S': { /* string object */ + PyObject **p = va_arg(*p_va, PyObject **); + if (PyString_Check(arg)) + *p = arg; + else + return converterr("string", arg, msgbuf); + break; + } - case 'U': /* Unicode object */ - { - PyObject **p = va_arg(*p_va, PyObject **); - if (PyUnicode_Check(arg)) + case 'U': { /* Unicode object */ + PyObject **p = va_arg(*p_va, PyObject **); + if (PyUnicode_Check(arg)) + *p = arg; + else + return converterr("unicode", arg, msgbuf); + 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 "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; + return converterr(type->tp_name, arg, msgbuf); - } - 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 **); + } + else if (*format == '?') { + inquiry pred = va_arg(*p_va, inquiry); + p = va_arg(*p_va, PyObject **); + format++; + if ((*pred)(arg)) *p = arg; - } - break; + else + return converterr("(unspecified)", + arg, msgbuf); + } + 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 converterr("(unspecified)", + arg, msgbuf); + } + 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; + 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; + if (pb == NULL || + pb->bf_getwritebuffer == NULL || + pb->bf_getsegcount == NULL) + return converterr("read-write buffer", arg, msgbuf); + if ((*pb->bf_getsegcount)(arg, NULL) != 1) + return converterr("single-segment read-write buffer", + arg, msgbuf); + if ((count = pb->bf_getwritebuffer(arg, 0, p)) < 0) + return converterr("(unspecified)", arg, msgbuf); + 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 "string or read-only character buffer"; - if ( (*pb->bf_getsegcount)(arg, NULL) != 1 ) - return "string or single-segment read-only buffer"; - if ( (count = pb->bf_getcharbuffer(arg, 0, p)) < 0 ) - return "(unspecified)"; - - *va_arg(*p_va, int *) = count; - - break; - } + case 't': { /* 8-bit character buffer, read-only access */ + const char **p = va_arg(*p_va, const char **); + char *buf; + int count; - + if (*format++ != '#') + return converterr( + "invalid use of 't' format character", + arg, msgbuf); + if (!PyType_HasFeature(arg->ob_type, + Py_TPFLAGS_HAVE_GETCHARBUFFER)) + return converterr( + "string or read-only character buffer", + arg, msgbuf); + + count = convertbuffer(arg, (void **)p, &buf); + if (count < 0) + return converterr(buf, arg, msgbuf); + *va_arg(*p_va, int *) = count; + break; + } + default: - return "impossible"; + return converterr("impossible", arg, msgbuf); } @@ -962,6 +942,25 @@ convertsimple1(PyObject *arg, char **p_format, va_list *p_va) return NULL; } +int convertbuffer(PyObject *arg, void **p, char **errmsg) +{ + PyBufferProcs *pb = arg->ob_type->tp_as_buffer; + int count; + if (pb == NULL || + pb->bf_getreadbuffer == NULL || + pb->bf_getsegcount == NULL) { + *errmsg = "string or read-only buffer"; + return -1; + } + if ((*pb->bf_getsegcount)(arg, NULL) != 1) { + *errmsg = "string or single-segment read-only buffer"; + return -1; + } + if ((count = (*pb->bf_getreadbuffer)(arg, 0, p)) < 0) { + *errmsg = "(unspecified)"; + } + return count; +} /* Support for keyword arguments donated by Geoff Philbrick */ -- cgit v0.12