mirror of
https://github.com/python/cpython.git
synced 2025-07-24 11:44:31 +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
|
@ -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,
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue