--- Objects/stringobject2.6b1.c 2008-06-10 14:23:22.000000000 -0700 +++ Objects/stringobject.c 2008-06-21 16:09:50.000000000 -0700 @@ -4,6 +4,7 @@ #include "Python.h" #include +#include /* DBL_DIG */ #ifdef COUNT_ALLOCS int null_strings, one_strings; @@ -158,7 +159,7 @@ PyString_FromFormatV(const char *format, va_list vargs) { va_list count; - Py_ssize_t n = 0; + Py_ssize_t m = 0; const char* f; char *s; PyObject* string; @@ -191,18 +192,25 @@ (void)va_arg(count, int); /* fall through... */ case '%': - n++; + m++; break; case 'd': case 'u': case 'i': case 'x': (void) va_arg(count, int); /* 20 bytes is enough to hold a 64-bit integer. Decimal takes the most space. This isn't enough for octal. */ - n += 20; + m += 20; + break; + case 'f': + (void) va_arg(count, double); + /* assume %f produces at most DBL_DIG + digits before and after the decimal + point, plus the latter plus a sign */ + m += DBL_DIG + 2 + DBL_DIG; break; case 's': s = va_arg(count, char*); - n += strlen(s); + m += strlen(s); break; case 'p': (void) va_arg(count, int); @@ -211,7 +219,7 @@ * so 19 characters is enough. * XXX I count 18 -- what's the extra for? */ - n += 19; + m += 19; break; default: /* if we stumble upon an unknown @@ -220,17 +228,17 @@ string. (we cannot just skip the code, since there's no way to know what's in the argument list) */ - n += strlen(p); + m += strlen(p); goto expand; } } else - n++; + m++; } expand: /* step 2: fill the buffer */ /* Since we've analyzed how much space we need for the worst case, use sprintf directly instead of the slower PyOS_snprintf. */ - string = PyString_FromStringAndSize(NULL, n); + string = PyString_FromStringAndSize(NULL, m + 1); if (!string) return NULL; @@ -239,17 +247,15 @@ for (f = format; *f; f++) { if (*f == '%') { const char* p = f++; - Py_ssize_t i; + Py_ssize_t i, w, n; int longflag = 0; int size_tflag = 0; - /* parse the width.precision part (we're only - interested in the precision value, if any) */ - n = 0; + /* parse the width.precision, if any */ + w = n = 0; while (isdigit(Py_CHARMASK(*f))) - n = (n*10) + *f++ - '0'; + w = (w*10) + *f++ - '0'; if (*f == '.') { f++; - n = 0; while (isdigit(Py_CHARMASK(*f))) n = (n*10) + *f++ - '0'; } @@ -293,6 +299,19 @@ va_arg(vargs, unsigned int)); s += strlen(s); break; + case 'f': + if (n > 0) { + i = m - 2 - (Py_ssize_t)(s - PyString_AsString(string)); + if (n > i) + n = i; + if (n > DBL_DIG) + n = DBL_DIG; + sprintf(s, "%.*f", (int)n, va_arg(vargs, double)); + } + else + sprintf(s, "%f", va_arg(vargs, double)); + s += strlen(s); + break; case 'i': sprintf(s, "%i", va_arg(vargs, int)); s += strlen(s); @@ -306,6 +325,8 @@ i = strlen(p); if (n > 0 && i > n) i = n; + else if (w > 0 && i > w) + i = w; Py_MEMCPY(s, p, i); s += i; break; @@ -334,7 +355,7 @@ } end: - _PyString_Resize(&string, s - PyString_AS_STRING(string)); + _PyString_Resize(&string, (Py_ssize_t)(s - PyString_AS_STRING(string))); return string; }