summaryrefslogtreecommitdiffstats
path: root/Objects/stringlib
diff options
context:
space:
mode:
Diffstat (limited to 'Objects/stringlib')
-rw-r--r--Objects/stringlib/count.h9
-rw-r--r--Objects/stringlib/eq.h23
-rw-r--r--Objects/stringlib/fastsearch.h4
-rw-r--r--Objects/stringlib/find.h31
-rw-r--r--Objects/stringlib/formatter.h1516
-rw-r--r--Objects/stringlib/localeutil.h27
-rw-r--r--Objects/stringlib/partition.h12
-rw-r--r--Objects/stringlib/split.h26
-rw-r--r--Objects/stringlib/stringdefs.h2
-rw-r--r--Objects/stringlib/ucs1lib.h35
-rw-r--r--Objects/stringlib/ucs2lib.h34
-rw-r--r--Objects/stringlib/ucs4lib.h34
-rw-r--r--Objects/stringlib/undef.h10
-rw-r--r--Objects/stringlib/unicode_format.h (renamed from Objects/stringlib/string_format.h)385
-rw-r--r--Objects/stringlib/unicodedefs.h2
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"