summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2009-11-15 16:18:58 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2009-11-15 16:18:58 (GMT)
commit82864d1ab101d971e77b73cac9e994fd09cd796b (patch)
tree65335906c1a5f330660bb1f64d698198d50856d3
parentd5b34d4597a7163edf20f831db620b0a4fe57d5d (diff)
downloadcpython-82864d1ab101d971e77b73cac9e994fd09cd796b.zip
cpython-82864d1ab101d971e77b73cac9e994fd09cd796b.tar.gz
cpython-82864d1ab101d971e77b73cac9e994fd09cd796b.tar.bz2
Issue #7228: Add '%lld' and '%llu' support to PyFormat_FromString,
PyFormat_FromStringV and PyErr_Format.
-rw-r--r--Doc/c-api/exceptions.rst16
-rw-r--r--Doc/c-api/string.rst16
-rw-r--r--Include/pyport.h16
-rw-r--r--Misc/NEWS3
-rw-r--r--Modules/_testcapimodule.c6
-rw-r--r--Objects/stringobject.c71
-rwxr-xr-xconfigure100
-rw-r--r--configure.in48
-rw-r--r--pyconfig.h.in3
9 files changed, 266 insertions, 13 deletions
diff --git a/Doc/c-api/exceptions.rst b/Doc/c-api/exceptions.rst
index 4482cd0..ba18af1 100644
--- a/Doc/c-api/exceptions.rst
+++ b/Doc/c-api/exceptions.rst
@@ -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)
diff --git a/Doc/c-api/string.rst b/Doc/c-api/string.rst
index c7d27a3..99fec5d 100644
--- a/Doc/c-api/string.rst
+++ b/Doc/c-api/string.rst
@@ -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)
diff --git a/Include/pyport.h b/Include/pyport.h
index 8310132..aab349e 100644
--- a/Include/pyport.h
+++ b/Include/pyport.h
@@ -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.
*
diff --git a/Misc/NEWS b/Misc/NEWS
index 051bff8..1e406f0 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index fb5cf73..f2181eb 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -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:
diff --git a/Objects/stringobject.c b/Objects/stringobject.c
index b5faf13..4746b3c 100644
--- a/Objects/stringobject.c
+++ b/Objects/stringobject.c
@@ -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);
- /* 20 bytes is enough to hold a 64-bit
- integer. Decimal takes the most space.
- This isn't enough for octal. */
- n += 20;
+#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. */
+ 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')) {
- longflag = 1;
- ++f;
+ /* 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));
diff --git a/configure b/configure
index cd2d7c1..367c879 100755
--- a/configure
+++ b/configure
@@ -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
diff --git a/configure.in b/configure.in
index 18555ee..fe8bb2b 100644
--- a/configure.in
+++ b/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>
diff --git a/pyconfig.h.in b/pyconfig.h.in
index 25187ce..c045593 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -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