diff options
author | Jeremy Hylton <jeremy@alum.mit.edu> | 2000-09-01 03:49:47 (GMT) |
---|---|---|
committer | Jeremy Hylton <jeremy@alum.mit.edu> | 2000-09-01 03:49:47 (GMT) |
commit | b69a27e5b2d336e3ca0e79d08236901ac296b0cc (patch) | |
tree | c2a5f3d52d11484926ab7f8dddd85053bdc5d734 /Python | |
parent | 51ee09b99539b5bdf54ad91670820adf57d462d8 (diff) | |
download | cpython-b69a27e5b2d336e3ca0e79d08236901ac296b0cc.zip cpython-b69a27e5b2d336e3ca0e79d08236901ac296b0cc.tar.gz cpython-b69a27e5b2d336e3ca0e79d08236901ac296b0cc.tar.bz2 |
code part of patch #100895 by Fredrik Lundh
PyErr_Format computes size of buffer needed rather than relying on
static buffer.
Diffstat (limited to 'Python')
-rw-r--r-- | Python/errors.c | 128 |
1 files changed, 124 insertions, 4 deletions
diff --git a/Python/errors.c b/Python/errors.c index 355ec9c..6469f9f 100644 --- a/Python/errors.c +++ b/Python/errors.c @@ -29,6 +29,8 @@ extern char *strerror(int); #include "winbase.h" #endif +#include <ctype.h> + void PyErr_Restore(PyObject *type, PyObject *value, PyObject *traceback) { @@ -364,7 +366,6 @@ PyObject *PyErr_SetFromWindowsErrWithFilename( PyObject *PyErr_SetFromWindowsErr(int ierr) { return PyErr_SetFromWindowsErrWithFilename(ierr, NULL); - } #endif /* MS_WINDOWS */ @@ -393,12 +394,131 @@ PyObject * PyErr_Format(PyObject *exception, const char *format, ...) { va_list vargs; - char buffer[500]; /* Caller is responsible for limiting the format */ + int n, i; + const char* f; + char* s; + PyObject* string; + /* step 1: figure out how large a buffer we need */ + +#ifdef HAVE_STDARG_PROTOTYPES va_start(vargs, format); +#else + va_start(vargs); +#endif - vsprintf(buffer, format, vargs); - PyErr_SetString(exception, buffer); + n = 0; + for (f = format; *f; f++) { + if (*f == '%') { + const char* p = f; + while (*++f && *f != '%' && !isalpha(*f)) + ; + switch (*f) { + case 'c': + va_arg(vargs, int); + /* fall through... */ + case '%': + n++; + break; + case 'd': case 'i': case 'x': + va_arg(vargs, int); + /* 20 bytes should be enough to hold a 64-bit + integer */ + n = n + 20; + break; + case 's': + s = va_arg(vargs, char*); + n = n + strlen(s); + break; + default: + /* if we stumble upon an unknown + formatting code, copy the rest of + the format string to the output + string. (we cannot just skip the + code, since there's no way to know + what's in the argument list) */ + n = n + strlen(p); + goto expand; + } + } else + n = n + 1; + } + + expand: + + string = PyString_FromStringAndSize(NULL, n); + if (!string) + return NULL; + +#ifdef HAVE_STDARG_PROTOTYPES + va_start(vargs, format); +#else + va_start(vargs); +#endif + + /* step 2: fill the buffer */ + + s = PyString_AsString(string); + + for (f = format; *f; f++) { + if (*f == '%') { + const char* p = f++; + /* parse the width.precision part (we're only + interested in the precision value, if any) */ + n = 0; + while (isdigit(*f)) + n = (n*10) + *f++ - '0'; + if (*f == '.') { + f++; + n = 0; + while (isdigit(*f)) + n = (n*10) + *f++ - '0'; + } + while (*f && *f != '%' && !isalpha(*f)) + f++; + switch (*f) { + case 'c': + *s++ = va_arg(vargs, int); + break; + case 'd': + sprintf(s, "%d", va_arg(vargs, int)); + s = s + strlen(s); + break; + case 'i': + sprintf(s, "%i", va_arg(vargs, int)); + s = s + strlen(s); + break; + case 'x': + sprintf(s, "%x", va_arg(vargs, int)); + s = s + strlen(s); + break; + case 's': + p = va_arg(vargs, char*); + i = strlen(p); + if (n > 0 && i > n) + i = n; + memcpy(s, p, i); + s = s + i; + break; + case '%': + *s++ = '%'; + break; + default: + strcpy(s, p); + s = s + strlen(s); + goto end; + } + } else + *s++ = *f; + } + + end: + + _PyString_Resize(&string, s - PyString_AsString(string)); + + PyErr_SetObject(exception, string); + Py_XDECREF(string); + return NULL; } |