Index: Python/ceval.c =================================================================== --- Python/ceval.c (revision 83392) +++ Python/ceval.c (working copy) @@ -4142,7 +4142,7 @@ if (PyErr_ExceptionMatches(PyExc_TypeError)) { PyErr_Format(PyExc_TypeError, "%.200s%.200s argument after * " - "must be a sequence, not %200s", + "must be a sequence, not %.200s", PyEval_GetFuncName(func), PyEval_GetFuncDesc(func), stararg->ob_type->tp_name); Index: Objects/unicodeobject.c =================================================================== --- Objects/unicodeobject.c (revision 83392) +++ Objects/unicodeobject.c (working copy) @@ -688,12 +688,12 @@ int zeropad, int width, int precision, char c) { *fmt++ = '%'; - if (width) { + if (width >= 0) { if (zeropad) *fmt++ = '0'; fmt += sprintf(fmt, "%d", width); } - if (precision) + if (precision >= 0) fmt += sprintf(fmt, ".%d", precision); if (longflag) *fmt++ = 'l'; @@ -731,6 +731,51 @@ 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) +static PyObject * +unicode_format(PyObject *unicode, int width, int precision) +{ + char *buffer; + int spaces_cnt; + PyObject *prec_unicode; + PyObject *width_unicode; + assert(PyUnicode_Check(unicode)); + + if (precision >= 0 && precision < PyUnicode_GET_SIZE(unicode)) { + prec_unicode = PySequence_GetSlice((PyObject*)unicode, 0, precision); + if (!prec_unicode) + return NULL; + } + else { + prec_unicode = unicode; + Py_INCREF(unicode); + } + + if (width <= PyUnicode_GET_SIZE(prec_unicode)) + return prec_unicode; + + // Add left-pad spaces to reach the width. + buffer = PyMem_New(char, width); + if (!buffer) { + Py_DECREF(prec_unicode); + return NULL; + } + memset(buffer, ' ', width); + width_unicode = PyUnicode_FromStringAndSize(buffer, width); + if (!width_unicode) { + PyMem_Del(buffer); + Py_DECREF(prec_unicode); + return NULL; + } + PyMem_Del(buffer); + spaces_cnt = width - PyUnicode_GET_SIZE(prec_unicode); + Py_UNICODE_COPY(PyUnicode_AS_UNICODE(width_unicode) + spaces_cnt, + PyUnicode_AS_UNICODE(prec_unicode), + PyUnicode_GET_SIZE(prec_unicode)); + Py_DECREF(prec_unicode); + return width_unicode; +} + + PyObject * PyUnicode_FromFormatV(const char *format, va_list vargs) { @@ -745,6 +790,7 @@ const char* f; Py_UNICODE *s; PyObject *string; + PyObject *formatted; /* used by sprintf */ char buffer[ITEM_BUFFER_LEN+1]; /* use abuffer instead of buffer, if we need more space @@ -772,13 +818,11 @@ if (*f == '%') { if (*(f+1)=='%') continue; - if (*(f+1)=='S' || *(f+1)=='R' || *(f+1)=='A') - ++callcount; while (ISDIGIT((unsigned)*f)) width = (width*10) + *f++ - '0'; while (*++f && *f != '%' && !ISALPHA((unsigned)*f)) ; - if (*f == 's') + if (*f == 's' || *f == 'S' || *f == 'R' || *f == 'A') ++callcount; } } @@ -798,10 +842,11 @@ #ifdef HAVE_LONG_LONG int longlongflag = 0; #endif - const char* p = f; + const char* p = f++; width = 0; while (ISDIGIT((unsigned)*f)) width = (width*10) + *f++ - '0'; + f--; while (*++f && *f != '%' && !ISALPHA((unsigned)*f)) ; @@ -858,7 +903,7 @@ PyObject *str = PyUnicode_DecodeUTF8(s, strlen(s), "replace"); if (!str) goto fail; - n += PyUnicode_GET_SIZE(str); + n += width > PyUnicode_GET_SIZE(str) ? width : PyUnicode_GET_SIZE(str); /* Remember the str and switch to the next slot */ *callresult++ = str; break; @@ -867,7 +912,7 @@ { PyObject *obj = va_arg(count, PyObject *); assert(obj && PyUnicode_Check(obj)); - n += PyUnicode_GET_SIZE(obj); + n += width > PyUnicode_GET_SIZE(obj) ? width : PyUnicode_GET_SIZE(obj); break; } case 'V': @@ -877,9 +922,9 @@ assert(obj || str); assert(!obj || PyUnicode_Check(obj)); if (obj) - n += PyUnicode_GET_SIZE(obj); + n += width > PyUnicode_GET_SIZE(obj) ? width : PyUnicode_GET_SIZE(obj); else - n += strlen(str); + n += width > strlen(str) ? width : strlen(str); break; } case 'S': @@ -890,7 +935,7 @@ str = PyObject_Str(obj); if (!str) goto fail; - n += PyUnicode_GET_SIZE(str); + n += width > PyUnicode_GET_SIZE(str) ? width : PyUnicode_GET_SIZE(str); /* Remember the str and switch to the next slot */ *callresult++ = str; break; @@ -903,7 +948,7 @@ repr = PyObject_Repr(obj); if (!repr) goto fail; - n += PyUnicode_GET_SIZE(repr); + n += width > PyUnicode_GET_SIZE(repr) ? width : PyUnicode_GET_SIZE(repr); /* Remember the repr and switch to the next slot */ *callresult++ = repr; break; @@ -916,7 +961,7 @@ ascii = PyObject_ASCII(obj); if (!ascii) goto fail; - n += PyUnicode_GET_SIZE(ascii); + n += width > PyUnicode_GET_SIZE(ascii) ? width : PyUnicode_GET_SIZE(ascii); /* Remember the repr and switch to the next slot */ *callresult++ = ascii; break; @@ -974,14 +1019,20 @@ int size_tflag = 0; zeropad = (*f == '0'); /* parse the width.precision part */ - width = 0; - while (ISDIGIT((unsigned)*f)) + width = -1; + while (ISDIGIT((unsigned)*f)) { + if (width == -1) + width = 0; width = (width*10) + *f++ - '0'; - precision = 0; + } + precision = -1; if (*f == '.') { f++; - while (ISDIGIT((unsigned)*f)) + while (ISDIGIT((unsigned)*f)) { + if (precision == -1) + precision = 0; precision = (precision*10) + *f++ - '0'; + } } /* Handle %ld, %lu, %lld and %llu. */ if (*f == 'l') { @@ -1052,11 +1103,15 @@ { /* unused, since we already have the result */ (void) va_arg(vargs, char *); - Py_UNICODE_COPY(s, PyUnicode_AS_UNICODE(*callresult), - PyUnicode_GET_SIZE(*callresult)); - s += PyUnicode_GET_SIZE(*callresult); + formatted = unicode_format(*callresult, width, precision); + Py_DECREF(*callresult); + if (!formatted) + goto fail; + Py_UNICODE_COPY(s, PyUnicode_AS_UNICODE(formatted), + PyUnicode_GET_SIZE(formatted)); + s += PyUnicode_GET_SIZE(formatted); /* We're done with the unicode()/repr() => forget it */ - Py_DECREF(*callresult); + Py_DECREF(formatted); /* switch to next unicode()/repr() result */ ++callresult; break; @@ -1064,9 +1119,12 @@ case 'U': { PyObject *obj = va_arg(vargs, PyObject *); - Py_ssize_t size = PyUnicode_GET_SIZE(obj); - Py_UNICODE_COPY(s, PyUnicode_AS_UNICODE(obj), size); - s += size; + formatted = unicode_format(obj, width, precision); + if (!formatted) + goto fail; + Py_UNICODE_COPY(s, PyUnicode_AS_UNICODE(formatted), + PyUnicode_GET_SIZE(formatted)); + s += PyUnicode_GET_SIZE(formatted); break; } case 'V': @@ -1074,28 +1132,38 @@ PyObject *obj = va_arg(vargs, PyObject *); const char *str = va_arg(vargs, const char *); if (obj) { - Py_ssize_t size = PyUnicode_GET_SIZE(obj); - Py_UNICODE_COPY(s, PyUnicode_AS_UNICODE(obj), size); - s += size; + formatted = unicode_format(obj, width, precision); + if (!formatted) + goto fail; + Py_UNICODE_COPY(s, PyUnicode_AS_UNICODE(formatted), + PyUnicode_GET_SIZE(formatted)); + s += PyUnicode_GET_SIZE(formatted); } else { - appendstring(str); + makefmt(fmt, 0, 0, 0, zeropad, width, precision, 's'); + sprintf(realbuffer, fmt, str); + appendstring(realbuffer); } break; } case 'S': case 'R': + case 'A': { Py_UNICODE *ucopy; Py_ssize_t usize; Py_ssize_t upos; /* unused, since we already have the result */ (void) va_arg(vargs, PyObject *); - ucopy = PyUnicode_AS_UNICODE(*callresult); - usize = PyUnicode_GET_SIZE(*callresult); + formatted = unicode_format(*callresult, width, precision); + Py_DECREF(*callresult); + if (!formatted) + goto fail; + ucopy = PyUnicode_AS_UNICODE(formatted); + usize = PyUnicode_GET_SIZE(formatted); for (upos = 0; upos forget it */ - Py_DECREF(*callresult); + Py_DECREF(formatted); /* switch to next unicode()/repr() result */ ++callresult; break;