static PyObject * asciistr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *self = NULL; PyObject *x = NULL; Py_buffer view; static char *kwlist[] = {"object", 0}; if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:asciistr", kwlist, &x)) { return NULL; } if (x == NULL) _Py_RETURN_ASCIISTR_EMPTY(); if (PyObject_CheckBuffer(x)) { if (PyObject_GetBuffer(x, &view, PyBUF_CONTIG_RO) < 0) { return NULL; } self = PyUnicode_FromString((char *)view.buf); PyBuffer_Release(&view); } else { self = PyObject_Str(x); } if (PyUnicode_KIND(self) != PyUnicode_1BYTE_KIND) { Py_DECREF(self); PyErr_SetString(PyExc_ValueError, "asciistr must contain no high-byte characters"); return (NULL); } if (PyUnicode_MAX_CHAR_VALUE(self) > 127) { Py_DECREF(self); PyErr_SetString(PyExc_ValueError, "asciistr must contain no high-byte characters"); return (NULL); } /* Probably going to hell for this. */ Py_TYPE(self) = type; return self; }
static int all_name_chars(PyObject *o) { static char ok_name_char[256]; static unsigned char *name_chars = (unsigned char *)NAME_CHARS; PyUnicodeObject *u = (PyUnicodeObject *)o; const unsigned char *s; if (!PyUnicode_Check(o) || PyUnicode_READY(u) == -1 || PyUnicode_MAX_CHAR_VALUE(u) >= 128) return 0; if (ok_name_char[*name_chars] == 0) { unsigned char *p; for (p = name_chars; *p; p++) ok_name_char[*p] = 1; } s = PyUnicode_1BYTE_DATA(u); while (*s) { if (ok_name_char[*s++] == 0) return 0; } return 1; }
static int format_string_internal(PyObject *value, const InternalFormatSpec *format, _PyUnicodeWriter *writer) { Py_ssize_t lpad; Py_ssize_t rpad; Py_ssize_t total; Py_ssize_t len; int result = -1; Py_UCS4 maxchar; assert(PyUnicode_IS_READY(value)); len = PyUnicode_GET_LENGTH(value); /* 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 ((format->width == -1 || format->width <= len) && (format->precision == -1 || format->precision >= len)) { /* Fast path */ return _PyUnicodeWriter_WriteStr(writer, value); } /* 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); maxchar = writer->maxchar; if (lpad != 0 || rpad != 0) maxchar = Py_MAX(maxchar, format->fill_char); if (PyUnicode_MAX_CHAR_VALUE(value) > maxchar) { Py_UCS4 valmaxchar = _PyUnicode_FindMaxChar(value, 0, len); maxchar = Py_MAX(maxchar, valmaxchar); } /* allocate the resulting string */ if (_PyUnicodeWriter_Prepare(writer, total, maxchar) == -1) goto done; /* Write into that space. First the padding. */ result = fill_padding(writer, len, format->fill_char, lpad, rpad); if (result == -1) goto done; /* Then the source string. */ if (len) { _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos, value, 0, len); } writer->pos += (len + rpad); result = 0; done: return result; }
/* 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, Py_UCS4 sign_char, PyObject *number, 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) { Py_ssize_t n_non_digit_non_padding; Py_ssize_t n_padding; spec->n_digits = n_end - n_start - n_remainder - (has_decimal?1:0); spec->n_lpadding = 0; spec->n_prefix = n_prefix; spec->n_decimal = has_decimal ? PyUnicode_GET_LENGTH(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 { Py_UCS4 grouping_maxchar; spec->n_grouped_digits = _PyUnicode_InsertThousandsGrouping( NULL, 0, 0, NULL, spec->n_digits, spec->n_min_width, locale->grouping, locale->thousands_sep, &grouping_maxchar); *maxchar = Py_MAX(*maxchar, grouping_maxchar); } /* 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; } } if (spec->n_lpadding || spec->n_spadding || spec->n_rpadding) *maxchar = Py_MAX(*maxchar, format->fill_char); if (spec->n_decimal) *maxchar = Py_MAX(*maxchar, PyUnicode_MAX_CHAR_VALUE(locale->decimal_point)); 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; }