Index: Objects/stringlib/string_format.h =================================================================== --- Objects/stringlib/string_format.h (revision 70268) +++ Objects/stringlib/string_format.h (working copy) @@ -563,18 +563,32 @@ *conversion = '\0'; SubString_init(format_spec, NULL, 0); - /* search for the field name. it's terminated by the end of the - string, or a ':' or '!' */ field_name->ptr = str->ptr; - while (str->ptr < str->end) { - switch (c = *(str->ptr++)) { - case ':': - case '!': + /* see if the field name is omitted. we can tell by either: + - an empty string + - starts with ':' (starts a specifier) + - starts with '!' (starts a conversion) + - starts with '.' (attribute access) + - starts with '[' (array indexing) + */ + if (str->ptr == str->end || *str->ptr == ':' || *str->ptr == '!' || + *str->ptr == '.' || *str->ptr == '[') + /* return a zero length field name */ + field_name->end = field_name->ptr; + else { + /* search for the field name. it's terminated by the end of + the string, or a ':' or '!' */ + field_name->ptr = str->ptr; + while (str->ptr < str->end) { + switch (c = *(str->ptr++)) { + case ':': + case '!': + break; + default: + continue; + } break; - default: - continue; } - break; } if (c == '!' || c == ':') { @@ -629,15 +643,32 @@ typedef struct { SubString str; + enum { + ANS_INIT, + ANS_AUTO, + ANS_MANUAL, + } auto_number_state; /* keep track if we're auto-numbering + fields */ + int auto_number_count; /* what number we're on */ + PyObject* auto_number_holder; /* holds the count, converted to a string */ } MarkupIterator; static int MarkupIterator_init(MarkupIterator *self, STRINGLIB_CHAR *ptr, Py_ssize_t len) { SubString_init(&self->str, ptr, len); + self->auto_number_state = ANS_INIT; + self->auto_number_count = 0; + self->auto_number_holder = NULL; return 1; } +static void +MarkupIterator_destroy(MarkupIterator *self) +{ + Py_XDECREF(self->auto_number_holder); +} + /* returns 0 on error, 1 on non-error termination, and 2 if it got a string (or something to be expanded) */ static int @@ -744,6 +775,50 @@ if (parse_field(&s, field_name, format_spec, conversion) == 0) return 0; + /* see if we're auto-numbering */ + if (self->auto_number_state == ANS_INIT) { + /* first time through, remember which state we're + using */ + if (field_name->ptr == field_name->end) + self->auto_number_state = ANS_AUTO; + else + self->auto_number_state = ANS_MANUAL; + } + + /* make sure what we're doing this time matches what we've + been doing before */ + if (self->auto_number_state == ANS_MANUAL) { + if (field_name->ptr == field_name->end) { + PyErr_SetString(PyExc_ValueError, "cannot switch from " + "manual field specification to " + "automatic field numbering"); + return 0; + } + } + else { + if (field_name->ptr != field_name->end) { + PyErr_SetString(PyExc_ValueError, "cannot switch from " + "automatic field numbering to " + "manual field specification"); + return 0; + } + } + + if (self->auto_number_state == ANS_AUTO) { + char buf[100]; + PyOS_snprintf(buf, sizeof(buf), "%d", self->auto_number_count); + self->auto_number_count++; + + /* if we're holding on to a string already, free it */ + Py_XDECREF(self->auto_number_holder); + + self->auto_number_holder = STRINGLIB_NEW(buf, strlen(buf)); + if (self->auto_number_holder == NULL) + return 0; + + field_name->ptr = STRINGLIB_STR(self->auto_number_holder); + field_name->end = field_name->ptr + strlen(buf); + } /* a zero length field_name is an error */ if (field_name->ptr == field_name->end) { PyErr_SetString(PyExc_ValueError, "zero length field name " @@ -878,14 +953,20 @@ while ((result = MarkupIterator_next(&iter, &literal, &field_name, &format_spec, &conversion, &format_spec_needs_expanding)) == 2) { - if (!output_data(output, literal.ptr, literal.end - literal.ptr)) - return 0; + if (!output_data(output, literal.ptr, literal.end - literal.ptr)) { + result = 0; + goto done; + } if (field_name.ptr != field_name.end) if (!output_markup(&field_name, &format_spec, format_spec_needs_expanding, conversion, output, - args, kwargs, recursion_depth)) - return 0; + args, kwargs, recursion_depth)) { + result = 0; + goto done; + } } +done: + MarkupIterator_destroy(&iter); return result; } @@ -979,6 +1060,7 @@ formatteriter_dealloc(formatteriterobject *it) { Py_XDECREF(it->str); + MarkupIterator_destroy(&it->it_markup); PyObject_FREE(it); }