--- Objects/stringobject2.6b1.c 2008-06-10 14:23:22.000000000 -0700 +++ Objects/stringobject.c 2008-06-22 16:49:25.000000000 -0700 @@ -5,6 +5,11 @@ #include "Python.h" #include +#include /* DBL_DIG, LDBL_DIG */ +#ifndef LDBL_DIG /* no long double? */ +# define LDBL_DIG 0 +#endif + #ifdef COUNT_ALLOCS int null_strings, one_strings; #endif @@ -158,10 +163,11 @@ PyString_FromFormatV(const char *format, va_list vargs) { va_list count; - Py_ssize_t n = 0; + Py_ssize_t i, w, n = 0; const char* f; char *s; PyObject* string; + int longflag, size_tflag; #ifdef VA_LIST_IS_ARRAY Py_MEMCPY(count, vargs, sizeof(va_list)); @@ -175,17 +181,24 @@ /* 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' or 'z' in {%ld, %zd, %lu, %zu} since - * they don't affect the amount of space we reserve. - */ - if ((*f == 'l' || *f == 'z') && - (f[1] == 'd' || f[1] == 'u')) - ++f; - + const char* p = f++; + while (*f && *f != '%' && !isalpha(Py_CHARMASK(*f))) + f++; + longflag = size_tflag = 0; + if (*f == 'l' || *f == 'z') { + if (*f++ == 'l') + longflag = 1; + else + size_tflag = 1; + if (*f != 'd' && *f != 'u') + f--; + } +#if LDBL_DIG > 0 + else if (*f == 'L' && f[1] == 'f') { + longflag = 1; + f++; + } +#endif switch (*f) { case 'c': (void)va_arg(count, int); @@ -194,12 +207,33 @@ n++; break; case 'd': case 'u': case 'i': case 'x': - (void) va_arg(count, int); - /* 20 bytes is enough to hold a 64-bit + if (longflag) + (void) va_arg(count, long); + else if (size_tflag) + (void) va_arg(count, size_t); + else + (void) va_arg(count, int); + /* 20 bytes is enough to hold any 64-bit integer. Decimal takes the most space. This isn't enough for octal. */ n += 20; break; + case 'f': + /* assume %f produces at most (L)DBL_DIG + digits before and after the decimal + point, plus the latter plus a sign */ +#if LDBL_DIG > 0 + if (longflag) { + (void) va_arg(count, long double); + n += LDBL_DIG + 2 + LDBL_DIG; + } + else +#endif + { + (void) va_arg(count, double); + n += DBL_DIG + 2 + DBL_DIG; + } + break; case 's': s = va_arg(count, char*); n += strlen(s); @@ -239,34 +273,36 @@ for (f = format; *f; f++) { if (*f == '%') { const char* p = f++; - Py_ssize_t i; - int longflag = 0; - int size_tflag = 0; - /* parse the width.precision part (we're only - interested in the precision value, if any) */ - n = 0; + int precision = 0; + /* parse 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'; + precision = 1; } + /* skip any non-alpha flags */ while (*f && *f != '%' && !isalpha(Py_CHARMASK(*f))) f++; - /* handle the long flag, but only for %ld and %lu. - others can be added when necessary. */ - if (*f == 'l' && (f[1] == 'd' || f[1] == 'u')) { - longflag = 1; - ++f; + /* handle the long flag and size_t flags */ + longflag = size_tflag = 0; + if (*f == 'l' || *f == 'z') { + if (*f++ == 'l') + longflag = 1; + else + size_tflag = 1; + if (*f != 'd' && *f != 'u') + f--; } - /* handle the size_t flag. */ - if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) { - size_tflag = 1; - ++f; +#if LDBL_DIG > 0 + else if (*f == 'L' && f[1] == 'f') { + longflag = 1; + f++; } - +#endif switch (*f) { case 'c': *s++ = va_arg(vargs, int); @@ -284,13 +320,39 @@ case 'u': if (longflag) sprintf(s, "%lu", - va_arg(vargs, unsigned long)); + va_arg(vargs, unsigned long)); else if (size_tflag) sprintf(s, "%" PY_FORMAT_SIZE_T "u", va_arg(vargs, size_t)); else sprintf(s, "%u", - va_arg(vargs, unsigned int)); + va_arg(vargs, unsigned int)); + s += strlen(s); + break; + case 'f': + if (precision) { +#if LDBL_DIG > 0 + if (longflag) { + if (n > LDBL_DIG) + n = LDBL_DIG; + sprintf(s, "%.*Lf", (int)n, + va_arg(vargs, long double)); + } + else +#endif + { + if (n > DBL_DIG) + n = DBL_DIG; + sprintf(s, "%.*f", (int)n, + va_arg(vargs, double)); + } + } +#if LDBL_DIG > 0 + else if (longflag) + sprintf(s, "%Lf", va_arg(vargs, long double)); +#endif + else + sprintf(s, "%f", va_arg(vargs, double)); s += strlen(s); break; case 'i': @@ -306,6 +368,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 +398,7 @@ } end: - _PyString_Resize(&string, s - PyString_AS_STRING(string)); + _PyString_Resize(&string, (Py_ssize_t)(s - PyString_AS_STRING(string))); return string; }