summaryrefslogtreecommitdiffstats
path: root/Objects/unicodeobject.c
diff options
context:
space:
mode:
authorMark Dickinson <dickinsm@gmail.com>2009-11-16 17:00:11 (GMT)
committerMark Dickinson <dickinsm@gmail.com>2009-11-16 17:00:11 (GMT)
commit6ce4a9a9f2d690e9ce7121154fd9cc04082d7f59 (patch)
tree4aacd6f6dd48c7fdd464cfb274108b5e5d16a725 /Objects/unicodeobject.c
parent260bd3e5578008682f009530faa615f74c6bcf82 (diff)
downloadcpython-6ce4a9a9f2d690e9ce7121154fd9cc04082d7f59.zip
cpython-6ce4a9a9f2d690e9ce7121154fd9cc04082d7f59.tar.gz
cpython-6ce4a9a9f2d690e9ce7121154fd9cc04082d7f59.tar.bz2
Merged revisions 76308 via svnmerge from
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. ........
Diffstat (limited to 'Objects/unicodeobject.c')
-rw-r--r--Objects/unicodeobject.c113
1 files changed, 90 insertions, 23 deletions
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index cdb739a..9c0be9b 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -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;