/* implements the unicode (as opposed to string) version of the built-in formatters for string, int, float. that is, the versions of int.__float__, etc., that take and return unicode objects */ #include "Python.h" #include "pycore_fileutils.h" // _Py_GetLocaleconvNumeric() #include "pycore_long.h" // _PyLong_FormatWriter() #include <locale.h> /* Raises an exception about an unknown presentation type for this * type. */ static void unknown_presentation_type(Py_UCS4 presentation_type, const char* type_name) { … } static void invalid_thousands_separator_type(char specifier, Py_UCS4 presentation_type) { … } static void invalid_comma_and_underscore(void) { … } /* 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(PyObject *str, Py_ssize_t *ppos, Py_ssize_t end, Py_ssize_t *result) { … } /************************************************************************/ /*********** standard format specifier parsing **************************/ /************************************************************************/ /* returns true if this character is a specifier alignment token */ Py_LOCAL_INLINE(int) is_alignment_token(Py_UCS4 c) { … } /* returns true if this character is a sign element */ Py_LOCAL_INLINE(int) is_sign_element(Py_UCS4 c) { … } /* Locale type codes. LT_NO_LOCALE must be zero. */ enum LocaleType { … }; InternalFormatSpec; /* 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(PyObject *obj, PyObject *format_spec, Py_ssize_t start, Py_ssize_t end, InternalFormatSpec *format, char default_type, char default_align) { … } /* Calculate the padding needed. */ static void calc_padding(Py_ssize_t nchars, Py_ssize_t width, Py_UCS4 align, Py_ssize_t *n_lpadding, Py_ssize_t *n_rpadding, Py_ssize_t *n_total) { … } /* Do the padding, and return a pointer to where the caller-supplied content goes. */ static int fill_padding(_PyUnicodeWriter *writer, Py_ssize_t nchars, Py_UCS4 fill_char, Py_ssize_t n_lpadding, Py_ssize_t n_rpadding) { … } /************************************************************************/ /*********** common routines for numeric formatting *********************/ /************************************************************************/ /* 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. */ LocaleInfo; #define LocaleInfo_STATIC_INIT … /* describes the layout for an integer, see the comment in calc_number_widths() for details */ 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(PyObject *s, Py_ssize_t pos, Py_ssize_t end, Py_ssize_t *n_remainder, int *has_decimal) { … } /* 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? Return -1 on error. */ static Py_ssize_t calc_number_widths(NumberFieldWidths *spec, Py_ssize_t n_prefix, Py_UCS4 sign_char, Py_ssize_t n_start, Py_ssize_t n_end, Py_ssize_t n_remainder, int has_decimal, const LocaleInfo *locale, const InternalFormatSpec *format, Py_UCS4 *maxchar) { … } /* Fill in the digit parts of a number's string representation, as determined in calc_number_widths(). Return -1 on error, or 0 on success. */ static int fill_number(_PyUnicodeWriter *writer, const NumberFieldWidths *spec, PyObject *digits, Py_ssize_t d_start, PyObject *prefix, Py_ssize_t p_start, Py_UCS4 fill_char, LocaleInfo *locale, int toupper) { … } static const char no_grouping[1] = …; /* 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 LT_UNDERSCORE_LOCALE/LT_UNDER_FOUR_LOCALE, or none if LT_NO_LOCALE. */ static int get_locale_info(enum LocaleType type, LocaleInfo *locale_info) { … } static void free_locale_info(LocaleInfo *locale_info) { … } /************************************************************************/ /*********** string formatting ******************************************/ /************************************************************************/ static int format_string_internal(PyObject *value, const InternalFormatSpec *format, _PyUnicodeWriter *writer) { … } /************************************************************************/ /*********** long formatting ********************************************/ /************************************************************************/ static int format_long_internal(PyObject *value, const InternalFormatSpec *format, _PyUnicodeWriter *writer) { … } /************************************************************************/ /*********** float formatting *******************************************/ /************************************************************************/ /* much of this is taken from unicodeobject.c */ static int format_float_internal(PyObject *value, const InternalFormatSpec *format, _PyUnicodeWriter *writer) { … } /************************************************************************/ /*********** complex formatting *****************************************/ /************************************************************************/ static int format_complex_internal(PyObject *value, const InternalFormatSpec *format, _PyUnicodeWriter *writer) { … } /************************************************************************/ /*********** built in formatters ****************************************/ /************************************************************************/ static int format_obj(PyObject *obj, _PyUnicodeWriter *writer) { … } int _PyUnicode_FormatAdvancedWriter(_PyUnicodeWriter *writer, PyObject *obj, PyObject *format_spec, Py_ssize_t start, Py_ssize_t end) { … } int _PyLong_FormatAdvancedWriter(_PyUnicodeWriter *writer, PyObject *obj, PyObject *format_spec, Py_ssize_t start, Py_ssize_t end) { … } int _PyFloat_FormatAdvancedWriter(_PyUnicodeWriter *writer, PyObject *obj, PyObject *format_spec, Py_ssize_t start, Py_ssize_t end) { … } int _PyComplex_FormatAdvancedWriter(_PyUnicodeWriter *writer, PyObject *obj, PyObject *format_spec, Py_ssize_t start, Py_ssize_t end) { … }