Merged revisions 76308 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r76308 | mark.dickinson | 2009-11-15 16:18:58 +0000 (Sun, 15 Nov 2009) | 3 lines

  Issue #7228:  Add '%lld' and '%llu' support to PyFormat_FromString,
  PyFormat_FromStringV and PyErr_Format.
........
This commit is contained in:
Mark Dickinson 2009-11-16 17:00:11 +00:00
parent 260bd3e557
commit 6ce4a9a9f2
9 changed files with 299 additions and 24 deletions

View file

@ -155,6 +155,8 @@ in various ways. There is a separate error indicator for each thread.
.. % The descriptions for %zd and %zu are wrong, but the truth is complicated .. % The descriptions for %zd and %zu are wrong, but the truth is complicated
.. % because not all compilers support the %z width modifier -- we fake it .. % because not all compilers support the %z width modifier -- we fake it
.. % when necessary via interpolating PY_FORMAT_SIZE_T. .. % when necessary via interpolating PY_FORMAT_SIZE_T.
.. % Similar comments apply to the %ll width modifier and
.. % PY_FORMAT_LONG_LONG.
+-------------------+---------------+--------------------------------+ +-------------------+---------------+--------------------------------+
| Format Characters | Type | Comment | | Format Characters | Type | Comment |
@ -176,6 +178,12 @@ in various ways. There is a separate error indicator for each thread.
| :attr:`%lu` | unsigned long | Exactly equivalent to | | :attr:`%lu` | unsigned long | Exactly equivalent to |
| | | ``printf("%lu")``. | | | | ``printf("%lu")``. |
+-------------------+---------------+--------------------------------+ +-------------------+---------------+--------------------------------+
| :attr:`%lld` | long long | Exactly equivalent to |
| | | ``printf("%lld")``. |
+-------------------+---------------+--------------------------------+
| :attr:`%llu` | unsigned | Exactly equivalent to |
| | long long | ``printf("%llu")``. |
+-------------------+---------------+--------------------------------+
| :attr:`%zd` | Py_ssize_t | Exactly equivalent to | | :attr:`%zd` | Py_ssize_t | Exactly equivalent to |
| | | ``printf("%zd")``. | | | | ``printf("%zd")``. |
+-------------------+---------------+--------------------------------+ +-------------------+---------------+--------------------------------+
@ -203,6 +211,14 @@ in various ways. There is a separate error indicator for each thread.
An unrecognized format character causes all the rest of the format string to be 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. copied as-is to the result string, and any extra arguments discarded.
.. note::
The `"%lld"` and `"%llu"` format specifiers are only available
when `HAVE_LONG_LONG` is defined.
.. versionchanged:: 3.2
Support for `"%lld"` and `"%llu"` added.
.. cfunction:: void PyErr_SetNone(PyObject *type) .. cfunction:: void PyErr_SetNone(PyObject *type)

View file

@ -232,9 +232,12 @@ APIs:
types and must correspond exactly to the format characters in the *format* types and must correspond exactly to the format characters in the *format*
string. The following format characters are allowed: string. The following format characters are allowed:
.. % This should be exactly the same as the table in PyErr_Format.
.. % The descriptions for %zd and %zu are wrong, but the truth is complicated .. % The descriptions for %zd and %zu are wrong, but the truth is complicated
.. % because not all compilers support the %z width modifier -- we fake it .. % because not all compilers support the %z width modifier -- we fake it
.. % when necessary via interpolating PY_FORMAT_SIZE_T. .. % when necessary via interpolating PY_FORMAT_SIZE_T.
.. % Similar comments apply to the %ll width modifier and
.. % PY_FORMAT_LONG_LONG.
+-------------------+---------------------+--------------------------------+ +-------------------+---------------------+--------------------------------+
| Format Characters | Type | Comment | | Format Characters | Type | Comment |
@ -256,6 +259,12 @@ APIs:
| :attr:`%lu` | unsigned long | Exactly equivalent to | | :attr:`%lu` | unsigned long | Exactly equivalent to |
| | | ``printf("%lu")``. | | | | ``printf("%lu")``. |
+-------------------+---------------------+--------------------------------+ +-------------------+---------------------+--------------------------------+
| :attr:`%lld` | long long | Exactly equivalent to |
| | | ``printf("%lld")``. |
+-------------------+---------------------+--------------------------------+
| :attr:`%llu` | unsigned long long | Exactly equivalent to |
| | | ``printf("%llu")``. |
+-------------------+---------------------+--------------------------------+
| :attr:`%zd` | Py_ssize_t | Exactly equivalent to | | :attr:`%zd` | Py_ssize_t | Exactly equivalent to |
| | | ``printf("%zd")``. | | | | ``printf("%zd")``. |
+-------------------+---------------------+--------------------------------+ +-------------------+---------------------+--------------------------------+
@ -301,6 +310,15 @@ APIs:
An unrecognized format character causes all the rest of the format string to be 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. copied as-is to the result string, and any extra arguments discarded.
.. note::
The `"%lld"` and `"%llu"` format specifiers are only available
when `HAVE_LONG_LONG` is defined.
.. versionchanged:: 3.2
Support for `"%lld"` and `"%llu"` added.
.. cfunction:: PyObject* PyUnicode_FromFormatV(const char *format, va_list vargs) .. cfunction:: PyObject* PyUnicode_FromFormatV(const char *format, va_list vargs)

View file

@ -219,6 +219,22 @@ typedef Py_intptr_t Py_ssize_t;
# endif # endif
#endif #endif
/* PY_FORMAT_LONG_LONG is analogous to PY_FORMAT_SIZE_T above, but for
* the long long type instead of the size_t type. It's only available
* when HAVE_LONG_LONG is defined. The "high level" Python format
* functions listed above will interpret "lld" or "llu" correctly on
* all platforms.
*/
#ifdef HAVE_LONG_LONG
# ifndef PY_FORMAT_LONG_LONG
# if defined(MS_WIN64) || defined(MS_WINDOWS)
# define PY_FORMAT_LONG_LONG "I64"
# else
# error "This platform's pyconfig.h needs to define PY_FORMAT_LONG_LONG"
# endif
# endif
#endif
/* Py_LOCAL can be used instead of static to get the fastest possible calling /* Py_LOCAL can be used instead of static to get the fastest possible calling
* convention for functions that are local to a given module. * convention for functions that are local to a given module.
* *

View file

@ -110,6 +110,9 @@ Core and Builtins
C-API C-API
----- -----
- Issue #Add '%lld' and '%llu' support to PyString_FromFormat(V)
and PyErr_Format, on machines with HAVE_LONG_LONG defined.
- Issue #6151: Made PyDescr_COMMON conform to standard C (like PyObject_HEAD - Issue #6151: Made PyDescr_COMMON conform to standard C (like PyObject_HEAD
in PEP 3123). The PyDescr_TYPE and PyDescr_NAME macros should be in PEP 3123). The PyDescr_TYPE and PyDescr_NAME macros should be
should used for accessing the d_type and d_name members of structures should used for accessing the d_type and d_name members of structures

View file

@ -1037,6 +1037,12 @@ test_string_from_format(PyObject *self, PyObject *args)
CHECK_1_FORMAT("%lu", unsigned long); CHECK_1_FORMAT("%lu", unsigned long);
CHECK_1_FORMAT("%zu", size_t); CHECK_1_FORMAT("%zu", size_t);
/* "%lld" and "%llu" support added in Python 2.7. */
#ifdef HAVE_LONG_LONG
CHECK_1_FORMAT("%llu", unsigned PY_LONG_LONG);
CHECK_1_FORMAT("%lld", PY_LONG_LONG);
#endif
Py_RETURN_NONE; Py_RETURN_NONE;
Fail: Fail:

View file

@ -667,7 +667,8 @@ PyObject *PyUnicode_FromWideChar(register const wchar_t *w,
#undef CONVERT_WCHAR_TO_SURROGATES #undef CONVERT_WCHAR_TO_SURROGATES
static void static void
makefmt(char *fmt, int longflag, int size_tflag, int zeropad, int width, int precision, char c) makefmt(char *fmt, int longflag, int longlongflag, int size_tflag,
int zeropad, int width, int precision, char c)
{ {
*fmt++ = '%'; *fmt++ = '%';
if (width) { if (width) {
@ -679,6 +680,19 @@ makefmt(char *fmt, int longflag, int size_tflag, int zeropad, int width, int pre
fmt += sprintf(fmt, ".%d", precision); fmt += sprintf(fmt, ".%d", precision);
if (longflag) if (longflag)
*fmt++ = 'l'; *fmt++ = 'l';
else if (longlongflag) {
/* longlongflag should only ever be nonzero on machines with
HAVE_LONG_LONG defined */
#ifdef HAVE_LONG_LONG
char *f = PY_FORMAT_LONG_LONG;
while (*f)
*fmt++ = *f++;
#else
/* we shouldn't ever get here */
assert(0);
*fmt++ = 'l';
#endif
}
else if (size_tflag) { else if (size_tflag) {
char *f = PY_FORMAT_SIZE_T; char *f = PY_FORMAT_SIZE_T;
while (*f) while (*f)
@ -690,6 +704,16 @@ makefmt(char *fmt, int longflag, int size_tflag, int zeropad, int width, int pre
#define appendstring(string) {for (copy = string;*copy;) *s++ = *copy++;} #define appendstring(string) {for (copy = string;*copy;) *s++ = *copy++;}
/* size of fixed-size buffer for formatting single arguments */
#define ITEM_BUFFER_LEN 21
/* maximum number of characters required for output of %ld. 21 characters
allows for 64-bit integers (in decimal) and an optional sign. */
#define MAX_LONG_CHARS 21
/* maximum number of characters required for output of %lld.
We need at most ceil(log10(256)*SIZEOF_LONG_LONG) digits,
plus 1 for the sign. 53/22 is an upper bound for log10(256). */
#define MAX_LONG_LONG_CHARS (2 + (SIZEOF_LONG_LONG*53-1) / 22)
PyObject * PyObject *
PyUnicode_FromFormatV(const char *format, va_list vargs) PyUnicode_FromFormatV(const char *format, va_list vargs)
{ {
@ -705,13 +729,13 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
Py_UNICODE *s; Py_UNICODE *s;
PyObject *string; PyObject *string;
/* used by sprintf */ /* used by sprintf */
char buffer[21]; char buffer[ITEM_BUFFER_LEN+1];
/* use abuffer instead of buffer, if we need more space /* use abuffer instead of buffer, if we need more space
* (which can happen if there's a format specifier with width). */ * (which can happen if there's a format specifier with width). */
char *abuffer = NULL; char *abuffer = NULL;
char *realbuffer; char *realbuffer;
Py_ssize_t abuffersize = 0; Py_ssize_t abuffersize = 0;
char fmt[60]; /* should be enough for %0width.precisionld */ char fmt[61]; /* should be enough for %0width.precisionlld */
const char *copy; const char *copy;
#ifdef VA_LIST_IS_ARRAY #ifdef VA_LIST_IS_ARRAY
@ -754,6 +778,9 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
/* step 3: figure out how large a buffer we need */ /* step 3: figure out how large a buffer we need */
for (f = format; *f; f++) { for (f = format; *f; f++) {
if (*f == '%') { if (*f == '%') {
#ifdef HAVE_LONG_LONG
int longlongflag = 0;
#endif
const char* p = f; const char* p = f;
width = 0; width = 0;
while (ISDIGIT((unsigned)*f)) while (ISDIGIT((unsigned)*f))
@ -764,9 +791,21 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
/* skip the 'l' or 'z' in {%ld, %zd, %lu, %zu} since /* skip the 'l' or 'z' in {%ld, %zd, %lu, %zu} since
* they don't affect the amount of space we reserve. * they don't affect the amount of space we reserve.
*/ */
if ((*f == 'l' || *f == 'z') && if (*f == 'l') {
(f[1] == 'd' || f[1] == 'u')) if (f[1] == 'd' || f[1] == 'u') {
++f;
}
#ifdef HAVE_LONG_LONG
else if (f[1] == 'l' &&
(f[2] == 'd' || f[2] == 'u')) {
longlongflag = 1;
f += 2;
}
#endif
}
else if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) {
++f; ++f;
}
switch (*f) { switch (*f) {
case 'c': case 'c':
@ -777,14 +816,21 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
break; break;
case 'd': case 'u': case 'i': case 'x': case 'd': case 'u': case 'i': case 'x':
(void) va_arg(count, int); (void) va_arg(count, int);
/* 20 bytes is enough to hold a 64-bit #ifdef HAVE_LONG_LONG
integer. Decimal takes the most space. if (longlongflag) {
This isn't enough for octal. if (width < MAX_LONG_LONG_CHARS)
If a width is specified we need more width = MAX_LONG_LONG_CHARS;
(which we allocate later). */ }
if (width < 20) else
width = 20; #endif
/* MAX_LONG_CHARS is enough to hold a 64-bit integer,
including sign. Decimal takes the most space. This
isn't enough for octal. If a width is specified we
need more (which we allocate later). */
if (width < MAX_LONG_CHARS)
width = MAX_LONG_CHARS;
n += width; n += width;
/* XXX should allow for large precision here too. */
if (abuffersize < width) if (abuffersize < width)
abuffersize = width; abuffersize = width;
break; break;
@ -881,8 +927,9 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
n++; n++;
} }
expand: expand:
if (abuffersize > 20) { if (abuffersize > ITEM_BUFFER_LEN) {
abuffer = PyObject_Malloc(abuffersize); /* add 1 for sprintf's trailing null byte */
abuffer = PyObject_Malloc(abuffersize + 1);
if (!abuffer) { if (!abuffer) {
PyErr_NoMemory(); PyErr_NoMemory();
goto fail; goto fail;
@ -906,6 +953,7 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
if (*f == '%') { if (*f == '%') {
const char* p = f++; const char* p = f++;
int longflag = 0; int longflag = 0;
int longlongflag = 0;
int size_tflag = 0; int size_tflag = 0;
zeropad = (*f == '0'); zeropad = (*f == '0');
/* parse the width.precision part */ /* parse the width.precision part */
@ -918,11 +966,19 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
while (ISDIGIT((unsigned)*f)) while (ISDIGIT((unsigned)*f))
precision = (precision*10) + *f++ - '0'; precision = (precision*10) + *f++ - '0';
} }
/* handle the long flag, but only for %ld and %lu. /* Handle %ld, %lu, %lld and %llu. */
others can be added when necessary. */ if (*f == 'l') {
if (*f == 'l' && (f[1] == 'd' || f[1] == 'u')) { if (f[1] == 'd' || f[1] == 'u') {
longflag = 1; longflag = 1;
++f; ++f;
}
#ifdef HAVE_LONG_LONG
else if (f[1] == 'l' &&
(f[2] == 'd' || f[2] == 'u')) {
longlongflag = 1;
f += 2;
}
#endif
} }
/* handle the size_t flag. */ /* handle the size_t flag. */
if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) { if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) {
@ -935,9 +991,14 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
*s++ = va_arg(vargs, int); *s++ = va_arg(vargs, int);
break; break;
case 'd': case 'd':
makefmt(fmt, longflag, size_tflag, zeropad, width, precision, 'd'); makefmt(fmt, longflag, longlongflag, size_tflag, zeropad,
width, precision, 'd');
if (longflag) if (longflag)
sprintf(realbuffer, fmt, va_arg(vargs, long)); sprintf(realbuffer, fmt, va_arg(vargs, long));
#ifdef HAVE_LONG_LONG
else if (longlongflag)
sprintf(realbuffer, fmt, va_arg(vargs, PY_LONG_LONG));
#endif
else if (size_tflag) else if (size_tflag)
sprintf(realbuffer, fmt, va_arg(vargs, Py_ssize_t)); sprintf(realbuffer, fmt, va_arg(vargs, Py_ssize_t));
else else
@ -945,9 +1006,15 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
appendstring(realbuffer); appendstring(realbuffer);
break; break;
case 'u': case 'u':
makefmt(fmt, longflag, size_tflag, zeropad, width, precision, 'u'); makefmt(fmt, longflag, longlongflag, size_tflag, zeropad,
width, precision, 'u');
if (longflag) if (longflag)
sprintf(realbuffer, fmt, va_arg(vargs, unsigned long)); sprintf(realbuffer, fmt, va_arg(vargs, unsigned long));
#ifdef HAVE_LONG_LONG
else if (longlongflag)
sprintf(realbuffer, fmt, va_arg(vargs,
unsigned PY_LONG_LONG));
#endif
else if (size_tflag) else if (size_tflag)
sprintf(realbuffer, fmt, va_arg(vargs, size_t)); sprintf(realbuffer, fmt, va_arg(vargs, size_t));
else else
@ -955,12 +1022,12 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
appendstring(realbuffer); appendstring(realbuffer);
break; break;
case 'i': case 'i':
makefmt(fmt, 0, 0, zeropad, width, precision, 'i'); makefmt(fmt, 0, 0, 0, zeropad, width, precision, 'i');
sprintf(realbuffer, fmt, va_arg(vargs, int)); sprintf(realbuffer, fmt, va_arg(vargs, int));
appendstring(realbuffer); appendstring(realbuffer);
break; break;
case 'x': case 'x':
makefmt(fmt, 0, 0, zeropad, width, precision, 'x'); makefmt(fmt, 0, 0, 0, zeropad, width, precision, 'x');
sprintf(realbuffer, fmt, va_arg(vargs, int)); sprintf(realbuffer, fmt, va_arg(vargs, int));
appendstring(realbuffer); appendstring(realbuffer);
break; break;

100
configure vendored
View file

@ -1,5 +1,5 @@
#! /bin/sh #! /bin/sh
# From configure.in Revision: 76030 . # From configure.in Revision: 76301 .
# Guess values for system-dependent variables and create Makefiles. # Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.61 for python 3.2. # Generated by GNU Autoconf 2.61 for python 3.2.
# #
@ -26314,6 +26314,104 @@ else
echo "${ECHO_T}no" >&6; } echo "${ECHO_T}no" >&6; }
fi fi
if test "$have_long_long" = yes
then
{ echo "$as_me:$LINENO: checking for %lld and %llu printf() format support" >&5
echo $ECHO_N "checking for %lld and %llu printf() format support... $ECHO_C" >&6; }
if test "${ac_cv_have_long_long_format+set}" = set; then
echo $ECHO_N "(cached) $ECHO_C" >&6
else
if test "$cross_compiling" = yes; then
ac_cv_have_long_long_format=no
else
cat >conftest.$ac_ext <<_ACEOF
/* confdefs.h. */
_ACEOF
cat confdefs.h >>conftest.$ac_ext
cat >>conftest.$ac_ext <<_ACEOF
/* end confdefs.h. */
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
int main()
{
char buffer[256];
if (sprintf(buffer, "%lld", (long long)123) < 0)
return 1;
if (strcmp(buffer, "123"))
return 1;
if (sprintf(buffer, "%lld", (long long)-123) < 0)
return 1;
if (strcmp(buffer, "-123"))
return 1;
if (sprintf(buffer, "%llu", (unsigned long long)123) < 0)
return 1;
if (strcmp(buffer, "123"))
return 1;
return 0;
}
_ACEOF
rm -f conftest$ac_exeext
if { (ac_try="$ac_link"
case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_link") 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); } && { ac_try='./conftest$ac_exeext'
{ (case "(($ac_try" in
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
*) ac_try_echo=$ac_try;;
esac
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
(eval "$ac_try") 2>&5
ac_status=$?
echo "$as_me:$LINENO: \$? = $ac_status" >&5
(exit $ac_status); }; }; then
ac_cv_have_long_long_format=yes
else
echo "$as_me: program exited with status $ac_status" >&5
echo "$as_me: failed program was:" >&5
sed 's/^/| /' conftest.$ac_ext >&5
( exit $ac_status )
ac_cv_have_long_long_format=no
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
fi
fi
{ echo "$as_me:$LINENO: result: $ac_cv_have_long_long_format" >&5
echo "${ECHO_T}$ac_cv_have_long_long_format" >&6; }
fi
if test $ac_cv_have_long_long_format = yes
then
cat >>confdefs.h <<\_ACEOF
#define PY_FORMAT_LONG_LONG "ll"
_ACEOF
fi
{ echo "$as_me:$LINENO: checking for %zd printf() format support" >&5 { echo "$as_me:$LINENO: checking for %zd printf() format support" >&5
echo $ECHO_N "checking for %zd printf() format support... $ECHO_C" >&6; } echo $ECHO_N "checking for %zd printf() format support... $ECHO_C" >&6; }
if test "${ac_cv_have_size_t_format+set}" = set; then if test "${ac_cv_have_size_t_format+set}" = set; then

View file

@ -3806,6 +3806,54 @@ else
AC_MSG_RESULT(no) AC_MSG_RESULT(no)
fi fi
if test "$have_long_long" = yes
then
AC_MSG_CHECKING(for %lld and %llu printf() format support)
AC_CACHE_VAL(ac_cv_have_long_long_format,
AC_TRY_RUN([[
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
int main()
{
char buffer[256];
if (sprintf(buffer, "%lld", (long long)123) < 0)
return 1;
if (strcmp(buffer, "123"))
return 1;
if (sprintf(buffer, "%lld", (long long)-123) < 0)
return 1;
if (strcmp(buffer, "-123"))
return 1;
if (sprintf(buffer, "%llu", (unsigned long long)123) < 0)
return 1;
if (strcmp(buffer, "123"))
return 1;
return 0;
}
]], ac_cv_have_long_long_format=yes,
ac_cv_have_long_long_format=no,
ac_cv_have_long_long_format=no)
)
AC_MSG_RESULT($ac_cv_have_long_long_format)
fi
if test $ac_cv_have_long_long_format = yes
then
AC_DEFINE(PY_FORMAT_LONG_LONG, "ll",
[Define to printf format modifier for long long type])
fi
AC_MSG_CHECKING(for %zd printf() format support) AC_MSG_CHECKING(for %zd printf() format support)
AC_CACHE_VAL(ac_cv_have_size_t_format, AC_CACHE_VAL(ac_cv_have_size_t_format,
AC_TRY_RUN([[ AC_TRY_RUN([[

View file

@ -910,6 +910,9 @@
/* Define as the preferred size in bits of long digits */ /* Define as the preferred size in bits of long digits */
#undef PYLONG_BITS_IN_DIGIT #undef PYLONG_BITS_IN_DIGIT
/* Define to printf format modifier for long long type */
#undef PY_FORMAT_LONG_LONG
/* Define to printf format modifier for Py_ssize_t */ /* Define to printf format modifier for Py_ssize_t */
#undef PY_FORMAT_SIZE_T #undef PY_FORMAT_SIZE_T