Skip to content

Commit 82864d1

Browse files
committed
Issue #7228: Add '%lld' and '%llu' support to PyFormat_FromString,
PyFormat_FromStringV and PyErr_Format.
1 parent d5b34d4 commit 82864d1

File tree

9 files changed

+266
-13
lines changed

9 files changed

+266
-13
lines changed

Doc/c-api/exceptions.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,8 @@ is a separate error indicator for each thread.
161161
.. % The descriptions for %zd and %zu are wrong, but the truth is complicated
162162
.. % because not all compilers support the %z width modifier -- we fake it
163163
.. % when necessary via interpolating PY_FORMAT_SIZE_T.
164+
.. % Similar comments apply to the %ll width modifier and
165+
.. % PY_FORMAT_LONG_LONG.
164166
.. % %u, %lu, %zu should have "new in Python 2.5" blurbs.
165167
166168
+-------------------+---------------+--------------------------------+
@@ -183,6 +185,12 @@ is a separate error indicator for each thread.
183185
| :attr:`%lu` | unsigned long | Exactly equivalent to |
184186
| | | ``printf("%lu")``. |
185187
+-------------------+---------------+--------------------------------+
188+
| :attr:`%lld` | long long | Exactly equivalent to |
189+
| | | ``printf("%lld")``. |
190+
+-------------------+---------------+--------------------------------+
191+
| :attr:`%llu` | unsigned | Exactly equivalent to |
192+
| | long long | ``printf("%llu")``. |
193+
+-------------------+---------------+--------------------------------+
186194
| :attr:`%zd` | Py_ssize_t | Exactly equivalent to |
187195
| | | ``printf("%zd")``. |
188196
+-------------------+---------------+--------------------------------+
@@ -210,6 +218,14 @@ is a separate error indicator for each thread.
210218
An unrecognized format character causes all the rest of the format string to be
211219
copied as-is to the result string, and any extra arguments discarded.
212220

221+
.. note::
222+
223+
The `"%lld"` and `"%llu"` format specifiers are only available
224+
when `HAVE_LONG_LONG` is defined.
225+
226+
.. versionchanged:: 2.7
227+
Support for `"%lld"` and `"%llu"` added.
228+
213229

214230
.. cfunction:: void PyErr_SetNone(PyObject *type)
215231

Doc/c-api/string.rst

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ called with a non-string parameter.
7878
.. % The descriptions for %zd and %zu are wrong, but the truth is complicated
7979
.. % because not all compilers support the %z width modifier -- we fake it
8080
.. % when necessary via interpolating PY_FORMAT_SIZE_T.
81+
.. % Similar comments apply to the %ll width modifier and
82+
.. % PY_FORMAT_LONG_LONG.
8183
.. % %u, %lu, %zu should have "new in Python 2.5" blurbs.
8284
8385
+-------------------+---------------+--------------------------------+
@@ -100,6 +102,12 @@ called with a non-string parameter.
100102
| :attr:`%lu` | unsigned long | Exactly equivalent to |
101103
| | | ``printf("%lu")``. |
102104
+-------------------+---------------+--------------------------------+
105+
| :attr:`%lld` | long long | Exactly equivalent to |
106+
| | | ``printf("%lld")``. |
107+
+-------------------+---------------+--------------------------------+
108+
| :attr:`%llu` | unsigned | Exactly equivalent to |
109+
| | long long | ``printf("%llu")``. |
110+
+-------------------+---------------+--------------------------------+
103111
| :attr:`%zd` | Py_ssize_t | Exactly equivalent to |
104112
| | | ``printf("%zd")``. |
105113
+-------------------+---------------+--------------------------------+
@@ -127,6 +135,14 @@ called with a non-string parameter.
127135
An unrecognized format character causes all the rest of the format string to be
128136
copied as-is to the result string, and any extra arguments discarded.
129137

138+
.. note::
139+
140+
The `"%lld"` and `"%llu"` format specifiers are only available
141+
when `HAVE_LONG_LONG` is defined.
142+
143+
.. versionchanged:: 2.7
144+
Support for `"%lld"` and `"%llu"` added.
145+
130146

131147
.. cfunction:: PyObject* PyString_FromFormatV(const char *format, va_list vargs)
132148

Include/pyport.h

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,22 @@ typedef Py_intptr_t Py_ssize_t;
229229
# endif
230230
#endif
231231

232+
/* PY_FORMAT_LONG_LONG is analogous to PY_FORMAT_SIZE_T above, but for
233+
* the long long type instead of the size_t type. It's only available
234+
* when HAVE_LONG_LONG is defined. The "high level" Python format
235+
* functions listed above will interpret "lld" or "llu" correctly on
236+
* all platforms.
237+
*/
238+
#ifdef HAVE_LONG_LONG
239+
# ifndef PY_FORMAT_LONG_LONG
240+
# if defined(MS_WIN64) || defined(MS_WINDOWS)
241+
# define PY_FORMAT_LONG_LONG "I64"
242+
# else
243+
# error "This platform's pyconfig.h needs to define PY_FORMAT_LONG_LONG"
244+
# endif
245+
# endif
246+
#endif
247+
232248
/* Py_LOCAL can be used instead of static to get the fastest possible calling
233249
* convention for functions that are local to a given module.
234250
*

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1462,6 +1462,9 @@ Documentation
14621462
C-API
14631463
-----
14641464

1465+
- Issue #Add '%lld' and '%llu' support to PyString_FromFormat(V)
1466+
and PyErr_Format, on machines with HAVE_LONG_LONG defined.
1467+
14651468
- Add new C-API function PyOS_string_to_double, and deprecated
14661469
PyOS_ascii_atof and PyOS_ascii_strtod.
14671470

Modules/_testcapimodule.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,12 @@ test_string_from_format(PyObject *self, PyObject *args)
954954
CHECK_1_FORMAT("%lu", unsigned long);
955955
CHECK_1_FORMAT("%zu", size_t);
956956

957+
/* "%lld" and "%llu" support added in Python 2.7. */
958+
#ifdef HAVE_LONG_LONG
959+
CHECK_1_FORMAT("%llu", unsigned PY_LONG_LONG);
960+
CHECK_1_FORMAT("%lld", PY_LONG_LONG);
961+
#endif
962+
957963
Py_RETURN_NONE;
958964

959965
Fail:

Objects/stringobject.c

Lines changed: 59 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -189,16 +189,31 @@ PyString_FromFormatV(const char *format, va_list vargs)
189189
/* step 1: figure out how large a buffer we need */
190190
for (f = format; *f; f++) {
191191
if (*f == '%') {
192+
#ifdef HAVE_LONG_LONG
193+
int longlongflag = 0;
194+
#endif
192195
const char* p = f;
193196
while (*++f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
194197
;
195198

196199
/* skip the 'l' or 'z' in {%ld, %zd, %lu, %zu} since
197200
* they don't affect the amount of space we reserve.
198201
*/
199-
if ((*f == 'l' || *f == 'z') &&
200-
(f[1] == 'd' || f[1] == 'u'))
202+
if (*f == 'l') {
203+
if (f[1] == 'd' || f[1] == 'u') {
204+
++f;
205+
}
206+
#ifdef HAVE_LONG_LONG
207+
else if (f[1] == 'l' &&
208+
(f[2] == 'd' || f[2] == 'u')) {
209+
longlongflag = 1;
210+
f += 2;
211+
}
212+
#endif
213+
}
214+
else if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) {
201215
++f;
216+
}
202217

203218
switch (*f) {
204219
case 'c':
@@ -209,10 +224,21 @@ PyString_FromFormatV(const char *format, va_list vargs)
209224
break;
210225
case 'd': case 'u': case 'i': case 'x':
211226
(void) va_arg(count, int);
212-
/* 20 bytes is enough to hold a 64-bit
213-
integer. Decimal takes the most space.
214-
This isn't enough for octal. */
215-
n += 20;
227+
#ifdef HAVE_LONG_LONG
228+
/* Need at most
229+
ceil(log10(256)*SIZEOF_LONG_LONG) digits,
230+
plus 1 for the sign. 53/22 is an upper
231+
bound for log10(256). */
232+
if (longlongflag)
233+
n += 2 + (SIZEOF_LONG_LONG*53-1) / 22;
234+
else
235+
#endif
236+
/* 20 bytes is enough to hold a 64-bit
237+
integer. Decimal takes the most
238+
space. This isn't enough for
239+
octal. */
240+
n += 20;
241+
216242
break;
217243
case 's':
218244
s = va_arg(count, char*);
@@ -255,6 +281,9 @@ PyString_FromFormatV(const char *format, va_list vargs)
255281
const char* p = f++;
256282
Py_ssize_t i;
257283
int longflag = 0;
284+
#ifdef HAVE_LONG_LONG
285+
int longlongflag = 0;
286+
#endif
258287
int size_tflag = 0;
259288
/* parse the width.precision part (we're only
260289
interested in the precision value, if any) */
@@ -269,14 +298,22 @@ PyString_FromFormatV(const char *format, va_list vargs)
269298
}
270299
while (*f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
271300
f++;
272-
/* handle the long flag, but only for %ld and %lu.
273-
others can be added when necessary. */
274-
if (*f == 'l' && (f[1] == 'd' || f[1] == 'u')) {
275-
longflag = 1;
276-
++f;
301+
/* Handle %ld, %lu, %lld and %llu. */
302+
if (*f == 'l') {
303+
if (f[1] == 'd' || f[1] == 'u') {
304+
longflag = 1;
305+
++f;
306+
}
307+
#ifdef HAVE_LONG_LONG
308+
else if (f[1] == 'l' &&
309+
(f[2] == 'd' || f[2] == 'u')) {
310+
longlongflag = 1;
311+
f += 2;
312+
}
313+
#endif
277314
}
278315
/* handle the size_t flag. */
279-
if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) {
316+
else if (*f == 'z' && (f[1] == 'd' || f[1] == 'u')) {
280317
size_tflag = 1;
281318
++f;
282319
}
@@ -288,6 +325,11 @@ PyString_FromFormatV(const char *format, va_list vargs)
288325
case 'd':
289326
if (longflag)
290327
sprintf(s, "%ld", va_arg(vargs, long));
328+
#ifdef HAVE_LONG_LONG
329+
else if (longlongflag)
330+
sprintf(s, "%" PY_FORMAT_LONG_LONG "d",
331+
va_arg(vargs, PY_LONG_LONG));
332+
#endif
291333
else if (size_tflag)
292334
sprintf(s, "%" PY_FORMAT_SIZE_T "d",
293335
va_arg(vargs, Py_ssize_t));
@@ -299,6 +341,11 @@ PyString_FromFormatV(const char *format, va_list vargs)
299341
if (longflag)
300342
sprintf(s, "%lu",
301343
va_arg(vargs, unsigned long));
344+
#ifdef HAVE_LONG_LONG
345+
else if (longlongflag)
346+
sprintf(s, "%" PY_FORMAT_LONG_LONG "u",
347+
va_arg(vargs, PY_LONG_LONG));
348+
#endif
302349
else if (size_tflag)
303350
sprintf(s, "%" PY_FORMAT_SIZE_T "u",
304351
va_arg(vargs, size_t));

configure

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#! /bin/sh
2-
# From configure.in Revision: 76052 .
2+
# From configure.in Revision: 76300 .
33
# Guess values for system-dependent variables and create Makefiles.
44
# Generated by GNU Autoconf 2.61 for python 2.7.
55
#
@@ -27014,6 +27014,104 @@ else
2701427014
echo "${ECHO_T}no" >&6; }
2701527015
fi
2701627016

27017+
if test "$have_long_long" = yes
27018+
then
27019+
{ echo "$as_me:$LINENO: checking for %lld and %llu printf() format support" >&5
27020+
echo $ECHO_N "checking for %lld and %llu printf() format support... $ECHO_C" >&6; }
27021+
if test "${ac_cv_have_long_long_format+set}" = set; then
27022+
echo $ECHO_N "(cached) $ECHO_C" >&6
27023+
else
27024+
if test "$cross_compiling" = yes; then
27025+
ac_cv_have_long_long_format=no
27026+
else
27027+
cat >conftest.$ac_ext <<_ACEOF
27028+
/* confdefs.h. */
27029+
_ACEOF
27030+
cat confdefs.h >>conftest.$ac_ext
27031+
cat >>conftest.$ac_ext <<_ACEOF
27032+
/* end confdefs.h. */
27033+
27034+
#include <stdio.h>
27035+
#include <stddef.h>
27036+
#include <string.h>
27037+
27038+
#ifdef HAVE_SYS_TYPES_H
27039+
#include <sys/types.h>
27040+
#endif
27041+
27042+
int main()
27043+
{
27044+
char buffer[256];
27045+
27046+
if (sprintf(buffer, "%lld", (long long)123) < 0)
27047+
return 1;
27048+
if (strcmp(buffer, "123"))
27049+
return 1;
27050+
27051+
if (sprintf(buffer, "%lld", (long long)-123) < 0)
27052+
return 1;
27053+
if (strcmp(buffer, "-123"))
27054+
return 1;
27055+
27056+
if (sprintf(buffer, "%llu", (unsigned long long)123) < 0)
27057+
return 1;
27058+
if (strcmp(buffer, "123"))
27059+
return 1;
27060+
27061+
return 0;
27062+
}
27063+
27064+
_ACEOF
27065+
rm -f conftest$ac_exeext
27066+
if { (ac_try="$ac_link"
27067+
case "(($ac_try" in
27068+
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
27069+
*) ac_try_echo=$ac_try;;
27070+
esac
27071+
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
27072+
(eval "$ac_link") 2>&5
27073+
ac_status=$?
27074+
echo "$as_me:$LINENO: \$? = $ac_status" >&5
27075+
(exit $ac_status); } && { ac_try='./conftest$ac_exeext'
27076+
{ (case "(($ac_try" in
27077+
*\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
27078+
*) ac_try_echo=$ac_try;;
27079+
esac
27080+
eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5
27081+
(eval "$ac_try") 2>&5
27082+
ac_status=$?
27083+
echo "$as_me:$LINENO: \$? = $ac_status" >&5
27084+
(exit $ac_status); }; }; then
27085+
ac_cv_have_long_long_format=yes
27086+
else
27087+
echo "$as_me: program exited with status $ac_status" >&5
27088+
echo "$as_me: failed program was:" >&5
27089+
sed 's/^/| /' conftest.$ac_ext >&5
27090+
27091+
( exit $ac_status )
27092+
ac_cv_have_long_long_format=no
27093+
fi
27094+
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
27095+
fi
27096+
27097+
27098+
27099+
fi
27100+
27101+
{ echo "$as_me:$LINENO: result: $ac_cv_have_long_long_format" >&5
27102+
echo "${ECHO_T}$ac_cv_have_long_long_format" >&6; }
27103+
fi
27104+
27105+
if test $ac_cv_have_long_long_format = yes
27106+
then
27107+
27108+
cat >>confdefs.h <<\_ACEOF
27109+
#define PY_FORMAT_LONG_LONG "ll"
27110+
_ACEOF
27111+
27112+
fi
27113+
27114+
2701727115
{ echo "$as_me:$LINENO: checking for %zd printf() format support" >&5
2701827116
echo $ECHO_N "checking for %zd printf() format support... $ECHO_C" >&6; }
2701927117
if test "${ac_cv_have_size_t_format+set}" = set; then

0 commit comments

Comments
 (0)