mirror of
https://github.com/python/cpython.git
synced 2025-10-21 14:12:27 +00:00
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.
This commit is contained in:
parent
16c018d2d2
commit
dadace004b
2 changed files with 159 additions and 0 deletions
|
@ -7,6 +7,8 @@
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Type PyStringObject represents a character string. An extra zero byte is
|
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
|
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_FromStringAndSize(const char *, int);
|
||||||
extern DL_IMPORT(PyObject *) PyString_FromString(const char *);
|
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(int) PyString_Size(PyObject *);
|
||||||
extern DL_IMPORT(char *) PyString_AsString(PyObject *);
|
extern DL_IMPORT(char *) PyString_AsString(PyObject *);
|
||||||
extern DL_IMPORT(void) PyString_Concat(PyObject **, PyObject *);
|
extern DL_IMPORT(void) PyString_Concat(PyObject **, PyObject *);
|
||||||
|
|
|
@ -147,6 +147,161 @@ PyString_FromString(const char *str)
|
||||||
return (PyObject *) op;
|
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,
|
PyObject *PyString_Decode(const char *s,
|
||||||
int size,
|
int size,
|
||||||
const char *encoding,
|
const char *encoding,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue