Commit 346737fc authored by Walter Dörwald's avatar Walter Dörwald

Add support for width, precision and zeropadding to the %d, %i, %u and %x

format specifiers in PyUnicode_FromFormat().

Change unicode's tp_str implementation to return a unicode object.
parent 3e1b85ea
...@@ -508,6 +508,28 @@ PyObject *PyUnicode_FromWideChar(register const wchar_t *w, ...@@ -508,6 +508,28 @@ PyObject *PyUnicode_FromWideChar(register const wchar_t *w,
return (PyObject *)unicode; return (PyObject *)unicode;
} }
static void
makefmt(char *fmt, int longflag, int size_tflag, int zeropad, int width, int precision, char c)
{
*fmt++ = '%';
if (width) {
if (zeropad)
*fmt++ = '0';
fmt += sprintf(fmt, "%d", width);
}
if (precision)
fmt += sprintf(fmt, ".%d", precision);
if (longflag)
*fmt++ = 'l';
else if (size_tflag) {
char *f = PY_FORMAT_SIZE_T;
while (*f)
*fmt++ = *f++;
}
*fmt++ = c;
*fmt = '\0';
}
#define appendstring(string) {for (copy = string;*copy;) *s++ = *copy++;} #define appendstring(string) {for (copy = string;*copy;) *s++ = *copy++;}
PyObject * PyObject *
...@@ -518,11 +540,20 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) ...@@ -518,11 +540,20 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
PyObject **callresults = NULL; PyObject **callresults = NULL;
PyObject **callresult; PyObject **callresult;
Py_ssize_t n = 0; Py_ssize_t n = 0;
int width = 0;
int precision = 0;
int zeropad;
const char* f; const char* f;
Py_UNICODE *s; Py_UNICODE *s;
PyObject *string; PyObject *string;
/* used by sprintf */ /* used by sprintf */
char buffer[21]; char buffer[21];
/* 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 */
const char *copy; const char *copy;
#ifdef VA_LIST_IS_ARRAY #ifdef VA_LIST_IS_ARRAY
...@@ -555,6 +586,9 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) ...@@ -555,6 +586,9 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
for (f = format; *f; f++) { for (f = format; *f; f++) {
if (*f == '%') { if (*f == '%') {
const char* p = f; const char* p = f;
width = 0;
while (isdigit(Py_CHARMASK(*f)))
width = (width*10) + *f++ - '0';
while (*++f && *f != '%' && !isalpha(Py_CHARMASK(*f))) while (*++f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
; ;
...@@ -576,8 +610,14 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) ...@@ -576,8 +610,14 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
(void) va_arg(count, int); (void) va_arg(count, int);
/* 20 bytes is enough to hold a 64-bit /* 20 bytes is enough to hold a 64-bit
integer. Decimal takes the most space. integer. Decimal takes the most space.
This isn't enough for octal. */ This isn't enough for octal.
n += 20; If a width is specified we need more
(which we allocate later). */
if (width < 20)
width = 20;
n += width;
if (abuffersize < width)
abuffersize = width;
break; break;
case 's': case 's':
n += strlen(va_arg(count, char*)); n += strlen(va_arg(count, char*));
...@@ -638,13 +678,23 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) ...@@ -638,13 +678,23 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
n++; n++;
} }
expand: expand:
if (abuffersize > 20) {
abuffer = PyMem_Malloc(abuffersize);
if (!abuffer) {
PyErr_NoMemory();
goto fail;
}
realbuffer = abuffer;
}
else
realbuffer = buffer;
/* step 4: fill the buffer */ /* step 4: fill the buffer */
/* Since we've analyzed how much space we need for the worst case, /* Since we've analyzed how much space we need for the worst case,
we don't have to resize the string. we don't have to resize the string.
There can be no errors beyond this point. */ There can be no errors beyond this point. */
string = PyUnicode_FromUnicode(NULL, n); string = PyUnicode_FromUnicode(NULL, n);
if (!string) if (!string)
return NULL; goto fail;
s = PyUnicode_AS_UNICODE(string); s = PyUnicode_AS_UNICODE(string);
callresult = callresults; callresult = callresults;
...@@ -654,19 +704,17 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) ...@@ -654,19 +704,17 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
const char* p = f++; const char* p = f++;
int longflag = 0; int longflag = 0;
int size_tflag = 0; int size_tflag = 0;
/* parse the width.precision part (we're only zeropad = (*f == '0');
interested in the precision value, if any) */ /* parse the width.precision part */
n = 0; width = 0;
while (isdigit(Py_CHARMASK(*f))) while (isdigit(Py_CHARMASK(*f)))
n = (n*10) + *f++ - '0'; width = (width*10) + *f++ - '0';
precision = 0;
if (*f == '.') { if (*f == '.') {
f++; f++;
n = 0;
while (isdigit(Py_CHARMASK(*f))) while (isdigit(Py_CHARMASK(*f)))
n = (n*10) + *f++ - '0'; precision = (precision*10) + *f++ - '0';
} }
while (*f && *f != '%' && !isalpha(Py_CHARMASK(*f)))
f++;
/* handle the long flag, but only for %ld and %lu. /* handle the long flag, but only for %ld and %lu.
others can be added when necessary. */ others can be added when necessary. */
if (*f == 'l' && (f[1] == 'd' || f[1] == 'u')) { if (*f == 'l' && (f[1] == 'd' || f[1] == 'u')) {
...@@ -684,34 +732,34 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) ...@@ -684,34 +732,34 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
*s++ = va_arg(vargs, int); *s++ = va_arg(vargs, int);
break; break;
case 'd': case 'd':
makefmt(fmt, longflag, size_tflag, zeropad, width, precision, 'd');
if (longflag) if (longflag)
sprintf(buffer, "%ld", va_arg(vargs, long)); sprintf(realbuffer, fmt, va_arg(vargs, long));
else if (size_tflag) else if (size_tflag)
sprintf(buffer, "%" PY_FORMAT_SIZE_T "d", sprintf(realbuffer, fmt, va_arg(vargs, Py_ssize_t));
va_arg(vargs, Py_ssize_t));
else else
sprintf(buffer, "%d", va_arg(vargs, int)); sprintf(realbuffer, fmt, va_arg(vargs, int));
appendstring(buffer); appendstring(realbuffer);
break; break;
case 'u': case 'u':
makefmt(fmt, longflag, size_tflag, zeropad, width, precision, 'u');
if (longflag) if (longflag)
sprintf(buffer, "%lu", sprintf(realbuffer, fmt, va_arg(vargs, unsigned long));
va_arg(vargs, unsigned long));
else if (size_tflag) else if (size_tflag)
sprintf(buffer, "%" PY_FORMAT_SIZE_T "u", sprintf(realbuffer, fmt, va_arg(vargs, size_t));
va_arg(vargs, size_t));
else else
sprintf(buffer, "%u", sprintf(realbuffer, fmt, va_arg(vargs, unsigned int));
va_arg(vargs, unsigned int)); appendstring(realbuffer);
appendstring(buffer);
break; break;
case 'i': case 'i':
sprintf(buffer, "%i", va_arg(vargs, int)); makefmt(fmt, 0, 0, zeropad, width, precision, 'i');
appendstring(buffer); sprintf(realbuffer, fmt, va_arg(vargs, int));
appendstring(realbuffer);
break; break;
case 'x': case 'x':
sprintf(buffer, "%x", va_arg(vargs, int)); makefmt(fmt, 0, 0, zeropad, width, precision, 'x');
appendstring(buffer); sprintf(realbuffer, fmt, va_arg(vargs, int));
appendstring(realbuffer);
break; break;
case 's': case 's':
p = va_arg(vargs, char*); p = va_arg(vargs, char*);
...@@ -767,6 +815,8 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) ...@@ -767,6 +815,8 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
end: end:
if (callresults) if (callresults)
PyMem_Free(callresults); PyMem_Free(callresults);
if (abuffer)
PyMem_Free(abuffer);
_PyUnicode_Resize(&string, s - PyUnicode_AS_UNICODE(string)); _PyUnicode_Resize(&string, s - PyUnicode_AS_UNICODE(string));
return string; return string;
fail: fail:
...@@ -778,6 +828,8 @@ PyUnicode_FromFormatV(const char *format, va_list vargs) ...@@ -778,6 +828,8 @@ PyUnicode_FromFormatV(const char *format, va_list vargs)
} }
PyMem_Free(callresults); PyMem_Free(callresults);
} }
if (abuffer)
PyMem_Free(abuffer);
return NULL; return NULL;
} }
...@@ -7327,9 +7379,13 @@ unicode_splitlines(PyUnicodeObject *self, PyObject *args) ...@@ -7327,9 +7379,13 @@ unicode_splitlines(PyUnicodeObject *self, PyObject *args)
static static
PyObject *unicode_str(PyObject *self) PyObject *unicode_str(PyObject *self)
{ {
PyObject *res = _PyUnicode_AsDefaultEncodedString(self, NULL); if (PyUnicode_CheckExact(self)) {
Py_XINCREF(res); Py_INCREF(self);
return res; return self;
} else
/* Subtype -- return genuine unicode string with the same value. */
return PyUnicode_FromUnicode(PyUnicode_AS_UNICODE(self),
PyUnicode_GET_SIZE(self));
} }
PyDoc_STRVAR(swapcase__doc__, PyDoc_STRVAR(swapcase__doc__,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment