summaryrefslogtreecommitdiffstats
path: root/Python
diff options
context:
space:
mode:
authorJeremy Hylton <jeremy@alum.mit.edu>2000-09-01 03:49:47 (GMT)
committerJeremy Hylton <jeremy@alum.mit.edu>2000-09-01 03:49:47 (GMT)
commitb69a27e5b2d336e3ca0e79d08236901ac296b0cc (patch)
treec2a5f3d52d11484926ab7f8dddd85053bdc5d734 /Python
parent51ee09b99539b5bdf54ad91670820adf57d462d8 (diff)
downloadcpython-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.c128
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;
}