--- Objects/stringobject2.6b1.c 2008-06-10 14:23:22.000000000 -0700 +++ Objects/stringobject.c 2008-06-23 18:35:38.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,44 +181,71 @@ /* 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 != 'x') + 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); + (void) va_arg(count, int); /* fall through... */ case '%': n++; break; + case 'p': /* like %#x */ +#if SIZEOF_VOID_P == SIZEOF_SIZE_T + size_tflag = 1; +#elif SIZEOF_VOID_P == SIZEOF_LONG + longflag = 1; +#elif SIZEOF_VOID_P != SIZEOF_INT +# error "unsupported SIZEOF_VOID_P value" +#endif /* fall through... */ 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); break; - case 'p': - (void) va_arg(count, int); - /* maximum 64-bit pointer representation: - * 0xffffffffffffffff - * so 19 characters is enough. - * XXX I count 18 -- what's the extra for? - */ - n += 19; - break; default: /* if we stumble upon an unknown formatting code, copy the rest of @@ -239,34 +272,38 @@ 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 hashflag = 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; + if (*f++ == '#') + hashflag = 1; + /* 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 != 'x') + 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,21 +321,69 @@ 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 'i': - sprintf(s, "%i", va_arg(vargs, int)); + case 'p': /* like %#x */ +#if SIZEOF_VOID_P == SIZEOF_SIZE_T + hashflag = size_tflag = 1; +#elif SIZEOF_VOID_P == SIZEOF_LONG + hashflag = longflag = 1; +#elif SIZEOF_VOID_P == SIZEOF_INT + hashflag = 1; +#else +# error "unsupported SIZEOF_VOID_P value" +#endif /* fall through... */ + case 'x': + if (hashflag) { + *s++ = '0'; + *s++ = 'x'; + } + if (longflag) + sprintf(s, "%lx", + va_arg(vargs, unsigned long)); + else if (size_tflag) + sprintf(s, "%" PY_FORMAT_SIZE_T "x", + va_arg(vargs, size_t)); + else + sprintf(s, "%x", + va_arg(vargs, unsigned int)); s += strlen(s); break; - case 'x': - sprintf(s, "%x", va_arg(vargs, int)); + 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': + sprintf(s, "%i", va_arg(vargs, int)); s += strlen(s); break; case 's': @@ -306,21 +391,11 @@ 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; - case 'p': - sprintf(s, "%p", va_arg(vargs, void*)); - /* %p is ill-defined: ensure leading 0x. */ - if (s[1] == 'X') - s[1] = 'x'; - else if (s[1] != 'x') { - memmove(s+2, s, strlen(s)+1); - s[0] = '0'; - s[1] = 'x'; - } - s += strlen(s); - break; case '%': *s++ = '%'; break; @@ -334,7 +409,7 @@ } end: - _PyString_Resize(&string, s - PyString_AS_STRING(string)); + _PyString_Resize(&string, (Py_ssize_t)(s - PyString_AS_STRING(string))); return string; } --- Modules/_testcapimodule2.6b1.c 2008-06-22 22:47:04.000000000 -0700 +++ Modules/_testcapimodule.c 2008-06-24 08:15:51.000000000 -0700 @@ -696,27 +696,45 @@ test_string_from_format(PyObject *self, PyObject *args) { PyObject *result; - char *msg; + char msg[256], *got; -#define CHECK_1_FORMAT(FORMAT, TYPE) \ - result = PyString_FromFormat(FORMAT, (TYPE)1); \ - if (result == NULL) \ - return NULL; \ - if (strcmp(PyString_AsString(result), "1")) { \ - msg = FORMAT " failed at 1"; \ - goto Fail; \ - } \ +#define CHECK_FORMAT(FORMAT, TYPE, VALUE, EXPECTED) \ + result = PyString_FromFormat(FORMAT, (TYPE)VALUE); \ + if (result == NULL) \ + return NULL; \ + got = PyString_AsString(result); \ + if (strcmp(got, EXPECTED)) { \ + sprintf(msg, "%s failed: got %s, expected %s", \ + FORMAT, got, EXPECTED); \ + goto Fail; \ + } \ Py_DECREF(result) - CHECK_1_FORMAT("%d", int); - CHECK_1_FORMAT("%ld", long); + CHECK_FORMAT("%d", int, 1, "1"); + CHECK_FORMAT("%ld", long, -12, "-12"); /* The z width modifier was added in Python 2.5. */ - CHECK_1_FORMAT("%zd", Py_ssize_t); + CHECK_FORMAT("%zd", Py_ssize_t, 123, "123"); /* The u type code was added in Python 2.5. */ - CHECK_1_FORMAT("%u", unsigned int); - CHECK_1_FORMAT("%lu", unsigned long); - CHECK_1_FORMAT("%zu", size_t); + CHECK_FORMAT("%u", unsigned int, 12345, "12345"); + CHECK_FORMAT("%lu", unsigned long, 13579, "13579"); + CHECK_FORMAT("%zu", size_t, 2468, "2468"); + + /* The x type code was added in Python 2.5. */ + CHECK_FORMAT("%x", unsigned int, 0xF, "f"); + CHECK_FORMAT("%lx", unsigned long, 0xFF, "ff"); + CHECK_FORMAT("%zx", size_t, 0xFFF, "fff"); + + CHECK_FORMAT("%#x", int, 0xF, "0xf"); + CHECK_FORMAT("%#lx", long, 0xFF, "0xff"); + CHECK_FORMAT("%#zx", size_t, 0xFFF, "0xfff"); + + CHECK_FORMAT("%p", void*, 0x4Beef, "0x4beef"); + + /* The f type code was added in Python 2.7. */ + CHECK_FORMAT("%f", double, 12345.67890, "12345.678900"); + CHECK_FORMAT("%.5f", double, 12345.67890, "12345.67890"); + CHECK_FORMAT("%.2f", double, 12345.67890, "12345.68"); Py_RETURN_NONE; @@ -724,6 +742,7 @@ Py_XDECREF(result); return raiseTestError("test_string_from_format", msg); +#undef CHECK_FORMAT #undef CHECK_1_FORMAT } --- Doc/c-api/exceptions2.6b1.rst 2008-04-26 19:28:02.000000000 -0700 +++ Doc/c-api/exceptions.rst 2008-06-24 08:29:21.000000000 -0700 @@ -154,50 +154,55 @@ .. % because not all compilers support the %z width modifier -- we fake it .. % when necessary via interpolating PY_FORMAT_SIZE_T. .. % %u, %lu, %zu should have "new in Python 2.5" blurbs. - - +-------------------+---------------+--------------------------------+ - | Format Characters | Type | Comment | - +===================+===============+================================+ - | :attr:`%%` | *n/a* | The literal % character. | - +-------------------+---------------+--------------------------------+ - | :attr:`%c` | int | A single character, | - | | | represented as an C int. | - +-------------------+---------------+--------------------------------+ - | :attr:`%d` | int | Exactly equivalent to | - | | | ``printf("%d")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%u` | unsigned int | Exactly equivalent to | - | | | ``printf("%u")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%ld` | long | Exactly equivalent to | - | | | ``printf("%ld")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%lu` | unsigned long | Exactly equivalent to | - | | | ``printf("%lu")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%zd` | Py_ssize_t | Exactly equivalent to | - | | | ``printf("%zd")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%zu` | size_t | Exactly equivalent to | - | | | ``printf("%zu")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%i` | int | Exactly equivalent to | - | | | ``printf("%i")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%x` | int | Exactly equivalent to | - | | | ``printf("%x")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%s` | char\* | A null-terminated C character | - | | | array. | - +-------------------+---------------+--------------------------------+ - | :attr:`%p` | void\* | The hex representation of a C | - | | | pointer. Mostly equivalent to | - | | | ``printf("%p")`` except that | - | | | it is guaranteed to start with | - | | | the literal ``0x`` regardless | - | | | of what the platform's | - | | | ``printf`` yields. | - +-------------------+---------------+--------------------------------+ + .. % %#x, %#lx, %#zx prepends 0x to the hex character string including 0x0. + .. % %Lf is only available on platforms supporting C type long double. + .. % a precision specification is supported for the %f, %Lf and %s formats. + + +-------------------+---------------+---------------------------+ + | Format Characters | Type | Comment | + +===================+===============+===========================+ + | :attr:`%%` | *n/a* | The literal % character. | + +-------------------+---------------+---------------------------+ + | :attr:`%c` | int | A single character, | + | | | represented as an C int. | + +-------------------+---------------+---------------------------+ + | :attr:`%d` | int | Exactly equivalent to | + | | | ``printf("%d")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%u` | unsigned int | Exactly equivalent to | + | | | ``printf("%u")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%ld` | long | Exactly equivalent to | + | | | ``printf("%ld")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%lu` | unsigned long | Exactly equivalent to | + | | | ``printf("%lu")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%zd` | Py_ssize_t | Exactly equivalent to | + | | | ``printf("%zd")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%zu` | size_t | Exactly equivalent to | + | | | ``printf("%zu")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%i` | int | Exactly equivalent to | + | | | ``printf("%i")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%x` | int | Exactly equivalent to | + | | | ``printf("%x")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%f` | double | Exactly equivalent to | + | | | ``printf("%f")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%Lf` | long double | Exactly equivalent to | + | | | ``printf("%Lf")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%s` | char\* | A null-terminated C | + | | | character array. | + +-------------------+---------------+---------------------------+ + | :attr:`%p` | void\* | The hex representation of | + | | | a C pointer equivalent to | + | | | ``printf("%#x")``. | + +-------------------+---------------+---------------------------+ An unrecognized format character causes all the rest of the format string to be copied as-is to the result string, and any extra arguments discarded. --- Doc/c-api/string2.6b1.rst 2008-06-22 22:03:10.000000000 -0700 +++ Doc/c-api/string.rst 2008-06-24 08:29:27.000000000 -0700 @@ -73,50 +73,55 @@ .. % because not all compilers support the %z width modifier -- we fake it .. % when necessary via interpolating PY_FORMAT_SIZE_T. .. % %u, %lu, %zu should have "new in Python 2.5" blurbs. - - +-------------------+---------------+--------------------------------+ - | Format Characters | Type | Comment | - +===================+===============+================================+ - | :attr:`%%` | *n/a* | The literal % character. | - +-------------------+---------------+--------------------------------+ - | :attr:`%c` | int | A single character, | - | | | represented as an C int. | - +-------------------+---------------+--------------------------------+ - | :attr:`%d` | int | Exactly equivalent to | - | | | ``printf("%d")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%u` | unsigned int | Exactly equivalent to | - | | | ``printf("%u")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%ld` | long | Exactly equivalent to | - | | | ``printf("%ld")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%lu` | unsigned long | Exactly equivalent to | - | | | ``printf("%lu")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%zd` | Py_ssize_t | Exactly equivalent to | - | | | ``printf("%zd")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%zu` | size_t | Exactly equivalent to | - | | | ``printf("%zu")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%i` | int | Exactly equivalent to | - | | | ``printf("%i")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%x` | int | Exactly equivalent to | - | | | ``printf("%x")``. | - +-------------------+---------------+--------------------------------+ - | :attr:`%s` | char\* | A null-terminated C character | - | | | array. | - +-------------------+---------------+--------------------------------+ - | :attr:`%p` | void\* | The hex representation of a C | - | | | pointer. Mostly equivalent to | - | | | ``printf("%p")`` except that | - | | | it is guaranteed to start with | - | | | the literal ``0x`` regardless | - | | | of what the platform's | - | | | ``printf`` yields. | - +-------------------+---------------+--------------------------------+ + .. % %#x, %#lx, %#zx prepends 0x to the hex character string including 0x0. + .. % %Lf is only available on platforms supporting C type long double. + .. % a precision specification is supported for the %f, %Lf and %s formats. + + +-------------------+---------------+---------------------------+ + | Format Characters | Type | Comment | + +===================+===============+===========================+ + | :attr:`%%` | *n/a* | The literal % character. | + +-------------------+---------------+---------------------------+ + | :attr:`%c` | int | A single character, | + | | | represented as an C int. | + +-------------------+---------------+---------------------------+ + | :attr:`%d` | int | Exactly equivalent to | + | | | ``printf("%d")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%u` | unsigned int | Exactly equivalent to | + | | | ``printf("%u")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%ld` | long | Exactly equivalent to | + | | | ``printf("%ld")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%lu` | unsigned long | Exactly equivalent to | + | | | ``printf("%lu")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%zd` | Py_ssize_t | Exactly equivalent to | + | | | ``printf("%zd")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%zu` | size_t | Exactly equivalent to | + | | | ``printf("%zu")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%i` | int | Exactly equivalent to | + | | | ``printf("%i")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%x` | int | Exactly equivalent to | + | | | ``printf("%x")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%f` | double | Exactly equivalent to | + | | | ``printf("%f")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%Lf` | long double | Exactly equivalent to | + | | | ``printf("%Lf")``. | + +-------------------+---------------+---------------------------+ + | :attr:`%s` | char\* | A null-terminated C | + | | | character array. | + +-------------------+---------------+---------------------------+ + | :attr:`%p` | void\* | The hex representation of | + | | | a C pointer equivalent to | + | | | ``printf("%#x")``. | + +-------------------+---------------+---------------------------+ An unrecognized format character causes all the rest of the format string to be copied as-is to the result string, and any extra arguments discarded.