mirror of https://github.com/python/cpython
Issue #7228: Add '%lld' and '%llu' support to PyFormat_FromString,
PyFormat_FromStringV and PyErr_Format.
This commit is contained in:
parent
d5b34d4597
commit
82864d1ab1
|
@ -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
|
||||
.. % because not all compilers support the %z width modifier -- we fake it
|
||||
.. % 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.
|
||||
|
||||
+-------------------+---------------+--------------------------------+
|
||||
|
@ -183,6 +185,12 @@ is a separate error indicator for each thread.
|
|||
| :attr:`%lu` | unsigned long | Exactly equivalent to |
|
||||
| | | ``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 |
|
||||
| | | ``printf("%zd")``. |
|
||||
+-------------------+---------------+--------------------------------+
|
||||
|
@ -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
|
||||
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)
|
||||
|
||||
|
|
|
@ -78,6 +78,8 @@ called with a non-string parameter.
|
|||
.. % 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
|
||||
.. % 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.
|
||||
|
||||
+-------------------+---------------+--------------------------------+
|
||||
|
@ -100,6 +102,12 @@ called with a non-string parameter.
|
|||
| :attr:`%lu` | unsigned long | Exactly equivalent to |
|
||||
| | | ``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 |
|
||||
| | | ``printf("%zd")``. |
|
||||
+-------------------+---------------+--------------------------------+
|
||||
|
@ -127,6 +135,14 @@ called with a non-string parameter.
|
|||
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.
|
||||
|
||||
.. 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)
|
||||
|
||||
|
|
|
@ -229,6 +229,22 @@ typedef Py_intptr_t Py_ssize_t;
|
|||
# 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
|
||||
* convention for functions that are local to a given module.
|
||||
*
|
||||
|
|
|
@ -1462,6 +1462,9 @@ Documentation
|
|||
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
|
||||
PyOS_ascii_atof and PyOS_ascii_strtod.
|
||||
|
||||
|
|
|
@ -954,6 +954,12 @@ test_string_from_format(PyObject *self, PyObject *args)
|
|||
CHECK_1_FORMAT("%lu", unsigned long);
|
||||
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;
|
||||
|
||||
Fail:
|
||||
|
|
|
@ -189,6 +189,9 @@ PyString_FromFormatV(const char *format, va_list vargs)
|
|||
/* step 1: figure out how large a buffer we need */
|
||||
for (f = format; *f; f++) {
|
||||
if (*f == '%') {
|
||||
#ifdef HAVE_LONG_LONG
|
||||
int longlongflag = 0;
|
||||
#endif
|
||||
const char* p = f;
|
||||
while (*++f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
|
||||
;
|
||||
|
@ -196,9 +199,21 @@ PyString_FromFormatV(const char *format, va_list vargs)
|
|||
/* 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'))
|
||||
if (*f == 'l') {
|
||||
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;
|
||||
}
|
||||
|
||||
switch (*f) {
|
||||
case 'c':
|
||||
|
@ -209,10 +224,21 @@ PyString_FromFormatV(const char *format, va_list vargs)
|
|||
break;
|
||||
case 'd': case 'u': case 'i': case 'x':
|
||||
(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
|
||||
integer. Decimal takes the most space.
|
||||
This isn't enough for octal. */
|
||||
integer. Decimal takes the most
|
||||
space. This isn't enough for
|
||||
octal. */
|
||||
n += 20;
|
||||
|
||||
break;
|
||||
case 's':
|
||||
s = va_arg(count, char*);
|
||||
|
@ -255,6 +281,9 @@ PyString_FromFormatV(const char *format, va_list vargs)
|
|||
const char* p = f++;
|
||||
Py_ssize_t i;
|
||||
int longflag = 0;
|
||||
#ifdef HAVE_LONG_LONG
|
||||
int longlongflag = 0;
|
||||
#endif
|
||||
int size_tflag = 0;
|
||||
/* parse the width.precision part (we're only
|
||||
interested in the precision value, if any) */
|
||||
|
@ -269,14 +298,22 @@ PyString_FromFormatV(const char *format, va_list vargs)
|
|||
}
|
||||
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')) {
|
||||
/* Handle %ld, %lu, %lld and %llu. */
|
||||
if (*f == 'l') {
|
||||
if (f[1] == 'd' || f[1] == 'u') {
|
||||
longflag = 1;
|
||||
++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. */
|
||||
if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) {
|
||||
else if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) {
|
||||
size_tflag = 1;
|
||||
++f;
|
||||
}
|
||||
|
@ -288,6 +325,11 @@ PyString_FromFormatV(const char *format, va_list vargs)
|
|||
case 'd':
|
||||
if (longflag)
|
||||
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)
|
||||
sprintf(s, "%" PY_FORMAT_SIZE_T "d",
|
||||
va_arg(vargs, Py_ssize_t));
|
||||
|
@ -299,6 +341,11 @@ PyString_FromFormatV(const char *format, va_list vargs)
|
|||
if (longflag)
|
||||
sprintf(s, "%lu",
|
||||
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)
|
||||
sprintf(s, "%" PY_FORMAT_SIZE_T "u",
|
||||
va_arg(vargs, size_t));
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#! /bin/sh
|
||||
# From configure.in Revision: 76052 .
|
||||
# From configure.in Revision: 76300 .
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.61 for python 2.7.
|
||||
#
|
||||
|
@ -27014,6 +27014,104 @@ else
|
|||
echo "${ECHO_T}no" >&6; }
|
||||
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 $ECHO_N "checking for %zd printf() format support... $ECHO_C" >&6; }
|
||||
if test "${ac_cv_have_size_t_format+set}" = set; then
|
||||
|
|
48
configure.in
48
configure.in
|
@ -3952,6 +3952,54 @@ else
|
|||
AC_MSG_RESULT(no)
|
||||
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_TRY_RUN([
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -903,6 +903,9 @@
|
|||
/* Define as the preferred size in bits of long digits */
|
||||
#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 */
|
||||
#undef PY_FORMAT_SIZE_T
|
||||
|
||||
|
|
Loading…
Reference in New Issue