diff options
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/abstract.c | 51 | ||||
-rw-r--r-- | Objects/stringlib/formatter.h | 228 | ||||
-rw-r--r-- | Objects/stringlib/string_format.h | 96 | ||||
-rw-r--r-- | Objects/stringlib/stringdefs.h | 5 | ||||
-rw-r--r-- | Objects/stringlib/unicodedefs.h | 6 |
5 files changed, 236 insertions, 150 deletions
diff --git a/Objects/abstract.c b/Objects/abstract.c index bb6c301..655a52a 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -704,6 +704,57 @@ PyBuffer_FillInfo(Py_buffer *view, void *buf, Py_ssize_t len, return 0; } +PyObject * +PyObject_Format(PyObject *obj, PyObject *format_spec) +{ + static PyObject * str__format__ = NULL; + PyObject *meth; + PyObject *empty = NULL; + PyObject *result = NULL; + + /* Initialize cached value */ + if (str__format__ == NULL) { + /* Initialize static variable needed by _PyType_Lookup */ + str__format__ = PyUnicode_FromString("__format__"); + if (str__format__ == NULL) + goto done; + } + + /* If no format_spec is provided, use an empty string */ + if (format_spec == NULL) { + empty = PyUnicode_FromUnicode(NULL, 0); + format_spec = empty; + } + + /* Make sure the type is initialized. float gets initialized late */ + if (Py_TYPE(obj)->tp_dict == NULL) + if (PyType_Ready(Py_TYPE(obj)) < 0) + goto done; + + /* Find the (unbound!) __format__ method (a borrowed reference) */ + meth = _PyType_Lookup(Py_TYPE(obj), str__format__); + if (meth == NULL) { + PyErr_Format(PyExc_TypeError, + "Type %.100s doesn't define __format__", + Py_TYPE(obj)->tp_name); + goto done; + } + + /* And call it, binding it to the value */ + result = PyObject_CallFunctionObjArgs(meth, obj, format_spec, NULL); + + if (result && !PyUnicode_Check(result)) { + PyErr_SetString(PyExc_TypeError, + "__format__ method did not return string"); + Py_DECREF(result); + result = NULL; + goto done; + } + +done: + Py_XDECREF(empty); + return result; +} /* Operations on numbers */ int diff --git a/Objects/stringlib/formatter.h b/Objects/stringlib/formatter.h index 2ff7290..39da6b3 100644 --- a/Objects/stringlib/formatter.h +++ b/Objects/stringlib/formatter.h @@ -195,7 +195,7 @@ parse_internal_render_format_spec(PyObject *format_spec, return 1; } - +#if defined FORMAT_FLOAT || defined FORMAT_LONG /************************************************************************/ /*********** common routines for numeric formatting *********************/ /************************************************************************/ @@ -288,7 +288,8 @@ calc_number_widths(NumberFieldWidths *r, STRINGLIB_CHAR actual_sign, else { /* determine which of left, space, or right padding is needed */ - Py_ssize_t padding = format->width - (r->n_lsign + n_digits + r->n_rsign); + Py_ssize_t padding = format->width - + (r->n_lsign + n_digits + r->n_rsign); if (format->align == '<') r->n_rpadding = padding; else if (format->align == '>') @@ -338,6 +339,7 @@ fill_number(STRINGLIB_CHAR *p_buf, const NumberFieldWidths *spec, } return p_digits; } +#endif /* FORMAT_FLOAT || FORMAT_LONG */ /************************************************************************/ /*********** string formatting ******************************************/ @@ -434,18 +436,23 @@ done: /*********** long formatting ********************************************/ /************************************************************************/ +#if defined FORMAT_LONG || defined FORMAT_INT +typedef PyObject* +(*IntOrLongToString)(PyObject *value, int base); + static PyObject * -format_long_internal(PyObject *value, const InternalFormatSpec *format) +format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format, + IntOrLongToString tostring) { PyObject *result = NULL; - int total_leading_chars_to_skip = 0; /* also includes sign, if - present */ + PyObject *tmp = NULL; + STRINGLIB_CHAR *pnumeric_chars; + STRINGLIB_CHAR numeric_char; STRINGLIB_CHAR sign = '\0'; STRINGLIB_CHAR *p; Py_ssize_t n_digits; /* count of digits need from the computed string */ - Py_ssize_t len; - Py_ssize_t tmp; + Py_ssize_t n_leading_chars; NumberFieldWidths spec; long x; @@ -469,6 +476,7 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format) /* taken from unicodeobject.c formatchar() */ /* Integer input truncated to a character */ +/* XXX: won't work for int */ x = PyLong_AsLong(value); if (x == -1 && PyErr_Occurred()) goto done; @@ -487,115 +495,101 @@ format_long_internal(PyObject *value, const InternalFormatSpec *format) goto done; } #endif - result = STRINGLIB_NEW(NULL, 1); - if (result == NULL) - goto done; - p = STRINGLIB_STR(result); - p[0] = (Py_UNICODE) x; - n_digits = len = 1; + numeric_char = (STRINGLIB_CHAR)x; + pnumeric_chars = &numeric_char; + n_digits = 1; } else { int base; - int format_leading_chars_to_skip; /* characters added by - PyNumber_ToBase that we - want to skip over. - instead of using them, - we'll compute our - own. */ - /* compute the base and how many characters will be added by + int leading_chars_to_skip; /* Number of characters added by + PyNumber_ToBase that we want to + skip over. */ + + /* Compute the base and how many characters will be added by PyNumber_ToBase */ switch (format->type) { case 'b': base = 2; - format_leading_chars_to_skip = 2; /* 0b */ + leading_chars_to_skip = 2; /* 0b */ break; case 'o': base = 8; - format_leading_chars_to_skip = 2; /* 0o */ + leading_chars_to_skip = 2; /* 0o */ break; case 'x': case 'X': base = 16; - format_leading_chars_to_skip = 2; /* 0x */ + leading_chars_to_skip = 2; /* 0x */ break; default: /* shouldn't be needed, but stops a compiler warning */ case 'd': base = 10; - format_leading_chars_to_skip = 0; + leading_chars_to_skip = 0; break; } - /* do the hard part, converting to a string in a given base */ - result = PyNumber_ToBase(value, base); - if (result == NULL) + /* Do the hard part, converting to a string in a given base */ + tmp = tostring(value, base); + if (tmp == NULL) goto done; - n_digits = STRINGLIB_LEN(result); - len = n_digits; - p = STRINGLIB_STR(result); + pnumeric_chars = STRINGLIB_STR(tmp); + n_digits = STRINGLIB_LEN(tmp); - /* if X, convert to uppercase */ - if (format->type == 'X') - for (tmp = 0; tmp < len; tmp++) - p[tmp] = STRINGLIB_TOUPPER(p[tmp]); + /* Remember not to modify what pnumeric_chars points to. it + might be interned. Only modify it after we copy it into a + newly allocated output buffer. */ - /* is a sign character present in the output? if so, remember it + /* Is a sign character present in the output? If so, remember it and skip it */ - sign = p[0]; + sign = pnumeric_chars[0]; if (sign == '-') { - total_leading_chars_to_skip += 1; - n_digits--; + ++leading_chars_to_skip; } - /* skip over the leading digits (0x, 0b, etc.) */ - assert(n_digits >= format_leading_chars_to_skip + 1); - n_digits -= format_leading_chars_to_skip; - total_leading_chars_to_skip += format_leading_chars_to_skip; + /* Skip over the leading chars (0x, 0b, etc.) */ + n_digits -= leading_chars_to_skip; + pnumeric_chars += leading_chars_to_skip; } + /* Calculate the widths of the various leading and trailing parts */ calc_number_widths(&spec, sign, n_digits, format); - /* if the buffer is getting bigger, realloc it. if it's getting - smaller, don't realloc because we need to move the results - around first. realloc after we've done that */ + /* Allocate a new string to hold the result */ + result = STRINGLIB_NEW(NULL, spec.n_total); + if (!result) + goto done; + p = STRINGLIB_STR(result); - if (spec.n_total > len) { - if (STRINGLIB_RESIZE(&result, spec.n_total) < 0) - goto done; - /* recalc, because string might have moved */ - p = STRINGLIB_STR(result); - } + /* Fill in the digit parts */ + n_leading_chars = spec.n_lpadding + spec.n_lsign + spec.n_spadding; + memmove(p + n_leading_chars, + pnumeric_chars, + n_digits * sizeof(STRINGLIB_CHAR)); - /* copy the characters into position first, since we're going to - overwrite some of that space */ - /* we need to move if the number of left padding in the output is - different from the number of characters we need to skip */ - if ((spec.n_lpadding + spec.n_lsign + spec.n_spadding) != - total_leading_chars_to_skip) { - memmove(p + (spec.n_lpadding + spec.n_lsign + spec.n_spadding), - p + total_leading_chars_to_skip, - n_digits * sizeof(STRINGLIB_CHAR)); + /* if X, convert to uppercase */ + if (format->type == 'X') { + Py_ssize_t t; + for (t = 0; t < n_digits; t++) + p[t + n_leading_chars] = STRINGLIB_TOUPPER(p[t + n_leading_chars]); } - /* now fill in the non-digit parts */ + /* Fill in the non-digit parts */ fill_number(p, &spec, n_digits, format->fill_char == '\0' ? ' ' : format->fill_char); - /* if we're getting smaller, realloc now */ - if (spec.n_total < len) { - if (STRINGLIB_RESIZE(&result, spec.n_total) < 0) - goto done; - } - done: + Py_XDECREF(tmp); return result; } - +#endif /* defined FORMAT_LONG || defined FORMAT_INT */ /************************************************************************/ /*********** float formatting *******************************************/ /************************************************************************/ +#ifdef FORMAT_FLOAT +#if STRINGLIB_IS_UNICODE /* taken from unicodeobject.c */ static Py_ssize_t strtounicode(Py_UNICODE *buffer, const char *charbuffer) @@ -607,6 +601,7 @@ strtounicode(Py_UNICODE *buffer, const char *charbuffer) return len; } +#endif /* the callback function to call to do the actual float formatting. it matches the definition of PyOS_ascii_formatd */ @@ -694,7 +689,8 @@ _format_float(STRINGLIB_CHAR type, PyObject *value, /* cast "type", because if we're in unicode we need to pass a 8-bit char. this is safe, because we've restricted what "type" can be */ - PyOS_snprintf(fmt, sizeof(fmt), "%%.%" PY_FORMAT_SIZE_T "d%c", precision, (char)type); + PyOS_snprintf(fmt, sizeof(fmt), "%%.%" PY_FORMAT_SIZE_T "d%c", precision, + (char)type); /* call the passed in function to do the actual formatting */ snprintf(charbuf, sizeof(charbuf), fmt, x); @@ -739,7 +735,8 @@ _format_float(STRINGLIB_CHAR type, PyObject *value, format->fill_char == '\0' ? ' ' : format->fill_char); /* fill in the digit parts */ - memmove(STRINGLIB_STR(result) + (spec.n_lpadding + spec.n_lsign + spec.n_spadding), + memmove(STRINGLIB_STR(result) + + (spec.n_lpadding + spec.n_lsign + spec.n_spadding), p, n_digits * sizeof(STRINGLIB_CHAR)); @@ -755,20 +752,43 @@ format_float_internal(PyObject *value, const InternalFormatSpec *format) else return _format_float(format->type, value, format, PyOS_ascii_formatd); } +#endif /* FORMAT_FLOAT */ /************************************************************************/ /*********** built in formatters ****************************************/ /************************************************************************/ - +#ifdef FORMAT_STRING PyObject * FORMAT_STRING(PyObject* value, PyObject* args) { PyObject *format_spec; PyObject *result = NULL; +#if PY_VERSION_HEX < 0x03000000 + PyObject *tmp = NULL; +#endif InternalFormatSpec format; - if (!PyArg_ParseTuple(args, STRINGLIB_PARSE_CODE ":__format__", &format_spec)) + /* If 2.x, we accept either str or unicode, and try to convert it + to the right type. In 3.x, we insist on only unicode */ +#if PY_VERSION_HEX >= 0x03000000 + if (!PyArg_ParseTuple(args, STRINGLIB_PARSE_CODE ":__format__", + &format_spec)) + goto done; +#else + /* If 2.x, convert format_spec to the same type as value */ + /* This is to allow things like u''.format('') */ + if (!PyArg_ParseTuple(args, "O:__format__", &format_spec)) + goto done; + if (!(PyString_Check(format_spec) || PyUnicode_Check(format_spec))) { + PyErr_Format(PyExc_TypeError, "__format__ arg must be str " + "or unicode, not %s", Py_TYPE(format_spec)->tp_name); + goto done; + } + tmp = STRINGLIB_TOSTR(format_spec); + if (tmp == NULL) goto done; + format_spec = tmp; +#endif /* check for the special case of zero length format spec, make it equivalent to str(value) */ @@ -777,6 +797,7 @@ FORMAT_STRING(PyObject* value, PyObject* args) goto done; } + /* parse the format_spec */ if (!parse_internal_render_format_spec(format_spec, &format, 's')) goto done; @@ -795,18 +816,24 @@ FORMAT_STRING(PyObject* value, PyObject* args) } done: +#if PY_VERSION_HEX < 0x03000000 + Py_XDECREF(tmp); +#endif return result; } +#endif /* FORMAT_STRING */ -PyObject * -FORMAT_LONG(PyObject* value, PyObject* args) +#if defined FORMAT_LONG || defined FORMAT_INT +static PyObject* +format_int_or_long(PyObject* value, PyObject* args, IntOrLongToString tostring) { PyObject *format_spec; PyObject *result = NULL; PyObject *tmp = NULL; InternalFormatSpec format; - if (!PyArg_ParseTuple(args, STRINGLIB_PARSE_CODE ":__format__", &format_spec)) + if (!PyArg_ParseTuple(args, STRINGLIB_PARSE_CODE ":__format__", + &format_spec)) goto done; /* check for the special case of zero length format spec, make @@ -828,8 +855,9 @@ FORMAT_LONG(PyObject* value, PyObject* args) case 'o': case 'x': case 'X': - /* no type conversion needed, already an int. do the formatting */ - result = format_long_internal(value, &format); + /* no type conversion needed, already an int (or long). do + the formatting */ + result = format_int_or_long_internal(value, &format, tostring); break; case 'e': @@ -858,7 +886,52 @@ done: Py_XDECREF(tmp); return result; } +#endif /* FORMAT_LONG || defined FORMAT_INT */ + +#ifdef FORMAT_LONG +/* Need to define long_format as a function that will convert a long + to a string. In 3.0, _PyLong_Format has the correct signature. In + 2.x, we need to fudge a few parameters */ +#if PY_VERSION_HEX >= 0x03000000 +#define long_format _PyLong_Format +#else +static PyObject* +long_format(PyObject* value, int base) +{ + /* Convert to base, don't add trailing 'L', and use the new octal + format. We already know this is a long object */ + assert(PyLong_Check(value)); + /* convert to base, don't add 'L', and use the new octal format */ + return _PyLong_Format(value, base, 0, 1); +} +#endif + +PyObject * +FORMAT_LONG(PyObject* value, PyObject* args) +{ + return format_int_or_long(value, args, long_format); +} +#endif /* FORMAT_LONG */ + +#ifdef FORMAT_INT +/* this is only used for 2.x, not 3.0 */ +static PyObject* +int_format(PyObject* value, int base) +{ + /* Convert to base, and use the new octal format. We already + know this is an int object */ + assert(PyInt_Check(value)); + return _PyInt_Format((PyIntObject*)value, base, 1); +} + +PyObject * +FORMAT_INT(PyObject* value, PyObject* args) +{ + return format_int_or_long(value, args, int_format); +} +#endif /* FORMAT_INT */ +#ifdef FORMAT_FLOAT PyObject * FORMAT_FLOAT(PyObject *value, PyObject *args) { @@ -904,3 +977,4 @@ FORMAT_FLOAT(PyObject *value, PyObject *args) done: return result; } +#endif /* FORMAT_FLOAT */ diff --git a/Objects/stringlib/string_format.h b/Objects/stringlib/string_format.h index 2c4510f..70f8f13 100644 --- a/Objects/stringlib/string_format.h +++ b/Objects/stringlib/string_format.h @@ -6,6 +6,11 @@ */ +/* Defines for Python 2.6 compatability */ +#if PY_VERSION_HEX < 0x03000000 +#define PyLong_FromSsize_t _PyLong_FromSsize_t +#endif + /* Defines for more efficiently reallocating the string buffer */ #define INITIAL_SIZE_INCREMENT 100 #define SIZE_MULTIPLIER 2 @@ -470,66 +475,6 @@ error: field object and field specification string generated by get_field_and_spec, and renders the field into the output string. - format() does the actual calling of the objects __format__ method. -*/ - - -/* returns fieldobj.__format__(format_spec) */ -static PyObject * -format(PyObject *fieldobj, SubString *format_spec) -{ - static PyObject *format_str = NULL; - PyObject *meth; - PyObject *spec = NULL; - PyObject *result = NULL; - - /* Initialize cached value */ - if (format_str == NULL) { - /* Initialize static variable needed by _PyType_Lookup */ - format_str = PyUnicode_FromString("__format__"); - if (format_str == NULL) - return NULL; - } - - /* Make sure the type is initialized. float gets initialized late */ - if (Py_TYPE(fieldobj)->tp_dict == NULL) - if (PyType_Ready(Py_TYPE(fieldobj)) < 0) - return NULL; - - /* we need to create an object out of the pointers we have */ - spec = SubString_new_object_or_empty(format_spec); - if (spec == NULL) - goto done; - - /* Find the (unbound!) __format__ method (a borrowed reference) */ - meth = _PyType_Lookup(Py_TYPE(fieldobj), format_str); - if (meth == NULL) { - PyErr_Format(PyExc_TypeError, - "Type %.100s doesn't define __format__", - Py_TYPE(fieldobj)->tp_name); - goto done; - } - - /* And call it, binding it to the value */ - result = PyObject_CallFunctionObjArgs(meth, fieldobj, spec, NULL); - if (result == NULL) - goto done; - - if (!STRINGLIB_CHECK(result)) { - PyErr_SetString(PyExc_TypeError, - "__format__ method did not return " - STRINGLIB_TYPE_NAME); - Py_DECREF(result); - result = NULL; - goto done; - } - -done: - Py_XDECREF(spec); - return result; -} - -/* render_field calls fieldobj.__format__(format_spec) method, and appends to the output. */ @@ -537,14 +482,21 @@ static int render_field(PyObject *fieldobj, SubString *format_spec, OutputString *output) { int ok = 0; - PyObject *result = format(fieldobj, format_spec); + PyObject *result = NULL; + /* we need to create an object out of the pointers we have */ + PyObject *format_spec_object = SubString_new_object_or_empty(format_spec); + if (format_spec_object == NULL) + goto done; + + result = PyObject_Format(fieldobj, format_spec_object); if (result == NULL) goto done; ok = output_data(output, STRINGLIB_STR(result), STRINGLIB_LEN(result)); done: + Py_DECREF(format_spec_object); Py_XDECREF(result); return ok; } @@ -770,7 +722,7 @@ do_conversion(PyObject *obj, STRINGLIB_CHAR conversion) case 'r': return PyObject_Repr(obj); case 's': - return PyObject_Str(obj); + return STRINGLIB_TOSTR(obj); default: PyErr_Format(PyExc_ValueError, "Unknown converion specifier %c", @@ -845,7 +797,7 @@ done: } /* - do_markup is the top-level loop for the format() function. It + do_markup is the top-level loop for the format() method. It searches through the format string for escapes to markup codes, and calls other functions to move non-markup text to the output, and to perform the markup to the output. @@ -958,7 +910,7 @@ do_string_format(PyObject *self, PyObject *args, PyObject *kwargs) typedef struct { PyObject_HEAD - PyUnicodeObject *str; + STRINGLIB_OBJECT *str; MarkupIterator it_markup; } formatteriterobject; @@ -984,7 +936,7 @@ formatteriter_next(formatteriterobject *it) SubString literal; SubString field_name; SubString format_spec; - Py_UNICODE conversion; + STRINGLIB_CHAR conversion; int format_spec_needs_expanding; int result = MarkupIterator_next(&it->it_markup, &literal, &field_name, &format_spec, &conversion, @@ -1028,7 +980,7 @@ formatteriter_next(formatteriterobject *it) Py_INCREF(conversion_str); } else - conversion_str = PyUnicode_FromUnicode(&conversion, 1); + conversion_str = STRINGLIB_NEW(&conversion, 1); if (conversion_str == NULL) goto done; @@ -1047,7 +999,7 @@ static PyMethodDef formatteriter_methods[] = { {NULL, NULL} /* sentinel */ }; -PyTypeObject PyFormatterIter_Type = { +static PyTypeObject PyFormatterIter_Type = { PyVarObject_HEAD_INIT(&PyType_Type, 0) "formatteriterator", /* tp_name */ sizeof(formatteriterobject), /* tp_basicsize */ @@ -1085,7 +1037,7 @@ PyTypeObject PyFormatterIter_Type = { describing the parsed elements. It's a wrapper around stringlib/string_format.h's MarkupIterator */ static PyObject * -formatter_parser(PyUnicodeObject *self) +formatter_parser(STRINGLIB_OBJECT *self) { formatteriterobject *it; @@ -1099,8 +1051,8 @@ formatter_parser(PyUnicodeObject *self) /* initialize the contained MarkupIterator */ MarkupIterator_init(&it->it_markup, - PyUnicode_AS_UNICODE(self), - PyUnicode_GET_SIZE(self)); + STRINGLIB_STR(self), + STRINGLIB_LEN(self)); return (PyObject *)it; } @@ -1118,7 +1070,7 @@ formatter_parser(PyUnicodeObject *self) typedef struct { PyObject_HEAD - PyUnicodeObject *str; + STRINGLIB_OBJECT *str; FieldNameIterator it_field; } fieldnameiterobject; @@ -1220,7 +1172,7 @@ static PyTypeObject PyFieldNameIter_Type = { field_name_split. The iterator it returns is a FieldNameIterator */ static PyObject * -formatter_field_name_split(PyUnicodeObject *self) +formatter_field_name_split(STRINGLIB_OBJECT *self) { SubString first; Py_ssize_t first_idx; diff --git a/Objects/stringlib/stringdefs.h b/Objects/stringlib/stringdefs.h index a4be17f..1e0df0f 100644 --- a/Objects/stringlib/stringdefs.h +++ b/Objects/stringlib/stringdefs.h @@ -6,12 +6,15 @@ compiled as unicode. */ #define STRINGLIB_IS_UNICODE 0 +#define STRINGLIB_OBJECT PyStringObject #define STRINGLIB_CHAR char #define STRINGLIB_TYPE_NAME "string" #define STRINGLIB_PARSE_CODE "S" -#define STRINGLIB_EMPTY string_empty +#define STRINGLIB_EMPTY nullstring #define STRINGLIB_ISDECIMAL(x) ((x >= '0') && (x <= '9')) #define STRINGLIB_TODECIMAL(x) (STRINGLIB_ISDECIMAL(x) ? (x - '0') : -1) +#define STRINGLIB_TOUPPER toupper +#define STRINGLIB_TOLOWER tolower #define STRINGLIB_FILL memset #define STRINGLIB_STR PyString_AS_STRING #define STRINGLIB_LEN PyString_GET_SIZE diff --git a/Objects/stringlib/unicodedefs.h b/Objects/stringlib/unicodedefs.h index 64777be..f402a98 100644 --- a/Objects/stringlib/unicodedefs.h +++ b/Objects/stringlib/unicodedefs.h @@ -6,6 +6,7 @@ compiled as unicode. */ #define STRINGLIB_IS_UNICODE 1 +#define STRINGLIB_OBJECT PyUnicodeObject #define STRINGLIB_CHAR Py_UNICODE #define STRINGLIB_TYPE_NAME "unicode" #define STRINGLIB_PARSE_CODE "U" @@ -20,7 +21,12 @@ #define STRINGLIB_NEW PyUnicode_FromUnicode #define STRINGLIB_RESIZE PyUnicode_Resize #define STRINGLIB_CHECK PyUnicode_Check + +#if PY_VERSION_HEX < 0x03000000 +#define STRINGLIB_TOSTR PyObject_Unicode +#else #define STRINGLIB_TOSTR PyObject_Str +#endif #define STRINGLIB_WANT_CONTAINS_OBJ 1 |