summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBarry Warsaw <barry@python.org>2001-08-24 18:32:06 (GMT)
committerBarry Warsaw <barry@python.org>2001-08-24 18:32:06 (GMT)
commitdadace004b4b94dcc4437bafc9c8407fbb1bed74 (patch)
treeb381d7e83a12d2a452c0c8c70da5acd26b8c522a
parent16c018d2d24e7b3366edda53baf85fa3a4a21f1e (diff)
downloadcpython-dadace004b4b94dcc4437bafc9c8407fbb1bed74.zip
cpython-dadace004b4b94dcc4437bafc9c8407fbb1bed74.tar.gz
cpython-dadace004b4b94dcc4437bafc9c8407fbb1bed74.tar.bz2
PyString_FromFormat() and PyString_FromFormatV(): Largely ripped from
PyErr_Format() these new C API methods can be used instead of sprintf()'s into hardcoded char* buffers. This allows us to fix many situation where long package, module, or class names get truncated in reprs. PyString_FromFormat() is the varargs variety. PyString_FromFormatV() is the va_list variety Original PyErr_Format() code was modified to allow %p and %ld expansions. Many reprs were converted to this, checkins coming soo. Not changed: complex_repr(), float_repr(), float_print(), float_str(), int_repr(). There may be other candidates not yet converted. Closes patch #454743.
-rw-r--r--Include/stringobject.h4
-rw-r--r--Objects/stringobject.c155
2 files changed, 159 insertions, 0 deletions
diff --git a/Include/stringobject.h b/Include/stringobject.h
index 96f371e..2d9ed2d 100644
--- a/Include/stringobject.h
+++ b/Include/stringobject.h
@@ -7,6 +7,8 @@
extern "C" {
#endif
+#include <stdarg.h>
+
/*
Type PyStringObject represents a character string. An extra zero byte is
reserved at the end to ensure it is zero-terminated, but a size is
@@ -53,6 +55,8 @@ extern DL_IMPORT(PyTypeObject) PyString_Type;
extern DL_IMPORT(PyObject *) PyString_FromStringAndSize(const char *, int);
extern DL_IMPORT(PyObject *) PyString_FromString(const char *);
+extern DL_IMPORT(PyObject *) PyString_FromFormatV(const char*, va_list);
+extern DL_IMPORT(PyObject *) PyString_FromFormat(const char*, ...);
extern DL_IMPORT(int) PyString_Size(PyObject *);
extern DL_IMPORT(char *) PyString_AsString(PyObject *);
extern DL_IMPORT(void) PyString_Concat(PyObject **, PyObject *);
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
index a8e063e..3acc69f 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -147,6 +147,161 @@ PyString_FromString(const char *str)
return (PyObject *) op;
}
+PyObject *
+PyString_FromFormatV(const char *format, va_list vargs)
+{
+ va_list count = vargs;
+ int n = 0;
+ const char* f;
+ char *s;
+ PyObject* string;
+
+ /* step 1: figure out how large a buffer we need */
+ for (f = format; *f; f++) {
+ if (*f == '%') {
+ const char* p = f;
+ while (*++f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
+ ;
+
+ /* skip the 'l' in %ld, since it doesn't change the
+ width. although only %d is supported (see
+ "expand" section below), others can be easily
+ add */
+ if (*f == 'l' && *(f+1) == 'd')
+ ++f;
+
+ switch (*f) {
+ case 'c':
+ (void)va_arg(count, int);
+ /* fall through... */
+ case '%':
+ n++;
+ break;
+ case 'd': case 'i': case 'x':
+ (void) va_arg(count, int);
+ /* 20 bytes should be enough to hold a 64-bit
+ integer */
+ n += 20;
+ break;
+ case 's':
+ s = va_arg(count, char*);
+ n += strlen(s);
+ break;
+ case 'p':
+ (void) va_arg(count, int);
+ /* maximum 64-bit pointer representation:
+ * 0xffffffffffffffff
+ * so 19 characters is enough.
+ */
+ n += 19;
+ 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 += strlen(p);
+ goto expand;
+ }
+ } else
+ n++;
+ }
+ expand:
+ /* step 2: fill the buffer */
+ string = PyString_FromStringAndSize(NULL, n);
+ if (!string)
+ return NULL;
+
+ s = PyString_AsString(string);
+
+ for (f = format; *f; f++) {
+ if (*f == '%') {
+ const char* p = f++;
+ int i, longflag = 0;
+ /* parse the width.precision part (we're only
+ interested in the precision value, if any) */
+ n = 0;
+ while (isdigit(Py_CHARMASK(*f)))
+ n = (n*10) + *f++ - '0';
+ if (*f == '.') {
+ f++;
+ n = 0;
+ while (isdigit(Py_CHARMASK(*f)))
+ n = (n*10) + *f++ - '0';
+ }
+ while (*f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
+ f++;
+ /* handle the long flag, but only for %ld. others
+ can be added when necessary. */
+ if (*f == 'l' && *(f+1) == 'd') {
+ longflag = 1;
+ ++f;
+ }
+
+ switch (*f) {
+ case 'c':
+ *s++ = va_arg(vargs, int);
+ break;
+ case 'd':
+ if (longflag)
+ sprintf(s, "%ld", va_arg(vargs, long));
+ else
+ sprintf(s, "%d", va_arg(vargs, int));
+ s += strlen(s);
+ break;
+ case 'i':
+ sprintf(s, "%i", va_arg(vargs, int));
+ s += strlen(s);
+ break;
+ case 'x':
+ sprintf(s, "%x", va_arg(vargs, int));
+ 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 += i;
+ break;
+ case 'p':
+ sprintf(s, "%p", va_arg(vargs, void*));
+ s += strlen(s);
+ break;
+ case '%':
+ *s++ = '%';
+ break;
+ default:
+ strcpy(s, p);
+ s += strlen(s);
+ goto end;
+ }
+ } else
+ *s++ = *f;
+ }
+
+ end:
+ _PyString_Resize(&string, s - PyString_AsString(string));
+ return string;
+}
+
+PyObject *
+PyString_FromFormat(const char *format, ...)
+{
+ va_list vargs;
+
+#ifdef HAVE_STDARG_PROTOTYPES
+ va_start(vargs, format);
+#else
+ va_start(vargs);
+#endif
+ return PyString_FromFormatV(format, vargs);
+}
+
+
PyObject *PyString_Decode(const char *s,
int size,
const char *encoding,