diff options
Diffstat (limited to 'Objects/stringlib')
-rw-r--r-- | Objects/stringlib/count.h | 9 | ||||
-rw-r--r-- | Objects/stringlib/eq.h | 23 | ||||
-rw-r--r-- | Objects/stringlib/fastsearch.h | 4 | ||||
-rw-r--r-- | Objects/stringlib/find.h | 31 | ||||
-rw-r--r-- | Objects/stringlib/formatter.h | 1516 | ||||
-rw-r--r-- | Objects/stringlib/localeutil.h | 27 | ||||
-rw-r--r-- | Objects/stringlib/partition.h | 12 | ||||
-rw-r--r-- | Objects/stringlib/split.h | 26 | ||||
-rw-r--r-- | Objects/stringlib/stringdefs.h | 2 | ||||
-rw-r--r-- | Objects/stringlib/ucs1lib.h | 35 | ||||
-rw-r--r-- | Objects/stringlib/ucs2lib.h | 34 | ||||
-rw-r--r-- | Objects/stringlib/ucs4lib.h | 34 | ||||
-rw-r--r-- | Objects/stringlib/undef.h | 10 | ||||
-rw-r--r-- | Objects/stringlib/unicode_format.h (renamed from Objects/stringlib/string_format.h) | 385 | ||||
-rw-r--r-- | Objects/stringlib/unicodedefs.h | 2 |
15 files changed, 386 insertions, 1764 deletions
diff --git a/Objects/stringlib/count.h b/Objects/stringlib/count.h index de34f96..f48500b 100644 --- a/Objects/stringlib/count.h +++ b/Objects/stringlib/count.h @@ -1,14 +1,11 @@ /* stringlib: count implementation */ -#ifndef STRINGLIB_COUNT_H -#define STRINGLIB_COUNT_H - #ifndef STRINGLIB_FASTSEARCH_H #error must include "stringlib/fastsearch.h" before including this module #endif Py_LOCAL_INLINE(Py_ssize_t) -stringlib_count(const STRINGLIB_CHAR* str, Py_ssize_t str_len, +STRINGLIB(count)(const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, Py_ssize_t maxcount) { @@ -19,7 +16,7 @@ stringlib_count(const STRINGLIB_CHAR* str, Py_ssize_t str_len, if (sub_len == 0) return (str_len < maxcount) ? str_len + 1 : maxcount; - count = fastsearch(str, str_len, sub, sub_len, maxcount, FAST_COUNT); + count = FASTSEARCH(str, str_len, sub, sub_len, maxcount, FAST_COUNT); if (count < 0) return 0; /* no match */ @@ -27,4 +24,4 @@ stringlib_count(const STRINGLIB_CHAR* str, Py_ssize_t str_len, return count; } -#endif + diff --git a/Objects/stringlib/eq.h b/Objects/stringlib/eq.h index 3e7f5e8..dd67128 100644 --- a/Objects/stringlib/eq.h +++ b/Objects/stringlib/eq.h @@ -9,13 +9,26 @@ unicode_eq(PyObject *aa, PyObject *bb) register PyUnicodeObject *a = (PyUnicodeObject *)aa; register PyUnicodeObject *b = (PyUnicodeObject *)bb; - if (a->length != b->length) + if (PyUnicode_READY(a) == -1 || PyUnicode_READY(b) == -1) { + assert(0 && "unicode_eq ready fail"); return 0; - if (a->length == 0) + } + + if (PyUnicode_GET_LENGTH(a) != PyUnicode_GET_LENGTH(b)) + return 0; + if (PyUnicode_GET_LENGTH(a) == 0) return 1; - if (a->str[0] != b->str[0]) + if (PyUnicode_KIND(a) != PyUnicode_KIND(b)) + return 0; + /* Just comparing the first byte is enough to see if a and b differ. + * If they are 2 byte or 4 byte character most differences will happen in + * the lower bytes anyways. + */ + if (PyUnicode_1BYTE_DATA(a)[0] != PyUnicode_1BYTE_DATA(b)[0]) return 0; - if (a->length == 1) + if (PyUnicode_KIND(a) == PyUnicode_1BYTE_KIND && + PyUnicode_GET_LENGTH(a) == 1) return 1; - return memcmp(a->str, b->str, a->length * sizeof(Py_UNICODE)) == 0; + return memcmp(PyUnicode_1BYTE_DATA(a), PyUnicode_1BYTE_DATA(b), + PyUnicode_GET_LENGTH(a) * PyUnicode_CHARACTER_SIZE(a)) == 0; } diff --git a/Objects/stringlib/fastsearch.h b/Objects/stringlib/fastsearch.h index e231c58..d35cba3 100644 --- a/Objects/stringlib/fastsearch.h +++ b/Objects/stringlib/fastsearch.h @@ -1,6 +1,5 @@ /* stringlib: fastsearch implementation */ -#ifndef STRINGLIB_FASTSEARCH_H #define STRINGLIB_FASTSEARCH_H /* fast search/count implementation, based on a mix between boyer- @@ -34,7 +33,7 @@ ((mask & (1UL << ((ch) & (STRINGLIB_BLOOM_WIDTH -1))))) Py_LOCAL_INLINE(Py_ssize_t) -fastsearch(const STRINGLIB_CHAR* s, Py_ssize_t n, +FASTSEARCH(const STRINGLIB_CHAR* s, Py_ssize_t n, const STRINGLIB_CHAR* p, Py_ssize_t m, Py_ssize_t maxcount, int mode) { @@ -157,4 +156,3 @@ fastsearch(const STRINGLIB_CHAR* s, Py_ssize_t n, return count; } -#endif diff --git a/Objects/stringlib/find.h b/Objects/stringlib/find.h index ce615dc..7cce156 100644 --- a/Objects/stringlib/find.h +++ b/Objects/stringlib/find.h @@ -1,14 +1,11 @@ /* stringlib: find/index implementation */ -#ifndef STRINGLIB_FIND_H -#define STRINGLIB_FIND_H - #ifndef STRINGLIB_FASTSEARCH_H #error must include "stringlib/fastsearch.h" before including this module #endif Py_LOCAL_INLINE(Py_ssize_t) -stringlib_find(const STRINGLIB_CHAR* str, Py_ssize_t str_len, +STRINGLIB(find)(const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, Py_ssize_t offset) { @@ -19,7 +16,7 @@ stringlib_find(const STRINGLIB_CHAR* str, Py_ssize_t str_len, if (sub_len == 0) return offset; - pos = fastsearch(str, str_len, sub, sub_len, -1, FAST_SEARCH); + pos = FASTSEARCH(str, str_len, sub, sub_len, -1, FAST_SEARCH); if (pos >= 0) pos += offset; @@ -28,7 +25,7 @@ stringlib_find(const STRINGLIB_CHAR* str, Py_ssize_t str_len, } Py_LOCAL_INLINE(Py_ssize_t) -stringlib_rfind(const STRINGLIB_CHAR* str, Py_ssize_t str_len, +STRINGLIB(rfind)(const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, Py_ssize_t offset) { @@ -39,7 +36,7 @@ stringlib_rfind(const STRINGLIB_CHAR* str, Py_ssize_t str_len, if (sub_len == 0) return str_len + offset; - pos = fastsearch(str, str_len, sub, sub_len, -1, FAST_RSEARCH); + pos = FASTSEARCH(str, str_len, sub, sub_len, -1, FAST_RSEARCH); if (pos >= 0) pos += offset; @@ -63,29 +60,29 @@ stringlib_rfind(const STRINGLIB_CHAR* str, Py_ssize_t str_len, } Py_LOCAL_INLINE(Py_ssize_t) -stringlib_find_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len, +STRINGLIB(find_slice)(const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, Py_ssize_t start, Py_ssize_t end) { ADJUST_INDICES(start, end, str_len); - return stringlib_find(str + start, end - start, sub, sub_len, start); + return STRINGLIB(find)(str + start, end - start, sub, sub_len, start); } Py_LOCAL_INLINE(Py_ssize_t) -stringlib_rfind_slice(const STRINGLIB_CHAR* str, Py_ssize_t str_len, +STRINGLIB(rfind_slice)(const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sub, Py_ssize_t sub_len, Py_ssize_t start, Py_ssize_t end) { ADJUST_INDICES(start, end, str_len); - return stringlib_rfind(str + start, end - start, sub, sub_len, start); + return STRINGLIB(rfind)(str + start, end - start, sub, sub_len, start); } #ifdef STRINGLIB_WANT_CONTAINS_OBJ Py_LOCAL_INLINE(int) -stringlib_contains_obj(PyObject* str, PyObject* sub) +STRINGLIB(contains_obj)(PyObject* str, PyObject* sub) { - return stringlib_find( + return STRINGLIB(find)( STRINGLIB_STR(str), STRINGLIB_LEN(str), STRINGLIB_STR(sub), STRINGLIB_LEN(sub), 0 ) != -1; @@ -105,7 +102,7 @@ is ok. #define FORMAT_BUFFER_SIZE 50 Py_LOCAL_INLINE(int) -stringlib_parse_args_finds(const char * function_name, PyObject *args, +STRINGLIB(parse_args_finds)(const char * function_name, PyObject *args, PyObject **subobj, Py_ssize_t *start, Py_ssize_t *end) { @@ -153,13 +150,13 @@ after finishing using the substring, must DECREF it). */ Py_LOCAL_INLINE(int) -stringlib_parse_args_finds_unicode(const char * function_name, PyObject *args, +STRINGLIB(parse_args_finds_unicode)(const char * function_name, PyObject *args, PyUnicodeObject **substring, Py_ssize_t *start, Py_ssize_t *end) { PyObject *tmp_substring; - if(stringlib_parse_args_finds(function_name, args, &tmp_substring, + if(STRINGLIB(parse_args_finds)(function_name, args, &tmp_substring, start, end)) { tmp_substring = PyUnicode_FromObject(tmp_substring); if (!tmp_substring) @@ -171,5 +168,3 @@ stringlib_parse_args_finds_unicode(const char * function_name, PyObject *args, } #endif /* STRINGLIB_IS_UNICODE */ - -#endif /* STRINGLIB_FIND_H */ diff --git a/Objects/stringlib/formatter.h b/Objects/stringlib/formatter.h deleted file mode 100644 index 139b56c..0000000 --- a/Objects/stringlib/formatter.h +++ /dev/null @@ -1,1516 +0,0 @@ -/* implements the string, long, and float formatters. that is, - string.__format__, etc. */ - -#include <locale.h> - -/* Before including this, you must include either: - stringlib/unicodedefs.h - stringlib/stringdefs.h - - Also, you should define the names: - FORMAT_STRING - FORMAT_LONG - FORMAT_FLOAT - FORMAT_COMPLEX - to be whatever you want the public names of these functions to - be. These are the only non-static functions defined here. -*/ - -/* Raises an exception about an unknown presentation type for this - * type. */ - -static void -unknown_presentation_type(STRINGLIB_CHAR presentation_type, - const char* type_name) -{ -#if STRINGLIB_IS_UNICODE - /* If STRINGLIB_CHAR is Py_UNICODE, %c might be out-of-range, - hence the two cases. If it is char, gcc complains that the - condition below is always true, hence the ifdef. */ - if (presentation_type > 32 && presentation_type < 128) -#endif - PyErr_Format(PyExc_ValueError, - "Unknown format code '%c' " - "for object of type '%.200s'", - (char)presentation_type, - type_name); -#if STRINGLIB_IS_UNICODE - else - PyErr_Format(PyExc_ValueError, - "Unknown format code '\\x%x' " - "for object of type '%.200s'", - (unsigned int)presentation_type, - type_name); -#endif -} - -static void -invalid_comma_type(STRINGLIB_CHAR presentation_type) -{ -#if STRINGLIB_IS_UNICODE - /* See comment in unknown_presentation_type */ - if (presentation_type > 32 && presentation_type < 128) -#endif - PyErr_Format(PyExc_ValueError, - "Cannot specify ',' with '%c'.", - (char)presentation_type); -#if STRINGLIB_IS_UNICODE - else - PyErr_Format(PyExc_ValueError, - "Cannot specify ',' with '\\x%x'.", - (unsigned int)presentation_type); -#endif -} - -/* - get_integer consumes 0 or more decimal digit characters from an - input string, updates *result with the corresponding positive - integer, and returns the number of digits consumed. - - returns -1 on error. -*/ -static int -get_integer(STRINGLIB_CHAR **ptr, STRINGLIB_CHAR *end, - Py_ssize_t *result) -{ - Py_ssize_t accumulator, digitval; - int numdigits; - accumulator = numdigits = 0; - for (;;(*ptr)++, numdigits++) { - if (*ptr >= end) - break; - digitval = STRINGLIB_TODECIMAL(**ptr); - if (digitval < 0) - break; - /* - Detect possible overflow before it happens: - - accumulator * 10 + digitval > PY_SSIZE_T_MAX if and only if - accumulator > (PY_SSIZE_T_MAX - digitval) / 10. - */ - if (accumulator > (PY_SSIZE_T_MAX - digitval) / 10) { - PyErr_Format(PyExc_ValueError, - "Too many decimal digits in format string"); - return -1; - } - accumulator = accumulator * 10 + digitval; - } - *result = accumulator; - return numdigits; -} - -/************************************************************************/ -/*********** standard format specifier parsing **************************/ -/************************************************************************/ - -/* returns true if this character is a specifier alignment token */ -Py_LOCAL_INLINE(int) -is_alignment_token(STRINGLIB_CHAR c) -{ - switch (c) { - case '<': case '>': case '=': case '^': - return 1; - default: - return 0; - } -} - -/* returns true if this character is a sign element */ -Py_LOCAL_INLINE(int) -is_sign_element(STRINGLIB_CHAR c) -{ - switch (c) { - case ' ': case '+': case '-': - return 1; - default: - return 0; - } -} - - -typedef struct { - STRINGLIB_CHAR fill_char; - STRINGLIB_CHAR align; - int alternate; - STRINGLIB_CHAR sign; - Py_ssize_t width; - int thousands_separators; - Py_ssize_t precision; - STRINGLIB_CHAR type; -} InternalFormatSpec; - - -#if 0 -/* Occassionally useful for debugging. Should normally be commented out. */ -static void -DEBUG_PRINT_FORMAT_SPEC(InternalFormatSpec *format) -{ - printf("internal format spec: fill_char %d\n", format->fill_char); - printf("internal format spec: align %d\n", format->align); - printf("internal format spec: alternate %d\n", format->alternate); - printf("internal format spec: sign %d\n", format->sign); - printf("internal format spec: width %zd\n", format->width); - printf("internal format spec: thousands_separators %d\n", - format->thousands_separators); - printf("internal format spec: precision %zd\n", format->precision); - printf("internal format spec: type %c\n", format->type); - printf("\n"); -} -#endif - - -/* - ptr points to the start of the format_spec, end points just past its end. - fills in format with the parsed information. - returns 1 on success, 0 on failure. - if failure, sets the exception -*/ -static int -parse_internal_render_format_spec(STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len, - InternalFormatSpec *format, - char default_type, - char default_align) -{ - STRINGLIB_CHAR *ptr = format_spec; - STRINGLIB_CHAR *end = format_spec + format_spec_len; - - /* end-ptr is used throughout this code to specify the length of - the input string */ - - Py_ssize_t consumed; - int align_specified = 0; - - format->fill_char = '\0'; - format->align = default_align; - format->alternate = 0; - format->sign = '\0'; - format->width = -1; - format->thousands_separators = 0; - format->precision = -1; - format->type = default_type; - - /* If the second char is an alignment token, - then parse the fill char */ - if (end-ptr >= 2 && is_alignment_token(ptr[1])) { - format->align = ptr[1]; - format->fill_char = ptr[0]; - align_specified = 1; - ptr += 2; - } - else if (end-ptr >= 1 && is_alignment_token(ptr[0])) { - format->align = ptr[0]; - align_specified = 1; - ++ptr; - } - - /* Parse the various sign options */ - if (end-ptr >= 1 && is_sign_element(ptr[0])) { - format->sign = ptr[0]; - ++ptr; - } - - /* If the next character is #, we're in alternate mode. This only - applies to integers. */ - if (end-ptr >= 1 && ptr[0] == '#') { - format->alternate = 1; - ++ptr; - } - - /* The special case for 0-padding (backwards compat) */ - if (format->fill_char == '\0' && end-ptr >= 1 && ptr[0] == '0') { - format->fill_char = '0'; - if (!align_specified) { - format->align = '='; - } - ++ptr; - } - - consumed = get_integer(&ptr, end, &format->width); - if (consumed == -1) - /* Overflow error. Exception already set. */ - return 0; - - /* If consumed is 0, we didn't consume any characters for the - width. In that case, reset the width to -1, because - get_integer() will have set it to zero. -1 is how we record - that the width wasn't specified. */ - if (consumed == 0) - format->width = -1; - - /* Comma signifies add thousands separators */ - if (end-ptr && ptr[0] == ',') { - format->thousands_separators = 1; - ++ptr; - } - - /* Parse field precision */ - if (end-ptr && ptr[0] == '.') { - ++ptr; - - consumed = get_integer(&ptr, end, &format->precision); - if (consumed == -1) - /* Overflow error. Exception already set. */ - return 0; - - /* Not having a precision after a dot is an error. */ - if (consumed == 0) { - PyErr_Format(PyExc_ValueError, - "Format specifier missing precision"); - return 0; - } - - } - - /* Finally, parse the type field. */ - - if (end-ptr > 1) { - /* More than one char remain, invalid conversion spec. */ - PyErr_Format(PyExc_ValueError, "Invalid conversion specification"); - return 0; - } - - if (end-ptr == 1) { - format->type = ptr[0]; - ++ptr; - } - - /* Do as much validating as we can, just by looking at the format - specifier. Do not take into account what type of formatting - we're doing (int, float, string). */ - - if (format->thousands_separators) { - switch (format->type) { - case 'd': - case 'e': - case 'f': - case 'g': - case 'E': - case 'G': - case '%': - case 'F': - case '\0': - /* These are allowed. See PEP 378.*/ - break; - default: - invalid_comma_type(format->type); - return 0; - } - } - - return 1; -} - -/* Calculate the padding needed. */ -static void -calc_padding(Py_ssize_t nchars, Py_ssize_t width, STRINGLIB_CHAR align, - Py_ssize_t *n_lpadding, Py_ssize_t *n_rpadding, - Py_ssize_t *n_total) -{ - if (width >= 0) { - if (nchars > width) - *n_total = nchars; - else - *n_total = width; - } - else { - /* not specified, use all of the chars and no more */ - *n_total = nchars; - } - - /* Figure out how much leading space we need, based on the - aligning */ - if (align == '>') - *n_lpadding = *n_total - nchars; - else if (align == '^') - *n_lpadding = (*n_total - nchars) / 2; - else if (align == '<' || align == '=') - *n_lpadding = 0; - else { - /* We should never have an unspecified alignment. */ - *n_lpadding = 0; - assert(0); - } - - *n_rpadding = *n_total - nchars - *n_lpadding; -} - -/* Do the padding, and return a pointer to where the caller-supplied - content goes. */ -static STRINGLIB_CHAR * -fill_padding(STRINGLIB_CHAR *p, Py_ssize_t nchars, STRINGLIB_CHAR fill_char, - Py_ssize_t n_lpadding, Py_ssize_t n_rpadding) -{ - /* Pad on left. */ - if (n_lpadding) - STRINGLIB_FILL(p, fill_char, n_lpadding); - - /* Pad on right. */ - if (n_rpadding) - STRINGLIB_FILL(p + nchars + n_lpadding, fill_char, n_rpadding); - - /* Pointer to the user content. */ - return p + n_lpadding; -} - -#if defined FORMAT_FLOAT || defined FORMAT_LONG || defined FORMAT_COMPLEX -/************************************************************************/ -/*********** common routines for numeric formatting *********************/ -/************************************************************************/ - -/* Locale type codes. */ -#define LT_CURRENT_LOCALE 0 -#define LT_DEFAULT_LOCALE 1 -#define LT_NO_LOCALE 2 - -/* Locale info needed for formatting integers and the part of floats - before and including the decimal. Note that locales only support - 8-bit chars, not unicode. */ -typedef struct { - char *decimal_point; - char *thousands_sep; - char *grouping; -} LocaleInfo; - -/* describes the layout for an integer, see the comment in - calc_number_widths() for details */ -typedef struct { - Py_ssize_t n_lpadding; - Py_ssize_t n_prefix; - Py_ssize_t n_spadding; - Py_ssize_t n_rpadding; - char sign; - Py_ssize_t n_sign; /* number of digits needed for sign (0/1) */ - Py_ssize_t n_grouped_digits; /* Space taken up by the digits, including - any grouping chars. */ - Py_ssize_t n_decimal; /* 0 if only an integer */ - Py_ssize_t n_remainder; /* Digits in decimal and/or exponent part, - excluding the decimal itself, if - present. */ - - /* These 2 are not the widths of fields, but are needed by - STRINGLIB_GROUPING. */ - Py_ssize_t n_digits; /* The number of digits before a decimal - or exponent. */ - Py_ssize_t n_min_width; /* The min_width we used when we computed - the n_grouped_digits width. */ -} NumberFieldWidths; - - -/* Given a number of the form: - digits[remainder] - where ptr points to the start and end points to the end, find where - the integer part ends. This could be a decimal, an exponent, both, - or neither. - If a decimal point is present, set *has_decimal and increment - remainder beyond it. - Results are undefined (but shouldn't crash) for improperly - formatted strings. -*/ -static void -parse_number(STRINGLIB_CHAR *ptr, Py_ssize_t len, - Py_ssize_t *n_remainder, int *has_decimal) -{ - STRINGLIB_CHAR *end = ptr + len; - STRINGLIB_CHAR *remainder; - - while (ptr<end && isdigit(*ptr)) - ++ptr; - remainder = ptr; - - /* Does remainder start with a decimal point? */ - *has_decimal = ptr<end && *remainder == '.'; - - /* Skip the decimal point. */ - if (*has_decimal) - remainder++; - - *n_remainder = end - remainder; -} - -/* not all fields of format are used. for example, precision is - unused. should this take discrete params in order to be more clear - about what it does? or is passing a single format parameter easier - and more efficient enough to justify a little obfuscation? */ -static Py_ssize_t -calc_number_widths(NumberFieldWidths *spec, Py_ssize_t n_prefix, - STRINGLIB_CHAR sign_char, STRINGLIB_CHAR *number, - Py_ssize_t n_number, Py_ssize_t n_remainder, - int has_decimal, const LocaleInfo *locale, - const InternalFormatSpec *format) -{ - Py_ssize_t n_non_digit_non_padding; - Py_ssize_t n_padding; - - spec->n_digits = n_number - n_remainder - (has_decimal?1:0); - spec->n_lpadding = 0; - spec->n_prefix = n_prefix; - spec->n_decimal = has_decimal ? strlen(locale->decimal_point) : 0; - spec->n_remainder = n_remainder; - spec->n_spadding = 0; - spec->n_rpadding = 0; - spec->sign = '\0'; - spec->n_sign = 0; - - /* the output will look like: - | | - | <lpadding> <sign> <prefix> <spadding> <grouped_digits> <decimal> <remainder> <rpadding> | - | | - - sign is computed from format->sign and the actual - sign of the number - - prefix is given (it's for the '0x' prefix) - - digits is already known - - the total width is either given, or computed from the - actual digits - - only one of lpadding, spadding, and rpadding can be non-zero, - and it's calculated from the width and other fields - */ - - /* compute the various parts we're going to write */ - switch (format->sign) { - case '+': - /* always put a + or - */ - spec->n_sign = 1; - spec->sign = (sign_char == '-' ? '-' : '+'); - break; - case ' ': - spec->n_sign = 1; - spec->sign = (sign_char == '-' ? '-' : ' '); - break; - default: - /* Not specified, or the default (-) */ - if (sign_char == '-') { - spec->n_sign = 1; - spec->sign = '-'; - } - } - - /* The number of chars used for non-digits and non-padding. */ - n_non_digit_non_padding = spec->n_sign + spec->n_prefix + spec->n_decimal + - spec->n_remainder; - - /* min_width can go negative, that's okay. format->width == -1 means - we don't care. */ - if (format->fill_char == '0' && format->align == '=') - spec->n_min_width = format->width - n_non_digit_non_padding; - else - spec->n_min_width = 0; - - if (spec->n_digits == 0) - /* This case only occurs when using 'c' formatting, we need - to special case it because the grouping code always wants - to have at least one character. */ - spec->n_grouped_digits = 0; - else - spec->n_grouped_digits = STRINGLIB_GROUPING(NULL, 0, NULL, - spec->n_digits, - spec->n_min_width, - locale->grouping, - locale->thousands_sep); - - /* Given the desired width and the total of digit and non-digit - space we consume, see if we need any padding. format->width can - be negative (meaning no padding), but this code still works in - that case. */ - n_padding = format->width - - (n_non_digit_non_padding + spec->n_grouped_digits); - if (n_padding > 0) { - /* Some padding is needed. Determine if it's left, space, or right. */ - switch (format->align) { - case '<': - spec->n_rpadding = n_padding; - break; - case '^': - spec->n_lpadding = n_padding / 2; - spec->n_rpadding = n_padding - spec->n_lpadding; - break; - case '=': - spec->n_spadding = n_padding; - break; - case '>': - spec->n_lpadding = n_padding; - break; - default: - /* Shouldn't get here, but treat it as '>' */ - spec->n_lpadding = n_padding; - assert(0); - break; - } - } - return spec->n_lpadding + spec->n_sign + spec->n_prefix + - spec->n_spadding + spec->n_grouped_digits + spec->n_decimal + - spec->n_remainder + spec->n_rpadding; -} - -/* Fill in the digit parts of a numbers's string representation, - as determined in calc_number_widths(). - No error checking, since we know the buffer is the correct size. */ -static void -fill_number(STRINGLIB_CHAR *buf, const NumberFieldWidths *spec, - STRINGLIB_CHAR *digits, Py_ssize_t n_digits, - STRINGLIB_CHAR *prefix, STRINGLIB_CHAR fill_char, - LocaleInfo *locale, int toupper) -{ - /* Used to keep track of digits, decimal, and remainder. */ - STRINGLIB_CHAR *p = digits; - -#ifndef NDEBUG - Py_ssize_t r; -#endif - - if (spec->n_lpadding) { - STRINGLIB_FILL(buf, fill_char, spec->n_lpadding); - buf += spec->n_lpadding; - } - if (spec->n_sign == 1) { - *buf++ = spec->sign; - } - if (spec->n_prefix) { - memmove(buf, - prefix, - spec->n_prefix * sizeof(STRINGLIB_CHAR)); - if (toupper) { - Py_ssize_t t; - for (t = 0; t < spec->n_prefix; ++t) - buf[t] = STRINGLIB_TOUPPER(buf[t]); - } - buf += spec->n_prefix; - } - if (spec->n_spadding) { - STRINGLIB_FILL(buf, fill_char, spec->n_spadding); - buf += spec->n_spadding; - } - - /* Only for type 'c' special case, it has no digits. */ - if (spec->n_digits != 0) { - /* Fill the digits with InsertThousandsGrouping. */ -#ifndef NDEBUG - r = -#endif - STRINGLIB_GROUPING(buf, spec->n_grouped_digits, digits, - spec->n_digits, spec->n_min_width, - locale->grouping, locale->thousands_sep); -#ifndef NDEBUG - assert(r == spec->n_grouped_digits); -#endif - p += spec->n_digits; - } - if (toupper) { - Py_ssize_t t; - for (t = 0; t < spec->n_grouped_digits; ++t) - buf[t] = STRINGLIB_TOUPPER(buf[t]); - } - buf += spec->n_grouped_digits; - - if (spec->n_decimal) { - Py_ssize_t t; - for (t = 0; t < spec->n_decimal; ++t) - buf[t] = locale->decimal_point[t]; - buf += spec->n_decimal; - p += 1; - } - - if (spec->n_remainder) { - memcpy(buf, p, spec->n_remainder * sizeof(STRINGLIB_CHAR)); - buf += spec->n_remainder; - p += spec->n_remainder; - } - - if (spec->n_rpadding) { - STRINGLIB_FILL(buf, fill_char, spec->n_rpadding); - buf += spec->n_rpadding; - } -} - -static char no_grouping[1] = {CHAR_MAX}; - -/* Find the decimal point character(s?), thousands_separator(s?), and - grouping description, either for the current locale if type is - LT_CURRENT_LOCALE, a hard-coded locale if LT_DEFAULT_LOCALE, or - none if LT_NO_LOCALE. */ -static void -get_locale_info(int type, LocaleInfo *locale_info) -{ - switch (type) { - case LT_CURRENT_LOCALE: { - struct lconv *locale_data = localeconv(); - locale_info->decimal_point = locale_data->decimal_point; - locale_info->thousands_sep = locale_data->thousands_sep; - locale_info->grouping = locale_data->grouping; - break; - } - case LT_DEFAULT_LOCALE: - locale_info->decimal_point = "."; - locale_info->thousands_sep = ","; - locale_info->grouping = "\3"; /* Group every 3 characters. The - (implicit) trailing 0 means repeat - infinitely. */ - break; - case LT_NO_LOCALE: - locale_info->decimal_point = "."; - locale_info->thousands_sep = ""; - locale_info->grouping = no_grouping; - break; - default: - assert(0); - } -} - -#endif /* FORMAT_FLOAT || FORMAT_LONG || FORMAT_COMPLEX */ - -/************************************************************************/ -/*********** string formatting ******************************************/ -/************************************************************************/ - -static PyObject * -format_string_internal(PyObject *value, const InternalFormatSpec *format) -{ - Py_ssize_t lpad; - Py_ssize_t rpad; - Py_ssize_t total; - STRINGLIB_CHAR *p; - Py_ssize_t len = STRINGLIB_LEN(value); - PyObject *result = NULL; - - /* sign is not allowed on strings */ - if (format->sign != '\0') { - PyErr_SetString(PyExc_ValueError, - "Sign not allowed in string format specifier"); - goto done; - } - - /* alternate is not allowed on strings */ - if (format->alternate) { - PyErr_SetString(PyExc_ValueError, - "Alternate form (#) not allowed in string format " - "specifier"); - goto done; - } - - /* '=' alignment not allowed on strings */ - if (format->align == '=') { - PyErr_SetString(PyExc_ValueError, - "'=' alignment not allowed " - "in string format specifier"); - goto done; - } - - /* if precision is specified, output no more that format.precision - characters */ - if (format->precision >= 0 && len >= format->precision) { - len = format->precision; - } - - calc_padding(len, format->width, format->align, &lpad, &rpad, &total); - - /* allocate the resulting string */ - result = STRINGLIB_NEW(NULL, total); - if (result == NULL) - goto done; - - /* Write into that space. First the padding. */ - p = fill_padding(STRINGLIB_STR(result), len, - format->fill_char=='\0'?' ':format->fill_char, - lpad, rpad); - - /* Then the source string. */ - memcpy(p, STRINGLIB_STR(value), len * sizeof(STRINGLIB_CHAR)); - -done: - return result; -} - - -/************************************************************************/ -/*********** long formatting ********************************************/ -/************************************************************************/ - -#if defined FORMAT_LONG || defined FORMAT_INT -typedef PyObject* -(*IntOrLongToString)(PyObject *value, int base); - -static PyObject * -format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format, - IntOrLongToString tostring) -{ - PyObject *result = NULL; - PyObject *tmp = NULL; - STRINGLIB_CHAR *pnumeric_chars; - STRINGLIB_CHAR numeric_char; - STRINGLIB_CHAR sign_char = '\0'; - Py_ssize_t n_digits; /* count of digits need from the computed - string */ - Py_ssize_t n_remainder = 0; /* Used only for 'c' formatting, which - produces non-digits */ - Py_ssize_t n_prefix = 0; /* Count of prefix chars, (e.g., '0x') */ - Py_ssize_t n_total; - STRINGLIB_CHAR *prefix = NULL; - NumberFieldWidths spec; - long x; - - /* Locale settings, either from the actual locale or - from a hard-code pseudo-locale */ - LocaleInfo locale; - - /* no precision allowed on integers */ - if (format->precision != -1) { - PyErr_SetString(PyExc_ValueError, - "Precision not allowed in integer format specifier"); - goto done; - } - - /* special case for character formatting */ - if (format->type == 'c') { - /* error to specify a sign */ - if (format->sign != '\0') { - PyErr_SetString(PyExc_ValueError, - "Sign not allowed with integer" - " format specifier 'c'"); - goto done; - } - - /* 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; -#ifdef Py_UNICODE_WIDE - if (x < 0 || x > 0x10ffff) { - PyErr_SetString(PyExc_OverflowError, - "%c arg not in range(0x110000) " - "(wide Python build)"); - goto done; - } -#else - if (x < 0 || x > 0xffff) { - PyErr_SetString(PyExc_OverflowError, - "%c arg not in range(0x10000) " - "(narrow Python build)"); - goto done; - } -#endif - numeric_char = (STRINGLIB_CHAR)x; - pnumeric_chars = &numeric_char; - n_digits = 1; - - /* As a sort-of hack, we tell calc_number_widths that we only - have "remainder" characters. calc_number_widths thinks - these are characters that don't get formatted, only copied - into the output string. We do this for 'c' formatting, - because the characters are likely to be non-digits. */ - n_remainder = 1; - } - else { - int base; - int leading_chars_to_skip = 0; /* 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; - leading_chars_to_skip = 2; /* 0b */ - break; - case 'o': - base = 8; - leading_chars_to_skip = 2; /* 0o */ - break; - case 'x': - case 'X': - base = 16; - leading_chars_to_skip = 2; /* 0x */ - break; - default: /* shouldn't be needed, but stops a compiler warning */ - case 'd': - case 'n': - base = 10; - break; - } - - /* The number of prefix chars is the same as the leading - chars to skip */ - if (format->alternate) - n_prefix = leading_chars_to_skip; - - /* Do the hard part, converting to a string in a given base */ - tmp = tostring(value, base); - if (tmp == NULL) - goto done; - - pnumeric_chars = STRINGLIB_STR(tmp); - n_digits = STRINGLIB_LEN(tmp); - - prefix = pnumeric_chars; - - /* 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 - and skip it */ - if (pnumeric_chars[0] == '-') { - sign_char = pnumeric_chars[0]; - ++prefix; - ++leading_chars_to_skip; - } - - /* Skip over the leading chars (0x, 0b, etc.) */ - n_digits -= leading_chars_to_skip; - pnumeric_chars += leading_chars_to_skip; - } - - /* Determine the grouping, separator, and decimal point, if any. */ - get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : - (format->thousands_separators ? - LT_DEFAULT_LOCALE : - LT_NO_LOCALE), - &locale); - - /* Calculate how much memory we'll need. */ - n_total = calc_number_widths(&spec, n_prefix, sign_char, pnumeric_chars, - n_digits, n_remainder, 0, &locale, format); - - /* Allocate the memory. */ - result = STRINGLIB_NEW(NULL, n_total); - if (!result) - goto done; - - /* Populate the memory. */ - fill_number(STRINGLIB_STR(result), &spec, pnumeric_chars, n_digits, - prefix, format->fill_char == '\0' ? ' ' : format->fill_char, - &locale, format->type == 'X'); - -done: - Py_XDECREF(tmp); - return result; -} -#endif /* defined FORMAT_LONG || defined FORMAT_INT */ - -/************************************************************************/ -/*********** float formatting *******************************************/ -/************************************************************************/ - -#ifdef FORMAT_FLOAT -#if STRINGLIB_IS_UNICODE -static void -strtounicode(Py_UNICODE *buffer, const char *charbuffer, Py_ssize_t len) -{ - Py_ssize_t i; - for (i = 0; i < len; ++i) - buffer[i] = (Py_UNICODE)charbuffer[i]; -} -#endif - -/* much of this is taken from unicodeobject.c */ -static PyObject * -format_float_internal(PyObject *value, - const InternalFormatSpec *format) -{ - char *buf = NULL; /* buffer returned from PyOS_double_to_string */ - Py_ssize_t n_digits; - Py_ssize_t n_remainder; - Py_ssize_t n_total; - int has_decimal; - double val; - Py_ssize_t precision = format->precision; - Py_ssize_t default_precision = 6; - STRINGLIB_CHAR type = format->type; - int add_pct = 0; - STRINGLIB_CHAR *p; - NumberFieldWidths spec; - int flags = 0; - PyObject *result = NULL; - STRINGLIB_CHAR sign_char = '\0'; - int float_type; /* Used to see if we have a nan, inf, or regular float. */ - -#if STRINGLIB_IS_UNICODE - Py_UNICODE *unicode_tmp = NULL; -#endif - - /* Locale settings, either from the actual locale or - from a hard-code pseudo-locale */ - LocaleInfo locale; - - if (format->alternate) - flags |= Py_DTSF_ALT; - - if (type == '\0') { - /* Omitted type specifier. Behaves in the same way as repr(x) - and str(x) if no precision is given, else like 'g', but with - at least one digit after the decimal point. */ - flags |= Py_DTSF_ADD_DOT_0; - type = 'r'; - default_precision = 0; - } - - if (type == 'n') - /* 'n' is the same as 'g', except for the locale used to - format the result. We take care of that later. */ - type = 'g'; - - val = PyFloat_AsDouble(value); - if (val == -1.0 && PyErr_Occurred()) - goto done; - - if (type == '%') { - type = 'f'; - val *= 100; - add_pct = 1; - } - - if (precision < 0) - precision = default_precision; - else if (type == 'r') - type = 'g'; - - /* 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. */ - buf = PyOS_double_to_string(val, (char)type, precision, flags, - &float_type); - if (buf == NULL) - goto done; - n_digits = strlen(buf); - - if (add_pct) { - /* We know that buf has a trailing zero (since we just called - strlen() on it), and we don't use that fact any more. So we - can just write over the trailing zero. */ - buf[n_digits] = '%'; - n_digits += 1; - } - - /* Since there is no unicode version of PyOS_double_to_string, - just use the 8 bit version and then convert to unicode. */ -#if STRINGLIB_IS_UNICODE - unicode_tmp = (Py_UNICODE*)PyMem_Malloc((n_digits)*sizeof(Py_UNICODE)); - if (unicode_tmp == NULL) { - PyErr_NoMemory(); - goto done; - } - strtounicode(unicode_tmp, buf, n_digits); - p = unicode_tmp; -#else - p = buf; -#endif - - /* Is a sign character present in the output? If so, remember it - and skip it */ - if (*p == '-') { - sign_char = *p; - ++p; - --n_digits; - } - - /* Determine if we have any "remainder" (after the digits, might include - decimal or exponent or both (or neither)) */ - parse_number(p, n_digits, &n_remainder, &has_decimal); - - /* Determine the grouping, separator, and decimal point, if any. */ - get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : - (format->thousands_separators ? - LT_DEFAULT_LOCALE : - LT_NO_LOCALE), - &locale); - - /* Calculate how much memory we'll need. */ - n_total = calc_number_widths(&spec, 0, sign_char, p, n_digits, - n_remainder, has_decimal, &locale, format); - - /* Allocate the memory. */ - result = STRINGLIB_NEW(NULL, n_total); - if (result == NULL) - goto done; - - /* Populate the memory. */ - fill_number(STRINGLIB_STR(result), &spec, p, n_digits, NULL, - format->fill_char == '\0' ? ' ' : format->fill_char, &locale, - 0); - -done: - PyMem_Free(buf); -#if STRINGLIB_IS_UNICODE - PyMem_Free(unicode_tmp); -#endif - return result; -} -#endif /* FORMAT_FLOAT */ - -/************************************************************************/ -/*********** complex formatting *****************************************/ -/************************************************************************/ - -#ifdef FORMAT_COMPLEX - -static PyObject * -format_complex_internal(PyObject *value, - const InternalFormatSpec *format) -{ - double re; - double im; - char *re_buf = NULL; /* buffer returned from PyOS_double_to_string */ - char *im_buf = NULL; /* buffer returned from PyOS_double_to_string */ - - InternalFormatSpec tmp_format = *format; - Py_ssize_t n_re_digits; - Py_ssize_t n_im_digits; - Py_ssize_t n_re_remainder; - Py_ssize_t n_im_remainder; - Py_ssize_t n_re_total; - Py_ssize_t n_im_total; - int re_has_decimal; - int im_has_decimal; - Py_ssize_t precision = format->precision; - Py_ssize_t default_precision = 6; - STRINGLIB_CHAR type = format->type; - STRINGLIB_CHAR *p_re; - STRINGLIB_CHAR *p_im; - NumberFieldWidths re_spec; - NumberFieldWidths im_spec; - int flags = 0; - PyObject *result = NULL; - STRINGLIB_CHAR *p; - STRINGLIB_CHAR re_sign_char = '\0'; - STRINGLIB_CHAR im_sign_char = '\0'; - int re_float_type; /* Used to see if we have a nan, inf, or regular float. */ - int im_float_type; - int add_parens = 0; - int skip_re = 0; - Py_ssize_t lpad; - Py_ssize_t rpad; - Py_ssize_t total; - -#if STRINGLIB_IS_UNICODE - Py_UNICODE *re_unicode_tmp = NULL; - Py_UNICODE *im_unicode_tmp = NULL; -#endif - - /* Locale settings, either from the actual locale or - from a hard-code pseudo-locale */ - LocaleInfo locale; - - /* Zero padding is not allowed. */ - if (format->fill_char == '0') { - PyErr_SetString(PyExc_ValueError, - "Zero padding is not allowed in complex format " - "specifier"); - goto done; - } - - /* Neither is '=' alignment . */ - if (format->align == '=') { - PyErr_SetString(PyExc_ValueError, - "'=' alignment flag is not allowed in complex format " - "specifier"); - goto done; - } - - re = PyComplex_RealAsDouble(value); - if (re == -1.0 && PyErr_Occurred()) - goto done; - im = PyComplex_ImagAsDouble(value); - if (im == -1.0 && PyErr_Occurred()) - goto done; - - if (format->alternate) - flags |= Py_DTSF_ALT; - - if (type == '\0') { - /* Omitted type specifier. Should be like str(self). */ - type = 'r'; - default_precision = 0; - if (re == 0.0 && copysign(1.0, re) == 1.0) - skip_re = 1; - else - add_parens = 1; - } - - if (type == 'n') - /* 'n' is the same as 'g', except for the locale used to - format the result. We take care of that later. */ - type = 'g'; - - if (precision < 0) - precision = default_precision; - else if (type == 'r') - type = 'g'; - - /* 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. */ - re_buf = PyOS_double_to_string(re, (char)type, precision, flags, - &re_float_type); - if (re_buf == NULL) - goto done; - im_buf = PyOS_double_to_string(im, (char)type, precision, flags, - &im_float_type); - if (im_buf == NULL) - goto done; - - n_re_digits = strlen(re_buf); - n_im_digits = strlen(im_buf); - - /* Since there is no unicode version of PyOS_double_to_string, - just use the 8 bit version and then convert to unicode. */ -#if STRINGLIB_IS_UNICODE - re_unicode_tmp = (Py_UNICODE*)PyMem_Malloc((n_re_digits)*sizeof(Py_UNICODE)); - if (re_unicode_tmp == NULL) { - PyErr_NoMemory(); - goto done; - } - strtounicode(re_unicode_tmp, re_buf, n_re_digits); - p_re = re_unicode_tmp; - - im_unicode_tmp = (Py_UNICODE*)PyMem_Malloc((n_im_digits)*sizeof(Py_UNICODE)); - if (im_unicode_tmp == NULL) { - PyErr_NoMemory(); - goto done; - } - strtounicode(im_unicode_tmp, im_buf, n_im_digits); - p_im = im_unicode_tmp; -#else - p_re = re_buf; - p_im = im_buf; -#endif - - /* Is a sign character present in the output? If so, remember it - and skip it */ - if (*p_re == '-') { - re_sign_char = *p_re; - ++p_re; - --n_re_digits; - } - if (*p_im == '-') { - im_sign_char = *p_im; - ++p_im; - --n_im_digits; - } - - /* Determine if we have any "remainder" (after the digits, might include - decimal or exponent or both (or neither)) */ - parse_number(p_re, n_re_digits, &n_re_remainder, &re_has_decimal); - parse_number(p_im, n_im_digits, &n_im_remainder, &im_has_decimal); - - /* Determine the grouping, separator, and decimal point, if any. */ - get_locale_info(format->type == 'n' ? LT_CURRENT_LOCALE : - (format->thousands_separators ? - LT_DEFAULT_LOCALE : - LT_NO_LOCALE), - &locale); - - /* Turn off any padding. We'll do it later after we've composed - the numbers without padding. */ - tmp_format.fill_char = '\0'; - tmp_format.align = '<'; - tmp_format.width = -1; - - /* Calculate how much memory we'll need. */ - n_re_total = calc_number_widths(&re_spec, 0, re_sign_char, p_re, - n_re_digits, n_re_remainder, - re_has_decimal, &locale, &tmp_format); - - /* Same formatting, but always include a sign, unless the real part is - * going to be omitted, in which case we use whatever sign convention was - * requested by the original format. */ - if (!skip_re) - tmp_format.sign = '+'; - n_im_total = calc_number_widths(&im_spec, 0, im_sign_char, p_im, - n_im_digits, n_im_remainder, - im_has_decimal, &locale, &tmp_format); - - if (skip_re) - n_re_total = 0; - - /* Add 1 for the 'j', and optionally 2 for parens. */ - calc_padding(n_re_total + n_im_total + 1 + add_parens * 2, - format->width, format->align, &lpad, &rpad, &total); - - result = STRINGLIB_NEW(NULL, total); - if (result == NULL) - goto done; - - /* Populate the memory. First, the padding. */ - p = fill_padding(STRINGLIB_STR(result), - n_re_total + n_im_total + 1 + add_parens * 2, - format->fill_char=='\0' ? ' ' : format->fill_char, - lpad, rpad); - - if (add_parens) - *p++ = '('; - - if (!skip_re) { - fill_number(p, &re_spec, p_re, n_re_digits, NULL, 0, &locale, 0); - p += n_re_total; - } - fill_number(p, &im_spec, p_im, n_im_digits, NULL, 0, &locale, 0); - p += n_im_total; - *p++ = 'j'; - - if (add_parens) - *p++ = ')'; - -done: - PyMem_Free(re_buf); - PyMem_Free(im_buf); -#if STRINGLIB_IS_UNICODE - PyMem_Free(re_unicode_tmp); - PyMem_Free(im_unicode_tmp); -#endif - return result; -} -#endif /* FORMAT_COMPLEX */ - -/************************************************************************/ -/*********** built in formatters ****************************************/ -/************************************************************************/ -PyObject * -FORMAT_STRING(PyObject *obj, - STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len) -{ - InternalFormatSpec format; - PyObject *result = NULL; - - /* check for the special case of zero length format spec, make - it equivalent to str(obj) */ - if (format_spec_len == 0) { - result = STRINGLIB_TOSTR(obj); - goto done; - } - - /* parse the format_spec */ - if (!parse_internal_render_format_spec(format_spec, format_spec_len, - &format, 's', '<')) - goto done; - - /* type conversion? */ - switch (format.type) { - case 's': - /* no type conversion needed, already a string. do the formatting */ - result = format_string_internal(obj, &format); - break; - default: - /* unknown */ - unknown_presentation_type(format.type, obj->ob_type->tp_name); - goto done; - } - -done: - return result; -} - -#if defined FORMAT_LONG || defined FORMAT_INT -static PyObject* -format_int_or_long(PyObject* obj, - STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len, - IntOrLongToString tostring) -{ - PyObject *result = NULL; - PyObject *tmp = NULL; - InternalFormatSpec format; - - /* check for the special case of zero length format spec, make - it equivalent to str(obj) */ - if (format_spec_len == 0) { - result = STRINGLIB_TOSTR(obj); - goto done; - } - - /* parse the format_spec */ - if (!parse_internal_render_format_spec(format_spec, - format_spec_len, - &format, 'd', '>')) - goto done; - - /* type conversion? */ - switch (format.type) { - case 'b': - case 'c': - case 'd': - case 'o': - case 'x': - case 'X': - case 'n': - /* no type conversion needed, already an int (or long). do - the formatting */ - result = format_int_or_long_internal(obj, &format, tostring); - break; - - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - case '%': - /* convert to float */ - tmp = PyNumber_Float(obj); - if (tmp == NULL) - goto done; - result = format_float_internal(tmp, &format); - break; - - default: - /* unknown */ - unknown_presentation_type(format.type, obj->ob_type->tp_name); - goto done; - } - -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 *obj, - STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len) -{ - return format_int_or_long(obj, format_spec, format_spec_len, - 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 *obj, - STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len) -{ - return format_int_or_long(obj, format_spec, format_spec_len, - int_format); -} -#endif /* FORMAT_INT */ - -#ifdef FORMAT_FLOAT -PyObject * -FORMAT_FLOAT(PyObject *obj, - STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len) -{ - PyObject *result = NULL; - InternalFormatSpec format; - - /* check for the special case of zero length format spec, make - it equivalent to str(obj) */ - if (format_spec_len == 0) { - result = STRINGLIB_TOSTR(obj); - goto done; - } - - /* parse the format_spec */ - if (!parse_internal_render_format_spec(format_spec, - format_spec_len, - &format, '\0', '>')) - goto done; - - /* type conversion? */ - switch (format.type) { - case '\0': /* No format code: like 'g', but with at least one decimal. */ - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - case 'n': - case '%': - /* no conversion, already a float. do the formatting */ - result = format_float_internal(obj, &format); - break; - - default: - /* unknown */ - unknown_presentation_type(format.type, obj->ob_type->tp_name); - goto done; - } - -done: - return result; -} -#endif /* FORMAT_FLOAT */ - -#ifdef FORMAT_COMPLEX -PyObject * -FORMAT_COMPLEX(PyObject *obj, - STRINGLIB_CHAR *format_spec, - Py_ssize_t format_spec_len) -{ - PyObject *result = NULL; - InternalFormatSpec format; - - /* check for the special case of zero length format spec, make - it equivalent to str(obj) */ - if (format_spec_len == 0) { - result = STRINGLIB_TOSTR(obj); - goto done; - } - - /* parse the format_spec */ - if (!parse_internal_render_format_spec(format_spec, - format_spec_len, - &format, '\0', '>')) - goto done; - - /* type conversion? */ - switch (format.type) { - case '\0': /* No format code: like 'g', but with at least one decimal. */ - case 'e': - case 'E': - case 'f': - case 'F': - case 'g': - case 'G': - case 'n': - /* no conversion, already a complex. do the formatting */ - result = format_complex_internal(obj, &format); - break; - - default: - /* unknown */ - unknown_presentation_type(format.type, obj->ob_type->tp_name); - goto done; - } - -done: - return result; -} -#endif /* FORMAT_COMPLEX */ diff --git a/Objects/stringlib/localeutil.h b/Objects/stringlib/localeutil.h index f548133..ddce69d 100644 --- a/Objects/stringlib/localeutil.h +++ b/Objects/stringlib/localeutil.h @@ -1,8 +1,5 @@ /* stringlib: locale related helpers implementation */ -#ifndef STRINGLIB_LOCALEUTIL_H -#define STRINGLIB_LOCALEUTIL_H - #include <locale.h> #define MAX(x, y) ((x) < (y) ? (y) : (x)) @@ -12,10 +9,10 @@ typedef struct { const char *grouping; char previous; Py_ssize_t i; /* Where we're currently pointing in grouping. */ -} GroupGenerator; +} STRINGLIB(GroupGenerator); static void -_GroupGenerator_init(GroupGenerator *self, const char *grouping) +STRINGLIB(GroupGenerator_init)(STRINGLIB(GroupGenerator) *self, const char *grouping) { self->grouping = grouping; self->i = 0; @@ -24,7 +21,7 @@ _GroupGenerator_init(GroupGenerator *self, const char *grouping) /* Returns the next grouping, or 0 to signify end. */ static Py_ssize_t -_GroupGenerator_next(GroupGenerator *self) +STRINGLIB(GroupGenerator_next)(STRINGLIB(GroupGenerator) *self) { /* Note that we don't really do much error checking here. If a grouping string contains just CHAR_MAX, for example, then just @@ -48,13 +45,11 @@ _GroupGenerator_next(GroupGenerator *self) /* Fill in some digits, leading zeros, and thousands separator. All are optional, depending on when we're called. */ static void -fill(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end, +STRINGLIB(fill)(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end, Py_ssize_t n_chars, Py_ssize_t n_zeros, const char* thousands_sep, Py_ssize_t thousands_sep_len) { -#if STRINGLIB_IS_UNICODE Py_ssize_t i; -#endif if (thousands_sep) { *buffer_end -= thousands_sep_len; @@ -76,7 +71,8 @@ fill(STRINGLIB_CHAR **digits_end, STRINGLIB_CHAR **buffer_end, memcpy(*buffer_end, *digits_end, n_chars * sizeof(STRINGLIB_CHAR)); *buffer_end -= n_zeros; - STRINGLIB_FILL(*buffer_end, '0', n_zeros); + for (i = 0; i < n_zeros; i++) + (*buffer_end)[i] = '0'; } /** @@ -133,15 +129,15 @@ _Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer, be looked at */ /* A generator that returns all of the grouping widths, until it returns 0. */ - GroupGenerator groupgen; - _GroupGenerator_init(&groupgen, grouping); + STRINGLIB(GroupGenerator) groupgen; + STRINGLIB(GroupGenerator_init)(&groupgen, grouping); if (buffer) { buffer_end = buffer + n_buffer; digits_end = digits + n_digits; } - while ((l = _GroupGenerator_next(&groupgen)) > 0) { + while ((l = STRINGLIB(GroupGenerator_next)(&groupgen)) > 0) { l = MIN(l, MAX(MAX(remaining, min_width), 1)); n_zeros = MAX(0, l - remaining); n_chars = MAX(0, MIN(remaining, l)); @@ -153,7 +149,7 @@ _Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer, if (buffer) { /* Copy into the output buffer. */ - fill(&digits_end, &buffer_end, n_chars, n_zeros, + STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros, use_separator ? thousands_sep : NULL, thousands_sep_len); } @@ -180,7 +176,7 @@ _Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer, count += (use_separator ? thousands_sep_len : 0) + n_zeros + n_chars; if (buffer) { /* Copy into the output buffer. */ - fill(&digits_end, &buffer_end, n_chars, n_zeros, + STRINGLIB(fill)(&digits_end, &buffer_end, n_chars, n_zeros, use_separator ? thousands_sep : NULL, thousands_sep_len); } } @@ -209,4 +205,3 @@ _Py_InsertThousandsGroupingLocale(STRINGLIB_CHAR *buffer, return _Py_InsertThousandsGrouping(buffer, n_buffer, digits, n_digits, min_width, grouping, thousands_sep); } -#endif /* STRINGLIB_LOCALEUTIL_H */ diff --git a/Objects/stringlib/partition.h b/Objects/stringlib/partition.h index 0170bdd..40cb512 100644 --- a/Objects/stringlib/partition.h +++ b/Objects/stringlib/partition.h @@ -1,14 +1,11 @@ /* stringlib: partition implementation */ -#ifndef STRINGLIB_PARTITION_H -#define STRINGLIB_PARTITION_H - #ifndef STRINGLIB_FASTSEARCH_H #error must include "stringlib/fastsearch.h" before including this module #endif Py_LOCAL_INLINE(PyObject*) -stringlib_partition(PyObject* str_obj, +STRINGLIB(partition)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, PyObject* sep_obj, const STRINGLIB_CHAR* sep, Py_ssize_t sep_len) @@ -25,7 +22,7 @@ stringlib_partition(PyObject* str_obj, if (!out) return NULL; - pos = fastsearch(str, str_len, sep, sep_len, -1, FAST_SEARCH); + pos = FASTSEARCH(str, str_len, sep, sep_len, -1, FAST_SEARCH); if (pos < 0) { #if STRINGLIB_MUTABLE @@ -58,7 +55,7 @@ stringlib_partition(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject*) -stringlib_rpartition(PyObject* str_obj, +STRINGLIB(rpartition)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, PyObject* sep_obj, const STRINGLIB_CHAR* sep, Py_ssize_t sep_len) @@ -75,7 +72,7 @@ stringlib_rpartition(PyObject* str_obj, if (!out) return NULL; - pos = fastsearch(str, str_len, sep, sep_len, -1, FAST_RSEARCH); + pos = FASTSEARCH(str, str_len, sep, sep_len, -1, FAST_RSEARCH); if (pos < 0) { #if STRINGLIB_MUTABLE @@ -107,4 +104,3 @@ stringlib_rpartition(PyObject* str_obj, return out; } -#endif diff --git a/Objects/stringlib/split.h b/Objects/stringlib/split.h index 60e7767..947dd28 100644 --- a/Objects/stringlib/split.h +++ b/Objects/stringlib/split.h @@ -1,8 +1,5 @@ /* stringlib: split implementation */ -#ifndef STRINGLIB_SPLIT_H -#define STRINGLIB_SPLIT_H - #ifndef STRINGLIB_FASTSEARCH_H #error must include "stringlib/fastsearch.h" before including this module #endif @@ -54,7 +51,7 @@ #define FIX_PREALLOC_SIZE(list) Py_SIZE(list) = count Py_LOCAL_INLINE(PyObject *) -stringlib_split_whitespace(PyObject* str_obj, +STRINGLIB(split_whitespace)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, Py_ssize_t maxcount) { @@ -102,7 +99,7 @@ stringlib_split_whitespace(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject *) -stringlib_split_char(PyObject* str_obj, +STRINGLIB(split_char)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR ch, Py_ssize_t maxcount) @@ -145,7 +142,7 @@ stringlib_split_char(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject *) -stringlib_split(PyObject* str_obj, +STRINGLIB(split)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sep, Py_ssize_t sep_len, Py_ssize_t maxcount) @@ -158,7 +155,7 @@ stringlib_split(PyObject* str_obj, return NULL; } else if (sep_len == 1) - return stringlib_split_char(str_obj, str, str_len, sep[0], maxcount); + return STRINGLIB(split_char)(str_obj, str, str_len, sep[0], maxcount); list = PyList_New(PREALLOC_SIZE(maxcount)); if (list == NULL) @@ -166,7 +163,7 @@ stringlib_split(PyObject* str_obj, i = j = 0; while (maxcount-- > 0) { - pos = fastsearch(str+i, str_len-i, sep, sep_len, -1, FAST_SEARCH); + pos = FASTSEARCH(str+i, str_len-i, sep, sep_len, -1, FAST_SEARCH); if (pos < 0) break; j = i + pos; @@ -193,7 +190,7 @@ stringlib_split(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject *) -stringlib_rsplit_whitespace(PyObject* str_obj, +STRINGLIB(rsplit_whitespace)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, Py_ssize_t maxcount) { @@ -243,7 +240,7 @@ stringlib_rsplit_whitespace(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject *) -stringlib_rsplit_char(PyObject* str_obj, +STRINGLIB(rsplit_char)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR ch, Py_ssize_t maxcount) @@ -287,7 +284,7 @@ stringlib_rsplit_char(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject *) -stringlib_rsplit(PyObject* str_obj, +STRINGLIB(rsplit)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, const STRINGLIB_CHAR* sep, Py_ssize_t sep_len, Py_ssize_t maxcount) @@ -300,7 +297,7 @@ stringlib_rsplit(PyObject* str_obj, return NULL; } else if (sep_len == 1) - return stringlib_rsplit_char(str_obj, str, str_len, sep[0], maxcount); + return STRINGLIB(rsplit_char)(str_obj, str, str_len, sep[0], maxcount); list = PyList_New(PREALLOC_SIZE(maxcount)); if (list == NULL) @@ -308,7 +305,7 @@ stringlib_rsplit(PyObject* str_obj, j = str_len; while (maxcount-- > 0) { - pos = fastsearch(str, j, sep, sep_len, -1, FAST_RSEARCH); + pos = FASTSEARCH(str, j, sep, sep_len, -1, FAST_RSEARCH); if (pos < 0) break; SPLIT_ADD(str, pos + sep_len, j); @@ -336,7 +333,7 @@ stringlib_rsplit(PyObject* str_obj, } Py_LOCAL_INLINE(PyObject *) -stringlib_splitlines(PyObject* str_obj, +STRINGLIB(splitlines)(PyObject* str_obj, const STRINGLIB_CHAR* str, Py_ssize_t str_len, int keepends) { @@ -391,4 +388,3 @@ stringlib_splitlines(PyObject* str_obj, return NULL; } -#endif diff --git a/Objects/stringlib/stringdefs.h b/Objects/stringlib/stringdefs.h index 1c49426..9619332 100644 --- a/Objects/stringlib/stringdefs.h +++ b/Objects/stringlib/stringdefs.h @@ -6,6 +6,8 @@ compiled as unicode. */ #define STRINGLIB_IS_UNICODE 0 +#define FASTSEARCH fastsearch +#define STRINGLIB(F) stringlib_##F #define STRINGLIB_OBJECT PyBytesObject #define STRINGLIB_CHAR char #define STRINGLIB_TYPE_NAME "string" diff --git a/Objects/stringlib/ucs1lib.h b/Objects/stringlib/ucs1lib.h new file mode 100644 index 0000000..4685c17 --- /dev/null +++ b/Objects/stringlib/ucs1lib.h @@ -0,0 +1,35 @@ +/* this is sort of a hack. there's at least one place (formatting + floats) where some stringlib code takes a different path if it's + compiled as unicode. */ +#define STRINGLIB_IS_UNICODE 1 + +#define FASTSEARCH ucs1lib_fastsearch +#define STRINGLIB(F) ucs1lib_##F +#define STRINGLIB_OBJECT PyUnicodeObject +#define STRINGLIB_CHAR Py_UCS1 +#define STRINGLIB_TYPE_NAME "unicode" +#define STRINGLIB_PARSE_CODE "U" +#define STRINGLIB_EMPTY unicode_empty +#define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE +#define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK +#define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL +#define STRINGLIB_TODECIMAL Py_UNICODE_TODECIMAL +#define STRINGLIB_TOUPPER Py_UNICODE_TOUPPER +#define STRINGLIB_TOLOWER Py_UNICODE_TOLOWER +#define STRINGLIB_FILL Py_UNICODE_FILL +#define STRINGLIB_STR PyUnicode_1BYTE_DATA +#define STRINGLIB_LEN PyUnicode_GET_LENGTH +#define STRINGLIB_NEW PyUnicode_FromUCS1 +#define STRINGLIB_RESIZE not_supported +#define STRINGLIB_CHECK PyUnicode_Check +#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact +#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping +#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale + +#define STRINGLIB_TOSTR PyObject_Str +#define STRINGLIB_TOASCII PyObject_ASCII + +#define _Py_InsertThousandsGrouping _PyUnicode_ucs1_InsertThousandsGrouping +#define _Py_InsertThousandsGroupingLocale _PyUnicode_ucs1_InsertThousandsGroupingLocale + + diff --git a/Objects/stringlib/ucs2lib.h b/Objects/stringlib/ucs2lib.h new file mode 100644 index 0000000..1bb9c27 --- /dev/null +++ b/Objects/stringlib/ucs2lib.h @@ -0,0 +1,34 @@ +/* this is sort of a hack. there's at least one place (formatting + floats) where some stringlib code takes a different path if it's + compiled as unicode. */ +#define STRINGLIB_IS_UNICODE 1 + +#define FASTSEARCH ucs2lib_fastsearch +#define STRINGLIB(F) ucs2lib_##F +#define STRINGLIB_OBJECT PyUnicodeObject +#define STRINGLIB_CHAR Py_UCS2 +#define STRINGLIB_TYPE_NAME "unicode" +#define STRINGLIB_PARSE_CODE "U" +#define STRINGLIB_EMPTY unicode_empty +#define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE +#define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK +#define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL +#define STRINGLIB_TODECIMAL Py_UNICODE_TODECIMAL +#define STRINGLIB_TOUPPER Py_UNICODE_TOUPPER +#define STRINGLIB_TOLOWER Py_UNICODE_TOLOWER +#define STRINGLIB_FILL Py_UNICODE_FILL +#define STRINGLIB_STR PyUnicode_1BYTE_DATA +#define STRINGLIB_LEN PyUnicode_GET_LENGTH +#define STRINGLIB_NEW PyUnicode_FromUCS2 +#define STRINGLIB_RESIZE not_supported +#define STRINGLIB_CHECK PyUnicode_Check +#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact +#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping +#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale + +#define STRINGLIB_TOSTR PyObject_Str +#define STRINGLIB_TOASCII PyObject_ASCII + +#define _Py_InsertThousandsGrouping _PyUnicode_ucs2_InsertThousandsGrouping +#define _Py_InsertThousandsGroupingLocale _PyUnicode_ucs2_InsertThousandsGroupingLocale + diff --git a/Objects/stringlib/ucs4lib.h b/Objects/stringlib/ucs4lib.h new file mode 100644 index 0000000..776d65f --- /dev/null +++ b/Objects/stringlib/ucs4lib.h @@ -0,0 +1,34 @@ +/* this is sort of a hack. there's at least one place (formatting + floats) where some stringlib code takes a different path if it's + compiled as unicode. */ +#define STRINGLIB_IS_UNICODE 1 + +#define FASTSEARCH ucs4lib_fastsearch +#define STRINGLIB(F) ucs4lib_##F +#define STRINGLIB_OBJECT PyUnicodeObject +#define STRINGLIB_CHAR Py_UCS4 +#define STRINGLIB_TYPE_NAME "unicode" +#define STRINGLIB_PARSE_CODE "U" +#define STRINGLIB_EMPTY unicode_empty +#define STRINGLIB_ISSPACE Py_UNICODE_ISSPACE +#define STRINGLIB_ISLINEBREAK BLOOM_LINEBREAK +#define STRINGLIB_ISDECIMAL Py_UNICODE_ISDECIMAL +#define STRINGLIB_TODECIMAL Py_UNICODE_TODECIMAL +#define STRINGLIB_TOUPPER Py_UNICODE_TOUPPER +#define STRINGLIB_TOLOWER Py_UNICODE_TOLOWER +#define STRINGLIB_FILL Py_UNICODE_FILL +#define STRINGLIB_STR PyUnicode_1BYTE_DATA +#define STRINGLIB_LEN PyUnicode_GET_LENGTH +#define STRINGLIB_NEW PyUnicode_FromUCS4 +#define STRINGLIB_RESIZE not_supported +#define STRINGLIB_CHECK PyUnicode_Check +#define STRINGLIB_CHECK_EXACT PyUnicode_CheckExact +#define STRINGLIB_GROUPING _PyUnicode_InsertThousandsGrouping +#define STRINGLIB_GROUPING_LOCALE _PyUnicode_InsertThousandsGroupingLocale + +#define STRINGLIB_TOSTR PyObject_Str +#define STRINGLIB_TOASCII PyObject_ASCII + +#define _Py_InsertThousandsGrouping _PyUnicode_ucs4_InsertThousandsGrouping +#define _Py_InsertThousandsGroupingLocale _PyUnicode_ucs4_InsertThousandsGroupingLocale + diff --git a/Objects/stringlib/undef.h b/Objects/stringlib/undef.h new file mode 100644 index 0000000..40b4391 --- /dev/null +++ b/Objects/stringlib/undef.h @@ -0,0 +1,10 @@ +#undef FASTSEARCH +#undef STRINGLIB +#undef STRINGLIB_CHAR +#undef STRINGLIB_STR +#undef STRINGLIB_LEN +#undef STRINGLIB_NEW +#undef STRINGLIB_RESIZE +#undef _Py_InsertThousandsGrouping +#undef _Py_InsertThousandsGroupingLocale + diff --git a/Objects/stringlib/string_format.h b/Objects/stringlib/unicode_format.h index d992b6f..81a1ff2 100644 --- a/Objects/stringlib/string_format.h +++ b/Objects/stringlib/unicode_format.h @@ -1,16 +1,8 @@ /* - string_format.h -- implementation of string.format(). - - It uses the Objects/stringlib conventions, so that it can be - compiled for both unicode and string objects. + unicode_format.h -- implementation of str.format(). */ -/* Defines for Python 2.6 compatibility */ -#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 @@ -26,8 +18,8 @@ unicode pointers. */ typedef struct { - STRINGLIB_CHAR *ptr; - STRINGLIB_CHAR *end; + PyObject *str; /* borrowed reference */ + Py_ssize_t start, end; } SubString; @@ -64,34 +56,32 @@ AutoNumber_Init(AutoNumber *auto_number) /* fill in a SubString from a pointer and length */ Py_LOCAL_INLINE(void) -SubString_init(SubString *str, STRINGLIB_CHAR *p, Py_ssize_t len) +SubString_init(SubString *str, PyObject *s, int start, int end) { - str->ptr = p; - if (p == NULL) - str->end = NULL; - else - str->end = str->ptr + len; + str->str = s; + str->start = start; + str->end = end; } -/* return a new string. if str->ptr is NULL, return None */ +/* return a new string. if str->str is NULL, return None */ Py_LOCAL_INLINE(PyObject *) SubString_new_object(SubString *str) { - if (str->ptr == NULL) { + if (str->str == NULL) { Py_INCREF(Py_None); return Py_None; } - return STRINGLIB_NEW(str->ptr, str->end - str->ptr); + return PyUnicode_Substring(str->str, str->start, str->end); } -/* return a new string. if str->ptr is NULL, return None */ +/* return a new string. if str->str is NULL, return None */ Py_LOCAL_INLINE(PyObject *) SubString_new_object_or_empty(SubString *str) { - if (str->ptr == NULL) { - return STRINGLIB_NEW(NULL, 0); + if (str->str == NULL) { + return PyUnicode_FromUnicode(NULL, 0); } - return STRINGLIB_NEW(str->ptr, str->end - str->ptr); + return SubString_new_object(str); } /* Return 1 if an error has been detected switching between automatic @@ -125,9 +115,10 @@ autonumber_state_error(AutoNumberState state, int field_name_is_empty) /************************************************************************/ typedef struct { - STRINGLIB_CHAR *ptr; - STRINGLIB_CHAR *end; - PyObject *obj; + char *data; + Py_UCS4 maxchar; + unsigned int kind; + Py_ssize_t pos, size; Py_ssize_t size_increment; } OutputString; @@ -135,12 +126,16 @@ typedef struct { static int output_initialize(OutputString *output, Py_ssize_t size) { - output->obj = STRINGLIB_NEW(NULL, size); - if (output->obj == NULL) + output->data = PyMem_Malloc(size); + if (output->data == NULL) { + PyErr_NoMemory(); return 0; + } - output->ptr = STRINGLIB_STR(output->obj); - output->end = STRINGLIB_LEN(output->obj) + output->ptr; + output->maxchar = 127; + output->kind = PyUnicode_1BYTE_KIND; + output->pos = 0; + output->size = size; output->size_increment = INITIAL_SIZE_INCREMENT; return 1; @@ -155,20 +150,51 @@ output_initialize(OutputString *output, Py_ssize_t size) static int output_extend(OutputString *output, Py_ssize_t count) { - STRINGLIB_CHAR *startptr = STRINGLIB_STR(output->obj); - Py_ssize_t curlen = output->ptr - startptr; - Py_ssize_t maxlen = curlen + count + output->size_increment; + Py_ssize_t maxlen = output->size + count + output->size_increment; - if (STRINGLIB_RESIZE(&output->obj, maxlen) < 0) + output->data = PyMem_Realloc(output->data, maxlen << (output->kind-1)); + output->size = maxlen; + if (output->data == 0) { + PyErr_NoMemory(); return 0; - startptr = STRINGLIB_STR(output->obj); - output->ptr = startptr + curlen; - output->end = startptr + maxlen; + } if (output->size_increment < MAX_SIZE_INCREMENT) output->size_increment *= SIZE_MULTIPLIER; return 1; } +static int +output_widen(OutputString *output, Py_UCS4 maxchar) +{ + int kind; + void *data; + Py_ssize_t i; + if (maxchar <= output->maxchar) + return 1; + if (maxchar < 256) { + output->maxchar = 255; + return 1; + } + if (maxchar < 65536) { + output->maxchar = 65535; + kind = 2; + } + else { + output->maxchar = 1<<21; + kind = 3; + } + data = PyMem_Malloc(output->size << (kind-1)); + if (data == 0) + return 0; + for (i = 0; i < output->size; i++) + PyUnicode_WRITE(kind, data, i, + PyUnicode_READ(output->kind, output->data, i)); + PyMem_Free(output->data); + output->data = data; + output->kind = kind; + return 1; +} + /* output_data dumps characters into our output string buffer. @@ -179,12 +205,25 @@ output_extend(OutputString *output, Py_ssize_t count) 1 for success. */ static int -output_data(OutputString *output, const STRINGLIB_CHAR *s, Py_ssize_t count) +output_data(OutputString *output, PyObject *s, Py_ssize_t start, Py_ssize_t end) { - if ((count > output->end - output->ptr) && !output_extend(output, count)) + Py_ssize_t i; + int kind; + if ((output->pos + end - start > output->size) && + !output_extend(output, end - start)) return 0; - memcpy(output->ptr, s, count * sizeof(STRINGLIB_CHAR)); - output->ptr += count; + kind = PyUnicode_KIND(s); + if (PyUnicode_MAX_CHAR_VALUE(s) > output->maxchar) { + Py_UCS4 maxchar = output->maxchar; + for (i = start; i < end; i++) + if (PyUnicode_READ(kind, PyUnicode_DATA(s), i) > maxchar) + maxchar = PyUnicode_READ(kind, PyUnicode_DATA(s), i); + if (!output_widen(output, maxchar)) + return 0; + } + for (i = start; i < end; i++) + PyUnicode_WRITE(output->kind, output->data, output->pos++, + PyUnicode_READ(kind, PyUnicode_DATA(s), i)); return 1; } @@ -197,15 +236,14 @@ get_integer(const SubString *str) { Py_ssize_t accumulator = 0; Py_ssize_t digitval; - Py_ssize_t oldaccumulator; - STRINGLIB_CHAR *p; + Py_ssize_t i; /* empty string is an error */ - if (str->ptr >= str->end) + if (str->start >= str->end) return -1; - for (p = str->ptr; p < str->end; p++) { - digitval = STRINGLIB_TODECIMAL(*p); + for (i = str->start; i < str->end; i++) { + digitval = Py_UNICODE_TODECIMAL(PyUnicode_READ_CHAR(str->str, i)); if (digitval < 0) return -1; /* @@ -280,34 +318,36 @@ typedef struct { lifetime of the iterator. can be empty */ SubString str; - /* pointer to where we are inside field_name */ - STRINGLIB_CHAR *ptr; + /* index to where we are inside field_name */ + Py_ssize_t index; } FieldNameIterator; static int -FieldNameIterator_init(FieldNameIterator *self, STRINGLIB_CHAR *ptr, - Py_ssize_t len) +FieldNameIterator_init(FieldNameIterator *self, PyObject *s, + Py_ssize_t start, Py_ssize_t end) { - SubString_init(&self->str, ptr, len); - self->ptr = self->str.ptr; + SubString_init(&self->str, s, start, end); + self->index = start; return 1; } static int _FieldNameIterator_attr(FieldNameIterator *self, SubString *name) { - STRINGLIB_CHAR c; + Py_UCS4 c; - name->ptr = self->ptr; + name->str = self->str.str; + name->start = self->index; /* return everything until '.' or '[' */ - while (self->ptr < self->str.end) { - switch (c = *self->ptr++) { + while (self->index < self->str.end) { + c = PyUnicode_READ_CHAR(self->str.str, self->index++); + switch (c) { case '[': case '.': /* backup so that we this character will be seen next time */ - self->ptr--; + self->index--; break; default: continue; @@ -315,7 +355,7 @@ _FieldNameIterator_attr(FieldNameIterator *self, SubString *name) break; } /* end of string is okay */ - name->end = self->ptr; + name->end = self->index; return 1; } @@ -323,13 +363,15 @@ static int _FieldNameIterator_item(FieldNameIterator *self, SubString *name) { int bracket_seen = 0; - STRINGLIB_CHAR c; + Py_UCS4 c; - name->ptr = self->ptr; + name->str = self->str.str; + name->start = self->index; /* return everything until ']' */ - while (self->ptr < self->str.end) { - switch (c = *self->ptr++) { + while (self->index < self->str.end) { + c = PyUnicode_READ_CHAR(self->str.str, self->index++); + switch (c) { case ']': bracket_seen = 1; break; @@ -346,7 +388,7 @@ _FieldNameIterator_item(FieldNameIterator *self, SubString *name) /* end of string is okay */ /* don't include the ']' */ - name->end = self->ptr-1; + name->end = self->index-1; return 1; } @@ -356,10 +398,10 @@ FieldNameIterator_next(FieldNameIterator *self, int *is_attribute, Py_ssize_t *name_idx, SubString *name) { /* check at end of input */ - if (self->ptr >= self->str.end) + if (self->index >= self->str.end) return 1; - switch (*self->ptr++) { + switch (PyUnicode_READ_CHAR(self->str.str, self->index++)) { case '.': *is_attribute = 1; if (_FieldNameIterator_attr(self, name) == 0) @@ -382,7 +424,7 @@ FieldNameIterator_next(FieldNameIterator *self, int *is_attribute, } /* empty string is an error */ - if (name->ptr == name->end) { + if (name->start == name->end) { PyErr_SetString(PyExc_ValueError, "Empty attribute in format string"); return 0; } @@ -398,24 +440,23 @@ FieldNameIterator_next(FieldNameIterator *self, int *is_attribute, 'rest' is an iterator to return the rest */ static int -field_name_split(STRINGLIB_CHAR *ptr, Py_ssize_t len, SubString *first, +field_name_split(PyObject *str, Py_ssize_t start, Py_ssize_t end, SubString *first, Py_ssize_t *first_idx, FieldNameIterator *rest, AutoNumber *auto_number) { - STRINGLIB_CHAR c; - STRINGLIB_CHAR *p = ptr; - STRINGLIB_CHAR *end = ptr + len; + Py_UCS4 c; + Py_ssize_t i = start; int field_name_is_empty; int using_numeric_index; /* find the part up until the first '.' or '[' */ - while (p < end) { - switch (c = *p++) { + while (i < end) { + switch (c = PyUnicode_READ_CHAR(str, i++)) { case '[': case '.': /* backup so that we this character is available to the "rest" iterator */ - p--; + i--; break; default: continue; @@ -424,15 +465,15 @@ field_name_split(STRINGLIB_CHAR *ptr, Py_ssize_t len, SubString *first, } /* set up the return values */ - SubString_init(first, ptr, p - ptr); - FieldNameIterator_init(rest, p, end - p); + SubString_init(first, str, start, i); + FieldNameIterator_init(rest, str, i, end); /* see if "first" is an integer, in which case it's used as an index */ *first_idx = get_integer(first); if (*first_idx == -1 && PyErr_Occurred()) return 0; - field_name_is_empty = first->ptr >= first->end; + field_name_is_empty = first->start >= first->end; /* If the field name is omitted or if we have a numeric index specified, then we're doing numeric indexing into args. */ @@ -487,7 +528,7 @@ get_field_object(SubString *input, PyObject *args, PyObject *kwargs, Py_ssize_t index; FieldNameIterator rest; - if (!field_name_split(input->ptr, input->end - input->ptr, &first, + if (!field_name_split(input->str, input->start, input->end, &first, &index, &rest, auto_number)) { goto error; } @@ -576,12 +617,8 @@ render_field(PyObject *fieldobj, SubString *format_spec, OutputString *output) int ok = 0; PyObject *result = NULL; PyObject *format_spec_object = NULL; - PyObject *(*formatter)(PyObject *, STRINGLIB_CHAR *, Py_ssize_t) = NULL; - STRINGLIB_CHAR* format_spec_start = format_spec->ptr ? - format_spec->ptr : NULL; - Py_ssize_t format_spec_len = format_spec->ptr ? - format_spec->end - format_spec->ptr : 0; - + PyObject *(*formatter)(PyObject *, PyObject *, Py_ssize_t, Py_ssize_t) = NULL; + /* If we know the type exactly, skip the lookup of __format__ and just call the formatter directly. */ if (PyUnicode_CheckExact(fieldobj)) @@ -597,39 +634,28 @@ render_field(PyObject *fieldobj, SubString *format_spec, OutputString *output) if (formatter) { /* we know exactly which formatter will be called when __format__ is looked up, so call it directly, instead. */ - result = formatter(fieldobj, format_spec_start, format_spec_len); + result = formatter(fieldobj, format_spec->str, + format_spec->start, format_spec->end); } else { /* We need to create an object out of the pointers we have, because __format__ takes a string/unicode object for format_spec. */ - format_spec_object = STRINGLIB_NEW(format_spec_start, - format_spec_len); + if (format_spec->str) + format_spec_object = PyUnicode_Substring(format_spec->str, + format_spec->start, + format_spec->end); + else + format_spec_object = PyUnicode_New(0, 0); if (format_spec_object == NULL) goto done; result = PyObject_Format(fieldobj, format_spec_object); } - if (result == NULL) + if (result == NULL || PyUnicode_READY(result) == -1) goto done; -#if PY_VERSION_HEX >= 0x03000000 assert(PyUnicode_Check(result)); -#else - assert(PyBytes_Check(result) || PyUnicode_Check(result)); - - /* Convert result to our type. We could be str, and result could - be unicode */ - { - PyObject *tmp = STRINGLIB_TOSTR(result); - if (tmp == NULL) - goto done; - Py_DECREF(result); - result = tmp; - } -#endif - - ok = output_data(output, - STRINGLIB_STR(result), STRINGLIB_LEN(result)); + ok = output_data(output, result, 0, PyUnicode_GET_LENGTH(result)); done: Py_XDECREF(format_spec_object); Py_XDECREF(result); @@ -638,23 +664,24 @@ done: static int parse_field(SubString *str, SubString *field_name, SubString *format_spec, - STRINGLIB_CHAR *conversion) + Py_UCS4 *conversion) { /* Note this function works if the field name is zero length, which is good. Zero length field names are handled later, in field_name_split. */ - STRINGLIB_CHAR c = 0; + Py_UCS4 c = 0; /* initialize these, as they may be empty */ *conversion = '\0'; - SubString_init(format_spec, NULL, 0); + SubString_init(format_spec, NULL, 0, 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++)) { + field_name->str = str->str; + field_name->start = str->start; + while (str->start < str->end) { + switch ((c = PyUnicode_READ_CHAR(str->str, str->start++))) { case ':': case '!': break; @@ -667,26 +694,27 @@ parse_field(SubString *str, SubString *field_name, SubString *format_spec, if (c == '!' || c == ':') { /* we have a format specifier and/or a conversion */ /* don't include the last character */ - field_name->end = str->ptr-1; + field_name->end = str->start-1; /* the format specifier is the rest of the string */ - format_spec->ptr = str->ptr; + format_spec->str = str->str; + format_spec->start = str->start; format_spec->end = str->end; /* see if there's a conversion specifier */ if (c == '!') { /* there must be another character present */ - if (format_spec->ptr >= format_spec->end) { + if (format_spec->start >= format_spec->end) { PyErr_SetString(PyExc_ValueError, "end of format while looking for conversion " "specifier"); return 0; } - *conversion = *(format_spec->ptr++); + *conversion = PyUnicode_READ_CHAR(format_spec->str, format_spec->start++); /* if there is another character, it must be a colon */ - if (format_spec->ptr < format_spec->end) { - c = *(format_spec->ptr++); + if (format_spec->start < format_spec->end) { + c = PyUnicode_READ_CHAR(format_spec->str, format_spec->start++); if (c != ':') { PyErr_SetString(PyExc_ValueError, "expected ':' after format specifier"); @@ -697,7 +725,7 @@ parse_field(SubString *str, SubString *field_name, SubString *format_spec, } else /* end of string, there's no format_spec or conversion */ - field_name->end = str->ptr; + field_name->end = str->start; return 1; } @@ -716,9 +744,10 @@ typedef struct { } MarkupIterator; static int -MarkupIterator_init(MarkupIterator *self, STRINGLIB_CHAR *ptr, Py_ssize_t len) +MarkupIterator_init(MarkupIterator *self, PyObject *str, + Py_ssize_t start, Py_ssize_t end) { - SubString_init(&self->str, ptr, len); + SubString_init(&self->str, str, start, end); return 1; } @@ -727,30 +756,30 @@ MarkupIterator_init(MarkupIterator *self, STRINGLIB_CHAR *ptr, Py_ssize_t len) static int MarkupIterator_next(MarkupIterator *self, SubString *literal, int *field_present, SubString *field_name, - SubString *format_spec, STRINGLIB_CHAR *conversion, + SubString *format_spec, Py_UCS4 *conversion, int *format_spec_needs_expanding) { int at_end; - STRINGLIB_CHAR c = 0; - STRINGLIB_CHAR *start; + Py_UCS4 c = 0; + Py_ssize_t start; int count; Py_ssize_t len; int markup_follows = 0; /* initialize all of the output variables */ - SubString_init(literal, NULL, 0); - SubString_init(field_name, NULL, 0); - SubString_init(format_spec, NULL, 0); + SubString_init(literal, NULL, 0, 0); + SubString_init(field_name, NULL, 0, 0); + SubString_init(format_spec, NULL, 0, 0); *conversion = '\0'; *format_spec_needs_expanding = 0; *field_present = 0; /* No more input, end of iterator. This is the normal exit path. */ - if (self->str.ptr >= self->str.end) + if (self->str.start >= self->str.end) return 1; - start = self->str.ptr; + start = self->str.start; /* First read any literal text. Read until the end of string, an escaped '{' or '}', or an unescaped '{'. In order to never @@ -759,8 +788,8 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, including the brace, but no format object. The next time through, we'll return the rest of the literal, skipping past the second consecutive brace. */ - while (self->str.ptr < self->str.end) { - switch (c = *(self->str.ptr++)) { + while (self->str.start < self->str.end) { + switch (c = PyUnicode_READ_CHAR(self->str.str, self->str.start++)) { case '{': case '}': markup_follows = 1; @@ -771,10 +800,12 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, break; } - at_end = self->str.ptr >= self->str.end; - len = self->str.ptr - start; + at_end = self->str.start >= self->str.end; + len = self->str.start - start; - if ((c == '}') && (at_end || (c != *self->str.ptr))) { + if ((c == '}') && (at_end || + (c != PyUnicode_READ_CHAR(self->str.str, + self->str.start)))) { PyErr_SetString(PyExc_ValueError, "Single '}' encountered " "in format string"); return 0; @@ -785,10 +816,10 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, return 0; } if (!at_end) { - if (c == *self->str.ptr) { + if (c == PyUnicode_READ_CHAR(self->str.str, self->str.start)) { /* escaped } or {, skip it in the input. there is no markup object following us, just this literal text */ - self->str.ptr++; + self->str.start++; markup_follows = 0; } else @@ -796,7 +827,8 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, } /* record the literal text */ - literal->ptr = start; + literal->str = self->str.str; + literal->start = start; literal->end = start + len; if (!markup_follows) @@ -808,12 +840,12 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, *field_present = 1; count = 1; - start = self->str.ptr; + start = self->str.start; /* we know we can't have a zero length string, so don't worry about that case */ - while (self->str.ptr < self->str.end) { - switch (c = *(self->str.ptr++)) { + while (self->str.start < self->str.end) { + switch (c = PyUnicode_READ_CHAR(self->str.str, self->str.start++)) { case '{': /* the format spec needs to be recursively expanded. this is an optimization, and not strictly needed */ @@ -826,7 +858,7 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, /* we're done. parse and get out */ SubString s; - SubString_init(&s, start, self->str.ptr - 1 - start); + SubString_init(&s, self->str.str, start, self->str.start - 1); if (parse_field(&s, field_name, format_spec, conversion) == 0) return 0; @@ -845,7 +877,7 @@ MarkupIterator_next(MarkupIterator *self, SubString *literal, /* do the !r or !s conversion on obj */ static PyObject * -do_conversion(PyObject *obj, STRINGLIB_CHAR conversion) +do_conversion(PyObject *obj, Py_UCS4 conversion) { /* XXX in pre-3.0, do we need to convert this to unicode, since it might have returned a string? */ @@ -853,11 +885,9 @@ do_conversion(PyObject *obj, STRINGLIB_CHAR conversion) case 'r': return PyObject_Repr(obj); case 's': - return STRINGLIB_TOSTR(obj); -#if PY_VERSION_HEX >= 0x03000000 + return PyObject_Str(obj); case 'a': - return STRINGLIB_TOASCII(obj); -#endif + return PyObject_ASCII(obj); default: if (conversion > 32 && conversion < 127) { /* It's the ASCII subrange; casting to char is safe @@ -889,7 +919,7 @@ do_conversion(PyObject *obj, STRINGLIB_CHAR conversion) static int output_markup(SubString *field_name, SubString *format_spec, - int format_spec_needs_expanding, STRINGLIB_CHAR conversion, + int format_spec_needs_expanding, Py_UCS4 conversion, OutputString *output, PyObject *args, PyObject *kwargs, int recursion_depth, AutoNumber *auto_number) { @@ -906,7 +936,7 @@ output_markup(SubString *field_name, SubString *format_spec, if (conversion != '\0') { tmp = do_conversion(fieldobj, conversion); - if (tmp == NULL) + if (tmp == NULL || PyUnicode_READY(tmp) == -1) goto done; /* do the assignment, transferring ownership: fieldobj = tmp */ @@ -919,14 +949,13 @@ output_markup(SubString *field_name, SubString *format_spec, if (format_spec_needs_expanding) { tmp = build_string(format_spec, args, kwargs, recursion_depth-1, auto_number); - if (tmp == NULL) + if (tmp == NULL || PyUnicode_READY(tmp) == -1) goto done; /* note that in the case we're expanding the format string, tmp must be kept around until after the call to render_field. */ - SubString_init(&expanded_format_spec, - STRINGLIB_STR(tmp), STRINGLIB_LEN(tmp)); + SubString_init(&expanded_format_spec, tmp, 0, PyUnicode_GET_LENGTH(tmp)); actual_format_spec = &expanded_format_spec; } else @@ -961,14 +990,14 @@ do_markup(SubString *input, PyObject *args, PyObject *kwargs, SubString literal; SubString field_name; SubString format_spec; - STRINGLIB_CHAR conversion; + Py_UCS4 conversion; - MarkupIterator_init(&iter, input->ptr, input->end - input->ptr); + MarkupIterator_init(&iter, input->str, input->start, input->end); while ((result = MarkupIterator_next(&iter, &literal, &field_present, &field_name, &format_spec, &conversion, &format_spec_needs_expanding)) == 2) { - if (!output_data(output, literal.ptr, literal.end - literal.ptr)) + if (!output_data(output, literal.str, literal.start, literal.end)) return 0; if (field_present) if (!output_markup(&field_name, &format_spec, @@ -990,9 +1019,8 @@ build_string(SubString *input, PyObject *args, PyObject *kwargs, { OutputString output; PyObject *result = NULL; - Py_ssize_t count; - output.obj = NULL; /* needed so cleanup code always works */ + output.data = NULL; /* needed so cleanup code always works */ /* check the recursion level */ if (recursion_depth <= 0) { @@ -1004,7 +1032,7 @@ build_string(SubString *input, PyObject *args, PyObject *kwargs, /* initial size is the length of the format string, plus the size increment. seems like a reasonable default */ if (!output_initialize(&output, - input->end - input->ptr + + input->end - input->start + INITIAL_SIZE_INCREMENT)) goto done; @@ -1013,17 +1041,14 @@ build_string(SubString *input, PyObject *args, PyObject *kwargs, goto done; } - count = output.ptr - STRINGLIB_STR(output.obj); - if (STRINGLIB_RESIZE(&output.obj, count) < 0) { + result = PyUnicode_New(output.pos, output.maxchar); + if (!result) goto done; - } - - /* transfer ownership to result */ - result = output.obj; - output.obj = NULL; + memcpy(PyUnicode_DATA(result), output.data, output.pos << (output.kind-1)); done: - Py_XDECREF(output.obj); + if (output.data) + PyMem_Free(output.data); return result; } @@ -1045,8 +1070,11 @@ do_string_format(PyObject *self, PyObject *args, PyObject *kwargs) AutoNumber auto_number; + if (PyUnicode_READY(self) == -1) + return NULL; + AutoNumber_Init(&auto_number); - SubString_init(&input, STRINGLIB_STR(self), STRINGLIB_LEN(self)); + SubString_init(&input, self, 0, PyUnicode_GET_LENGTH(self)); return build_string(&input, args, kwargs, recursion_depth, &auto_number); } @@ -1069,7 +1097,7 @@ do_string_format_map(PyObject *self, PyObject *obj) typedef struct { PyObject_HEAD - STRINGLIB_OBJECT *str; + PyUnicodeObject *str; MarkupIterator it_markup; } formatteriterobject; @@ -1095,7 +1123,7 @@ formatteriter_next(formatteriterobject *it) SubString literal; SubString field_name; SubString format_spec; - STRINGLIB_CHAR conversion; + Py_UCS4 conversion; int format_spec_needs_expanding; int field_present; int result = MarkupIterator_next(&it->it_markup, &literal, &field_present, @@ -1139,7 +1167,8 @@ formatteriter_next(formatteriterobject *it) Py_INCREF(conversion_str); } else - conversion_str = STRINGLIB_NEW(&conversion, 1); + conversion_str = PyUnicode_FromKindAndData(PyUnicode_4BYTE_KIND, + &conversion, 1); if (conversion_str == NULL) goto done; @@ -1196,7 +1225,7 @@ static PyTypeObject PyFormatterIter_Type = { describing the parsed elements. It's a wrapper around stringlib/string_format.h's MarkupIterator */ static PyObject * -formatter_parser(PyObject *ignored, STRINGLIB_OBJECT *self) +formatter_parser(PyObject *ignored, PyUnicodeObject *self) { formatteriterobject *it; @@ -1205,6 +1234,9 @@ formatter_parser(PyObject *ignored, STRINGLIB_OBJECT *self) return NULL; } + if (PyUnicode_READY(self) == -1) + return NULL; + it = PyObject_New(formatteriterobject, &PyFormatterIter_Type); if (it == NULL) return NULL; @@ -1214,10 +1246,7 @@ formatter_parser(PyObject *ignored, STRINGLIB_OBJECT *self) it->str = self; /* initialize the contained MarkupIterator */ - MarkupIterator_init(&it->it_markup, - STRINGLIB_STR(self), - STRINGLIB_LEN(self)); - + MarkupIterator_init(&it->it_markup, (PyObject*)self, 0, PyUnicode_GET_LENGTH(self)); return (PyObject *)it; } @@ -1234,7 +1263,7 @@ formatter_parser(PyObject *ignored, STRINGLIB_OBJECT *self) typedef struct { PyObject_HEAD - STRINGLIB_OBJECT *str; + PyUnicodeObject *str; FieldNameIterator it_field; } fieldnameiterobject; @@ -1336,7 +1365,7 @@ static PyTypeObject PyFieldNameIter_Type = { field_name_split. The iterator it returns is a FieldNameIterator */ static PyObject * -formatter_field_name_split(PyObject *ignored, STRINGLIB_OBJECT *self) +formatter_field_name_split(PyObject *ignored, PyUnicodeObject *self) { SubString first; Py_ssize_t first_idx; @@ -1350,6 +1379,9 @@ formatter_field_name_split(PyObject *ignored, STRINGLIB_OBJECT *self) return NULL; } + if (PyUnicode_READY(self) == -1) + return NULL; + it = PyObject_New(fieldnameiterobject, &PyFieldNameIter_Type); if (it == NULL) return NULL; @@ -1361,8 +1393,7 @@ formatter_field_name_split(PyObject *ignored, STRINGLIB_OBJECT *self) /* Pass in auto_number = NULL. We'll return an empty string for first_obj in that case. */ - if (!field_name_split(STRINGLIB_STR(self), - STRINGLIB_LEN(self), + if (!field_name_split((PyObject*)self, 0, PyUnicode_GET_LENGTH(self), &first, &first_idx, &it->it_field, NULL)) goto done; diff --git a/Objects/stringlib/unicodedefs.h b/Objects/stringlib/unicodedefs.h index 09dae6d..0c40b80 100644 --- a/Objects/stringlib/unicodedefs.h +++ b/Objects/stringlib/unicodedefs.h @@ -6,6 +6,8 @@ compiled as unicode. */ #define STRINGLIB_IS_UNICODE 1 +#define FASTSEARCH fastsearch +#define STRINGLIB(F) stringlib_##F #define STRINGLIB_OBJECT PyUnicodeObject #define STRINGLIB_CHAR Py_UNICODE #define STRINGLIB_TYPE_NAME "unicode" |