]> granicus.if.org Git - python/commitdiff
Merged revisions 76308 via svnmerge from
authorMark Dickinson <dickinsm@gmail.com>
Mon, 16 Nov 2009 17:00:11 +0000 (17:00 +0000)
committerMark Dickinson <dickinsm@gmail.com>
Mon, 16 Nov 2009 17:00:11 +0000 (17:00 +0000)
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.
........

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

index 819e22e02c8bb4aa7a180d867d28a3caf4946512..25f7c1152f23ef8a74f0270e80ddc02bcbc7dc7d 100644 (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
    .. % 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.
 
    +-------------------+---------------+--------------------------------+
    | 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          |
    |                   |               | ``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")``.             |
    +-------------------+---------------+--------------------------------+
@@ -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
    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)
 
index 4c0d6a462d4b9cbe597b8a32cbbeb05fb4675bc9..0455ae58968394f58dd345f880e78658a8a60f44 100644 (file)
@@ -232,9 +232,12 @@ APIs:
    types and must correspond exactly to the format characters in the *format*
    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
    .. % 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.
 
    +-------------------+---------------------+--------------------------------+
    | Format Characters | Type                | Comment                        |
@@ -256,6 +259,12 @@ APIs:
    | :attr:`%lu`       | unsigned long       | Exactly equivalent to          |
    |                   |                     | ``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          |
    |                   |                     | ``printf("%zd")``.             |
    +-------------------+---------------------+--------------------------------+
@@ -301,6 +310,15 @@ APIs:
    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:: 3.2
+      Support for `"%lld"` and `"%llu"` added.
+
+
 
 .. cfunction:: PyObject* PyUnicode_FromFormatV(const char *format, va_list vargs)
 
index be15fe1b6c3b02779ff963398286cbf6ff6a5295..1adb5f0d02004e90d3e82f4f10646f69e7642175 100644 (file)
@@ -219,6 +219,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 289a64c5a542fc37a56303800aa2db0ce4202deb..42d1d46e4027e5fb05c9dafffdd3e2ad478bb0b9 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -110,6 +110,9 @@ Core and Builtins
 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
   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
index 7e0e95c0b9f806983c2f936d1a8f44243b2cc380..0ed211150846d25d9e5aca622d5cef17bf2f1baa 100644 (file)
@@ -1037,6 +1037,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 cdb739a3d5db1d36867254fe0da8e653312cfaf9..9c0be9b23ca7569fd6ec3e965b9d2504a7c3e424 100644 (file)
@@ -667,7 +667,8 @@ PyObject *PyUnicode_FromWideChar(register const wchar_t *w,
 #undef CONVERT_WCHAR_TO_SURROGATES
 
 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++ = '%';
     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);
     if (longflag)
         *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) {
         char *f = PY_FORMAT_SIZE_T;
         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++;}
 
+/* 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 *
 PyUnicode_FromFormatV(const char *format, va_list vargs)
 {
@@ -705,13 +729,13 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
     Py_UNICODE *s;
     PyObject *string;
     /* used by sprintf */
-    char buffer[21];
+    char buffer[ITEM_BUFFER_LEN+1];
     /* use abuffer instead of buffer, if we need more space
      * (which can happen if there's a format specifier with width). */
     char *abuffer = NULL;
     char *realbuffer;
     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;
 
 #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 */
     for (f = format; *f; f++) {
         if (*f == '%') {
+#ifdef HAVE_LONG_LONG
+            int longlongflag = 0;
+#endif
             const char* p = f;
             width = 0;
             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
              * 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':
@@ -777,14 +816,21 @@ PyUnicode_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.
-                   If a width is specified we need more
-                   (which we allocate later). */
-                if (width < 20)
-                    width = 20;
+#ifdef HAVE_LONG_LONG
+                if (longlongflag) {
+                    if (width < MAX_LONG_LONG_CHARS)
+                        width = MAX_LONG_LONG_CHARS;
+                }
+                else
+#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;
+                /* XXX should allow for large precision here too. */
                 if (abuffersize < width)
                     abuffersize = width;
                 break;
@@ -881,8 +927,9 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
             n++;
     }
   expand:
-    if (abuffersize > 20) {
-        abuffer = PyObject_Malloc(abuffersize);
+    if (abuffersize > ITEM_BUFFER_LEN) {
+        /* add 1 for sprintf's trailing null byte */
+        abuffer = PyObject_Malloc(abuffersize + 1);
         if (!abuffer) {
             PyErr_NoMemory();
             goto fail;
@@ -906,6 +953,7 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
         if (*f == '%') {
             const char* p = f++;
             int longflag = 0;
+            int longlongflag = 0;
             int size_tflag = 0;
             zeropad = (*f == '0');
             /* parse the width.precision part */
@@ -918,11 +966,19 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
                 while (ISDIGIT((unsigned)*f))
                     precision = (precision*10) + *f++ - '0';
             }
-            /* 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')) {
@@ -935,9 +991,14 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
                 *s++ = va_arg(vargs, int);
                 break;
             case 'd':
-                makefmt(fmt, longflag, size_tflag, zeropad, width, precision, 'd');
+                makefmt(fmt, longflag, longlongflag, size_tflag, zeropad,
+                        width, precision, 'd');
                 if (longflag)
                     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)
                     sprintf(realbuffer, fmt, va_arg(vargs, Py_ssize_t));
                 else
@@ -945,9 +1006,15 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
                 appendstring(realbuffer);
                 break;
             case 'u':
-                makefmt(fmt, longflag, size_tflag, zeropad, width, precision, 'u');
+                makefmt(fmt, longflag, longlongflag, size_tflag, zeropad,
+                        width, precision, 'u');
                 if (longflag)
                     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)
                     sprintf(realbuffer, fmt, va_arg(vargs, size_t));
                 else
@@ -955,12 +1022,12 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
                 appendstring(realbuffer);
                 break;
             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));
                 appendstring(realbuffer);
                 break;
             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));
                 appendstring(realbuffer);
                 break;
index 188435b2feb0eb7bf2698086e8edd42b823f4c4e..d0b086905d02d2dfa0b0494ca74a097d028efa5c 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,5 +1,5 @@
 #! /bin/sh
-# From configure.in Revision: 76030 .
+# From configure.in Revision: 76301 .
 # Guess values for system-dependent variables and create Makefiles.
 # Generated by GNU Autoconf 2.61 for python 3.2.
 #
@@ -26314,6 +26314,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 4a0bf6833cc80a131688f8b0ff94e4a4dcd22d6e..2a0745f2323a17b3dd624d9faf412259591dee6b 100644 (file)
@@ -3806,6 +3806,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_MSG_CHECKING(for %zd printf() format support)
 AC_CACHE_VAL(ac_cv_have_size_t_format,
 AC_TRY_RUN([[
index 9df729a0efc15ae2865947e5584893788ddfe871..223c9961bd060936dc0e07afa7effefd2341deac 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