]> granicus.if.org Git - python/commitdiff
Issue #7228: Add '%lld' and '%llu' support to PyFormat_FromString,
authorMark Dickinson <dickinsm@gmail.com>
Sun, 15 Nov 2009 16:18:58 +0000 (16:18 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Sun, 15 Nov 2009 16:18:58 +0000 (16:18 +0000)
PyFormat_FromStringV and PyErr_Format.

Doc/c-api/exceptions.rst
Doc/c-api/string.rst
Include/pyport.h
Misc/NEWS
Modules/_testcapimodule.c
Objects/stringobject.c
configure
configure.in
pyconfig.h.in

index 4482cd0bd72a1530894567499d47fcd776374810..ba18af161abdaf144e808da19e88d5df5cc40422 100644 (file)
@@ -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)
 
index c7d27a31c79054aac33cdfb5ebb04a8140653f76..99fec5d0cdb87707439566fde137a1b2566d8e77 100644 (file)
@@ -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)
 
index 83101323754fcf2c3bd77529b759b5164679663c..aab349e53ef01d99fc74cdc0e8efe2403fd202d6 100644 (file)
@@ -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.
  *
index 051bff81a66f168c8c4b1312d7011dd03693d7e7..1e406f0d61a5e2cb530b707f6c2a465c09e47032 100644 (file)
--- 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.
 
index fb5cf732e2bd2fff7936899a3c119f3bba4851fb..f2181ebce5ed6fede069acd0c85276f02c5f1aaf 100644 (file)
@@ -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:
index b5faf13fdaec5c099a6aba1c7513d743325e4793..4746b3c48b5ba12d11b702b118197e9bf6d172c1 100644 (file)
@@ -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));
index cd2d7c189802a78fc7e58822d9f650665ccc65fe..367c87996b016457ffdcf38791f27d274047a031 100755 (executable)
--- 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
index 18555ee6898f35a3fb2a7110fb6eb3d893b26446..fe8bb2bd6ff8c7f0598d691db66623b3a1967701 100644 (file)
@@ -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>
index 25187ced0bd7d953312a074426ca2585003aa1b4..c0455933fc50a393d56d0a90e7a9b4e51a7ffdf2 100644 (file)
 /* 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