diff options
Diffstat (limited to 'Objects/stringlib')
| -rw-r--r-- | Objects/stringlib/formatter.h | 30 | ||||
| -rw-r--r-- | Objects/stringlib/localeutil.h | 121 | ||||
| -rw-r--r-- | Objects/stringlib/stringdefs.h | 1 | ||||
| -rw-r--r-- | Objects/stringlib/unicodedefs.h | 1 | 
4 files changed, 150 insertions, 3 deletions
diff --git a/Objects/stringlib/formatter.h b/Objects/stringlib/formatter.h index 531bc22..22dd292 100644 --- a/Objects/stringlib/formatter.h +++ b/Objects/stringlib/formatter.h @@ -453,6 +453,9 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,      Py_ssize_t n_digits;       /* count of digits need from the computed                                    string */      Py_ssize_t n_leading_chars; +    Py_ssize_t n_grouping_chars = 0; /* Count of additional chars to +					allocate, used for 'n' +					formatting. */      NumberFieldWidths spec;      long x; @@ -523,6 +526,7 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,              break;          default:  /* shouldn't be needed, but stops a compiler warning */          case 'd': +        case 'n':              base = 10;              leading_chars_to_skip = 0;              break; @@ -555,8 +559,15 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,      /* Calculate the widths of the various leading and trailing parts */      calc_number_widths(&spec, sign, n_digits, format); +    if (format->type == 'n') +	    /* Compute how many additional chars we need to allocate +	       to hold the thousands grouping. */ +	    STRINGLIB_GROUPING(pnumeric_chars, n_digits, +			       pnumeric_chars+n_digits, +			       0, &n_grouping_chars, 0); +      /* Allocate a new string to hold the result */ -    result = STRINGLIB_NEW(NULL, spec.n_total); +    result = STRINGLIB_NEW(NULL, spec.n_total + n_grouping_chars);      if (!result)  	goto done;      p = STRINGLIB_STR(result); @@ -567,13 +578,26 @@ format_int_or_long_internal(PyObject *value, const InternalFormatSpec *format,  	    pnumeric_chars,  	    n_digits * sizeof(STRINGLIB_CHAR)); -    /* if X, convert to uppercase */ +    /* If type is 'X', convert to uppercase */      if (format->type == 'X') {  	Py_ssize_t t;  	for (t = 0; t < n_digits; ++t)  	    p[t + n_leading_chars] = STRINGLIB_TOUPPER(p[t + n_leading_chars]);      } +    /* Insert the grouping, if any, after the uppercasing of 'X', so we can +       ensure that grouping chars won't be affeted. */ +    if (n_grouping_chars && format->type == 'n') { +	    /* We know this can't fail, since we've already +	       reserved enough space. */ +	    STRINGLIB_CHAR *pstart = p + n_leading_chars; +	    int r = STRINGLIB_GROUPING(pstart, n_digits, +				       pstart + n_digits, +				       spec.n_total+n_grouping_chars-n_leading_chars, +				       NULL, 0); +	    assert(r); +    } +      /* Fill in the non-digit parts */      fill_number(p, &spec, n_digits,                  format->fill_char == '\0' ? ' ' : format->fill_char); @@ -841,6 +865,7 @@ format_int_or_long(PyObject* value, PyObject* args, IntOrLongToString tostring)      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(value, &format, tostring); @@ -852,7 +877,6 @@ format_int_or_long(PyObject* value, PyObject* args, IntOrLongToString tostring)      case 'F':      case 'g':      case 'G': -    case 'n':      case '%':          /* convert to float */          tmp = PyNumber_Float(value); diff --git a/Objects/stringlib/localeutil.h b/Objects/stringlib/localeutil.h new file mode 100644 index 0000000..5cab0bb --- /dev/null +++ b/Objects/stringlib/localeutil.h @@ -0,0 +1,121 @@ +/* stringlib: locale related helpers implementation */ + +#ifndef STRINGLIB_LOCALEUTIL_H +#define STRINGLIB_LOCALEUTIL_H + +#include <locale.h> + +/** + * _Py_InsertThousandsGrouping: + * @buffer: A pointer to the start of a string. + * @len: The length of the string. + * @plast: A pointer to the end of of the digits in the string.  This + *         may be before the end of the string (if the string contains + *         decimals, for example). + * @buf_size: The maximum size of the buffer pointed to by buffer. + * @count: If non-NULL, points to a variable that will receive the + *         number of characters we need to insert (and no formatting + *         will actually occur). + * @append_zero_char: If non-zero, put a trailing zero at the end of + *         of the resulting string, if and only if we modified the + *         string. + * + * Inserts thousand grouping characters (as defined in the current + *  locale) into the string between buffer and plast.  If count is + *  non-NULL, don't do any formatting, just count the number of + *  characters to insert.  This is used by the caller to appropriately + *  resize the buffer, if needed. + * + * Return value: 0 on error, else 1.  Note that no error can occur if + *  count is non-NULL. + * + * This name won't be used, the includer of this file should define + *  it to be the actual function name, based on unicode or string. + **/ +int +_Py_InsertThousandsGrouping(STRINGLIB_CHAR *buffer, +			    Py_ssize_t len, +			    STRINGLIB_CHAR *plast, +			    Py_ssize_t buf_size, +			    Py_ssize_t *count, +			    int append_zero_char) +{ +	struct lconv *locale_data = localeconv(); +	const char *grouping = locale_data->grouping; +	const char *thousands_sep = locale_data->thousands_sep; +	Py_ssize_t thousands_sep_len = strlen(thousands_sep); +	STRINGLIB_CHAR *pend = buffer + len; /* current end of buffer */ +	STRINGLIB_CHAR *pmax = buffer + buf_size;       /* max of buffer */ +	char current_grouping; + +	/* Initialize the character count, if we're just counting. */ +	if (count) +		*count = 0; + +	/* Starting at plast and working right-to-left, keep track of +	   what grouping needs to be added and insert that. */ +	current_grouping = *grouping++; + +	/* If the first character is 0, perform no grouping at all. */ +	if (current_grouping == 0) +		return 1; + +	while (plast - buffer > current_grouping) { +		/* Always leave buffer and pend valid at the end of this +		   loop, since we might leave with a return statement. */ + +		plast -= current_grouping; +		if (count) { +			/* We're only counting, not touching the memory. */ +			*count += thousands_sep_len; +		} +		else { +			/* Do the formatting. */ + +			/* Is there room to insert thousands_sep_len chars? */ +			if (pmax - pend < thousands_sep_len) +				/* No room. */ +				return 0; + +			/* Move the rest of the string down. */ +			memmove(plast + thousands_sep_len, +				plast, +				(pend - plast) * sizeof(STRINGLIB_CHAR)); +			/* Copy the thousands_sep chars into the buffer. */ +#if STRINGLIB_IS_UNICODE +			/* Convert from the char's of the thousands_sep from +			   the locale into unicode. */ +			{ +				Py_ssize_t i; +				for (i = 0; i < thousands_sep_len; ++i) +					plast[i] = thousands_sep[i]; +			} +#else +			/* No conversion, just memcpy the thousands_sep. */ +			memcpy(plast, thousands_sep, thousands_sep_len); +#endif +		} + +		/* Adjust end pointer. */ +		pend += thousands_sep_len; + +		/* Move to the next grouping character, unless we're +		   repeating (which is designated by a grouping of 0). */ +		if (*grouping != 0) { +			current_grouping = *grouping++; +			if (current_grouping == CHAR_MAX) +				/* We're done. */ +				break; +		} +	} +	if (append_zero_char) { +		/* Append a zero character to mark the end of the string, +		   if there's room. */ +		if (pend - plast < 1) +			/* No room, error. */ +			return 0; +		*pend = 0; +	} +	return 1; +} +#endif /* STRINGLIB_LOCALEUTIL_H */ diff --git a/Objects/stringlib/stringdefs.h b/Objects/stringlib/stringdefs.h index 1e0df0f..daaa2e2 100644 --- a/Objects/stringlib/stringdefs.h +++ b/Objects/stringlib/stringdefs.h @@ -23,5 +23,6 @@  #define STRINGLIB_CHECK          PyString_Check  #define STRINGLIB_CMP            memcmp  #define STRINGLIB_TOSTR          PyObject_Str +#define STRINGLIB_GROUPING       _PyString_InsertThousandsGrouping  #endif /* !STRINGLIB_STRINGDEFS_H */ diff --git a/Objects/stringlib/unicodedefs.h b/Objects/stringlib/unicodedefs.h index f402a98..8f87fe0 100644 --- a/Objects/stringlib/unicodedefs.h +++ b/Objects/stringlib/unicodedefs.h @@ -21,6 +21,7 @@  #define STRINGLIB_NEW            PyUnicode_FromUnicode  #define STRINGLIB_RESIZE         PyUnicode_Resize  #define STRINGLIB_CHECK          PyUnicode_Check +#define STRINGLIB_GROUPING       _PyUnicode_InsertThousandsGrouping  #if PY_VERSION_HEX < 0x03000000  #define STRINGLIB_TOSTR          PyObject_Unicode  | 
