Commit 82864d1a authored by Mark Dickinson's avatar Mark Dickinson

Issue #7228: Add '%lld' and '%llu' support to PyFormat_FromString,

PyFormat_FromStringV and PyErr_Format.
parent d5b34d45
...@@ -161,6 +161,8 @@ is a separate error indicator for each thread. ...@@ -161,6 +161,8 @@ 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.
.. % %u, %lu, %zu should have "new in Python 2.5" blurbs. .. % %u, %lu, %zu should have "new in Python 2.5" blurbs.
+-------------------+---------------+--------------------------------+ +-------------------+---------------+--------------------------------+
...@@ -183,6 +185,12 @@ is a separate error indicator for each thread. ...@@ -183,6 +185,12 @@ 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")``. |
+-------------------+---------------+--------------------------------+ +-------------------+---------------+--------------------------------+
...@@ -210,6 +218,14 @@ is a separate error indicator for each thread. ...@@ -210,6 +218,14 @@ 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:: 2.7
Support for `"%lld"` and `"%llu"` added.
.. cfunction:: void PyErr_SetNone(PyObject *type) .. cfunction:: void PyErr_SetNone(PyObject *type)
......
...@@ -78,6 +78,8 @@ called with a non-string parameter. ...@@ -78,6 +78,8 @@ called with a non-string parameter.
.. % 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.
.. % %u, %lu, %zu should have "new in Python 2.5" blurbs. .. % %u, %lu, %zu should have "new in Python 2.5" blurbs.
+-------------------+---------------+--------------------------------+ +-------------------+---------------+--------------------------------+
...@@ -100,6 +102,12 @@ called with a non-string parameter. ...@@ -100,6 +102,12 @@ called with a non-string parameter.
| :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")``. |
+-------------------+---------------+--------------------------------+ +-------------------+---------------+--------------------------------+
...@@ -127,6 +135,14 @@ called with a non-string parameter. ...@@ -127,6 +135,14 @@ called with a non-string parameter.
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:: 2.7
Support for `"%lld"` and `"%llu"` added.
.. cfunction:: PyObject* PyString_FromFormatV(const char *format, va_list vargs) .. cfunction:: PyObject* PyString_FromFormatV(const char *format, va_list vargs)
......
...@@ -229,6 +229,22 @@ typedef Py_intptr_t Py_ssize_t; ...@@ -229,6 +229,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.
* *
......
...@@ -1462,6 +1462,9 @@ Documentation ...@@ -1462,6 +1462,9 @@ Documentation
C-API C-API
----- -----
- Issue #Add '%lld' and '%llu' support to PyString_FromFormat(V)
and PyErr_Format, on machines with HAVE_LONG_LONG defined.
- Add new C-API function PyOS_string_to_double, and deprecated - Add new C-API function PyOS_string_to_double, and deprecated
PyOS_ascii_atof and PyOS_ascii_strtod. PyOS_ascii_atof and PyOS_ascii_strtod.
......
...@@ -954,6 +954,12 @@ test_string_from_format(PyObject *self, PyObject *args) ...@@ -954,6 +954,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:
......
...@@ -189,6 +189,9 @@ PyString_FromFormatV(const char *format, va_list vargs) ...@@ -189,6 +189,9 @@ PyString_FromFormatV(const char *format, va_list vargs)
/* step 1: figure out how large a buffer we need */ /* step 1: 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;
while (*++f && *f != '%' && !isalpha(Py_CHARMASK(*f))) while (*++f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
; ;
...@@ -196,9 +199,21 @@ PyString_FromFormatV(const char *format, va_list vargs) ...@@ -196,9 +199,21 @@ PyString_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':
...@@ -209,10 +224,21 @@ PyString_FromFormatV(const char *format, va_list vargs) ...@@ -209,10 +224,21 @@ PyString_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);
#ifdef HAVE_LONG_LONG
/* Need at most
ceil(log10(256)*SIZEOF_LONG_LONG) digits,
plus 1 for the sign. 53/22 is an upper
bound for log10(256). */
if (longlongflag)
n += 2 + (SIZEOF_LONG_LONG*53-1) / 22;
else
#endif
/* 20 bytes is enough to hold a 64-bit /* 20 bytes is enough to hold a 64-bit
integer. Decimal takes the most space. integer. Decimal takes the most
This isn't enough for octal. */ space. This isn't enough for
octal. */
n += 20; n += 20;
break; break;
case 's': case 's':
s = va_arg(count, char*); s = va_arg(count, char*);
...@@ -255,6 +281,9 @@ PyString_FromFormatV(const char *format, va_list vargs) ...@@ -255,6 +281,9 @@ PyString_FromFormatV(const char *format, va_list vargs)
const char* p = f++; const char* p = f++;
Py_ssize_t i; Py_ssize_t i;
int longflag = 0; int longflag = 0;
#ifdef HAVE_LONG_LONG
int longlongflag = 0;
#endif
int size_tflag = 0; int size_tflag = 0;
/* parse the width.precision part (we're only /* parse the width.precision part (we're only
interested in the precision value, if any) */ interested in the precision value, if any) */
...@@ -269,14 +298,22 @@ PyString_FromFormatV(const char *format, va_list vargs) ...@@ -269,14 +298,22 @@ PyString_FromFormatV(const char *format, va_list vargs)
} }
while (*f && *f != '%' && !isalpha(Py_CHARMASK(*f))) while (*f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
f++; f++;
/* 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')) { else if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) {
size_tflag = 1; size_tflag = 1;
++f; ++f;
} }
...@@ -288,6 +325,11 @@ PyString_FromFormatV(const char *format, va_list vargs) ...@@ -288,6 +325,11 @@ PyString_FromFormatV(const char *format, va_list vargs)
case 'd': case 'd':
if (longflag) if (longflag)
sprintf(s, "%ld", va_arg(vargs, long)); sprintf(s, "%ld", va_arg(vargs, long));
#ifdef HAVE_LONG_LONG
else if (longlongflag)
sprintf(s, "%" PY_FORMAT_LONG_LONG "d",
va_arg(vargs, PY_LONG_LONG));
#endif
else if (size_tflag) else if (size_tflag)
sprintf(s, "%" PY_FORMAT_SIZE_T "d", sprintf(s, "%" PY_FORMAT_SIZE_T "d",
va_arg(vargs, Py_ssize_t)); va_arg(vargs, Py_ssize_t));
...@@ -299,6 +341,11 @@ PyString_FromFormatV(const char *format, va_list vargs) ...@@ -299,6 +341,11 @@ PyString_FromFormatV(const char *format, va_list vargs)
if (longflag) if (longflag)
sprintf(s, "%lu", sprintf(s, "%lu",
va_arg(vargs, unsigned long)); va_arg(vargs, unsigned long));
#ifdef HAVE_LONG_LONG
else if (longlongflag)
sprintf(s, "%" PY_FORMAT_LONG_LONG "u",
va_arg(vargs, PY_LONG_LONG));
#endif
else if (size_tflag) else if (size_tflag)
sprintf(s, "%" PY_FORMAT_SIZE_T "u", sprintf(s, "%" PY_FORMAT_SIZE_T "u",
va_arg(vargs, size_t)); va_arg(vargs, size_t));
......
#! /bin/sh #! /bin/sh
# From configure.in Revision: 76052 . # From configure.in Revision: 76300 .
# 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 2.7. # Generated by GNU Autoconf 2.61 for python 2.7.
# #
...@@ -27014,6 +27014,104 @@ else ...@@ -27014,6 +27014,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
......
...@@ -3952,6 +3952,54 @@ else ...@@ -3952,6 +3952,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_CACHE_CHECK([for %zd printf() format support], ac_cv_have_size_t_format, [dnl AC_CACHE_CHECK([for %zd printf() format support], ac_cv_have_size_t_format, [dnl
AC_TRY_RUN([ AC_TRY_RUN([
#include <stdio.h> #include <stdio.h>
......
...@@ -903,6 +903,9 @@ ...@@ -903,6 +903,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
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment