mirror of https://github.com/python/cpython
Issue #23383: Cleaned up bytes formatting.
This commit is contained in:
parent
4163cc0d9f
commit
ea5ce5a15e
|
@ -433,105 +433,46 @@ formatfloat(PyObject *v, int flags, int prec, int type)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* format_long emulates the format codes d, u, o, x and X, and
|
|
||||||
* the F_ALT flag, for Python's long (unbounded) ints. It's not used for
|
|
||||||
* Python's regular ints.
|
|
||||||
* Return value: a new PyBytes*, or NULL if error.
|
|
||||||
* . *pbuf is set to point into it,
|
|
||||||
* *plen set to the # of chars following that.
|
|
||||||
* Caller must decref it when done using pbuf.
|
|
||||||
* The string starting at *pbuf is of the form
|
|
||||||
* "-"? ("0x" | "0X")? digit+
|
|
||||||
* "0x"/"0X" are present only for x and X conversions, with F_ALT
|
|
||||||
* set in flags. The case of hex digits will be correct,
|
|
||||||
* There will be at least prec digits, zero-filled on the left if
|
|
||||||
* necessary to get that many.
|
|
||||||
* val object to be converted
|
|
||||||
* flags bitmask of format flags; only F_ALT is looked at
|
|
||||||
* prec minimum number of digits; 0-fill on left if needed
|
|
||||||
* type a character in [duoxX]; u acts the same as d
|
|
||||||
*
|
|
||||||
* CAUTION: o, x and X conversions on regular ints can never
|
|
||||||
* produce a '-' sign, but can for Python's unbounded ints.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static PyObject *
|
|
||||||
format_long(PyObject *val, int flags, int prec, int type,
|
|
||||||
char **pbuf, int *plen)
|
|
||||||
{
|
|
||||||
PyObject *s;
|
|
||||||
PyObject *result = NULL;
|
|
||||||
|
|
||||||
s = _PyUnicode_FormatLong(val, flags & F_ALT, prec, type);
|
|
||||||
if (!s)
|
|
||||||
return NULL;
|
|
||||||
result = _PyUnicode_AsASCIIString(s, "strict");
|
|
||||||
Py_DECREF(s);
|
|
||||||
if (!result)
|
|
||||||
return NULL;
|
|
||||||
*pbuf = PyBytes_AS_STRING(result);
|
|
||||||
*plen = PyBytes_GET_SIZE(result);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Py_LOCAL_INLINE(int)
|
Py_LOCAL_INLINE(int)
|
||||||
formatchar(char *buf, size_t buflen, PyObject *v)
|
byte_converter(PyObject *arg, char *p)
|
||||||
{
|
{
|
||||||
PyObject *w = NULL;
|
if (PyBytes_Check(arg) && PyBytes_Size(arg) == 1) {
|
||||||
/* convert bytearray to bytes */
|
*p = PyBytes_AS_STRING(arg)[0];
|
||||||
if (PyByteArray_Check(v)) {
|
return 1;
|
||||||
w = PyBytes_FromObject(v);
|
|
||||||
if (w == NULL)
|
|
||||||
goto error;
|
|
||||||
v = w;
|
|
||||||
}
|
}
|
||||||
/* presume that the buffer is at least 2 characters long */
|
else if (PyByteArray_Check(arg) && PyByteArray_Size(arg) == 1) {
|
||||||
if (PyBytes_Check(v)) {
|
*p = PyByteArray_AS_STRING(arg)[0];
|
||||||
if (!PyArg_Parse(v, "c;%c requires an integer in range(256) or a single byte", &buf[0]))
|
return 1;
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
long ival = PyLong_AsLong(v);
|
long ival = PyLong_AsLong(arg);
|
||||||
if (ival == -1 && PyErr_Occurred()) {
|
if (0 <= ival && ival <= 255) {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
*p = (char)ival;
|
||||||
"%c requires an integer in range(256) or a single byte");
|
return 1;
|
||||||
goto error;
|
|
||||||
}
|
}
|
||||||
if (ival < 0 || ival > 255) {
|
|
||||||
PyErr_SetString(PyExc_TypeError,
|
|
||||||
"%c requires an integer in range(256) or a single byte");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
buf[0] = (char)ival;
|
|
||||||
}
|
}
|
||||||
Py_XDECREF(w);
|
PyErr_SetString(PyExc_TypeError,
|
||||||
buf[1] = '\0';
|
"%c requires an integer in range(256) or a single byte");
|
||||||
return 1;
|
return 0;
|
||||||
|
|
||||||
error:
|
|
||||||
Py_XDECREF(w);
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
format_obj(PyObject *v)
|
format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen)
|
||||||
{
|
{
|
||||||
PyObject *result = NULL, *w = NULL;
|
PyObject *func, *result;
|
||||||
PyObject *func;
|
|
||||||
_Py_IDENTIFIER(__bytes__);
|
_Py_IDENTIFIER(__bytes__);
|
||||||
/* convert bytearray to bytes */
|
|
||||||
if (PyByteArray_Check(v)) {
|
|
||||||
w = PyBytes_FromObject(v);
|
|
||||||
if (w == NULL)
|
|
||||||
return NULL;
|
|
||||||
v = w;
|
|
||||||
}
|
|
||||||
/* is it a bytes object? */
|
/* is it a bytes object? */
|
||||||
if (PyBytes_Check(v)) {
|
if (PyBytes_Check(v)) {
|
||||||
result = v;
|
*pbuf = PyBytes_AS_STRING(v);
|
||||||
|
*plen = PyBytes_GET_SIZE(v);
|
||||||
Py_INCREF(v);
|
Py_INCREF(v);
|
||||||
Py_XDECREF(w);
|
return v;
|
||||||
return result;
|
}
|
||||||
|
if (PyByteArray_Check(v)) {
|
||||||
|
*pbuf = PyByteArray_AS_STRING(v);
|
||||||
|
*plen = PyByteArray_GET_SIZE(v);
|
||||||
|
Py_INCREF(v);
|
||||||
|
return v;
|
||||||
}
|
}
|
||||||
/* does it support __bytes__? */
|
/* does it support __bytes__? */
|
||||||
func = _PyObject_LookupSpecial(v, &PyId___bytes__);
|
func = _PyObject_LookupSpecial(v, &PyId___bytes__);
|
||||||
|
@ -547,6 +488,8 @@ format_obj(PyObject *v)
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
*pbuf = PyBytes_AS_STRING(result);
|
||||||
|
*plen = PyBytes_GET_SIZE(result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
|
@ -573,7 +516,6 @@ _PyBytes_Format(PyObject *format, PyObject *args)
|
||||||
Py_ssize_t reslen, rescnt, fmtcnt;
|
Py_ssize_t reslen, rescnt, fmtcnt;
|
||||||
int args_owned = 0;
|
int args_owned = 0;
|
||||||
PyObject *result;
|
PyObject *result;
|
||||||
PyObject *repr;
|
|
||||||
PyObject *dict = NULL;
|
PyObject *dict = NULL;
|
||||||
if (format == NULL || !PyBytes_Check(format) || args == NULL) {
|
if (format == NULL || !PyBytes_Check(format) || args == NULL) {
|
||||||
PyErr_BadInternalCall();
|
PyErr_BadInternalCall();
|
||||||
|
@ -619,15 +561,13 @@ _PyBytes_Format(PyObject *format, PyObject *args)
|
||||||
int prec = -1;
|
int prec = -1;
|
||||||
int c = '\0';
|
int c = '\0';
|
||||||
int fill;
|
int fill;
|
||||||
int isnumok;
|
PyObject *iobj;
|
||||||
PyObject *v = NULL;
|
PyObject *v = NULL;
|
||||||
PyObject *temp = NULL;
|
PyObject *temp = NULL;
|
||||||
Py_buffer buf = {NULL, NULL};
|
const char *pbuf = NULL;
|
||||||
char *pbuf;
|
|
||||||
int sign;
|
int sign;
|
||||||
Py_ssize_t len;
|
Py_ssize_t len = 0;
|
||||||
char formatbuf[FORMATBUFLEN];
|
char onechar; /* For byte_converter() */
|
||||||
/* For format{int,char}() */
|
|
||||||
|
|
||||||
fmt++;
|
fmt++;
|
||||||
if (*fmt == '(') {
|
if (*fmt == '(') {
|
||||||
|
@ -781,37 +721,21 @@ _PyBytes_Format(PyObject *format, PyObject *args)
|
||||||
len = 1;
|
len = 1;
|
||||||
break;
|
break;
|
||||||
case 'a':
|
case 'a':
|
||||||
temp = PyObject_Repr(v);
|
temp = PyObject_ASCII(v);
|
||||||
if (temp == NULL)
|
if (temp == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
repr = PyUnicode_AsEncodedObject(temp, "ascii", "backslashreplace");
|
assert(PyUnicode_IS_ASCII(temp));
|
||||||
if (repr == NULL) {
|
pbuf = (const char *)PyUnicode_1BYTE_DATA(temp);
|
||||||
Py_DECREF(temp);
|
len = PyUnicode_GET_LENGTH(temp);
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
if (PyObject_GetBuffer(repr, &buf, PyBUF_SIMPLE) != 0) {
|
|
||||||
temp = format_obj(repr);
|
|
||||||
if (temp == NULL) {
|
|
||||||
Py_DECREF(repr);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
Py_DECREF(repr);
|
|
||||||
repr = temp;
|
|
||||||
}
|
|
||||||
pbuf = PyBytes_AS_STRING(repr);
|
|
||||||
len = PyBytes_GET_SIZE(repr);
|
|
||||||
Py_DECREF(repr);
|
|
||||||
if (prec >= 0 && len > prec)
|
if (prec >= 0 && len > prec)
|
||||||
len = prec;
|
len = prec;
|
||||||
break;
|
break;
|
||||||
case 's':
|
case 's':
|
||||||
// %s is only for 2/3 code; 3 only code should use %b
|
// %s is only for 2/3 code; 3 only code should use %b
|
||||||
case 'b':
|
case 'b':
|
||||||
temp = format_obj(v);
|
temp = format_obj(v, &pbuf, &len);
|
||||||
if (temp == NULL)
|
if (temp == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
pbuf = PyBytes_AS_STRING(temp);
|
|
||||||
len = PyBytes_GET_SIZE(temp);
|
|
||||||
if (prec >= 0 && len > prec)
|
if (prec >= 0 && len > prec)
|
||||||
len = prec;
|
len = prec;
|
||||||
break;
|
break;
|
||||||
|
@ -823,41 +747,32 @@ _PyBytes_Format(PyObject *format, PyObject *args)
|
||||||
case 'X':
|
case 'X':
|
||||||
if (c == 'i')
|
if (c == 'i')
|
||||||
c = 'd';
|
c = 'd';
|
||||||
isnumok = 0;
|
iobj = NULL;
|
||||||
if (PyNumber_Check(v)) {
|
if (PyNumber_Check(v)) {
|
||||||
PyObject *iobj=NULL;
|
|
||||||
|
|
||||||
if ((PyLong_Check(v))) {
|
if ((PyLong_Check(v))) {
|
||||||
iobj = v;
|
iobj = v;
|
||||||
Py_INCREF(iobj);
|
Py_INCREF(iobj);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
iobj = PyNumber_Long(v);
|
iobj = PyNumber_Long(v);
|
||||||
}
|
if (iobj != NULL && !PyLong_Check(iobj))
|
||||||
if (iobj!=NULL) {
|
Py_CLEAR(iobj);
|
||||||
if (PyLong_Check(iobj)) {
|
|
||||||
int ilen;
|
|
||||||
|
|
||||||
isnumok = 1;
|
|
||||||
temp = format_long(iobj, flags, prec, c,
|
|
||||||
&pbuf, &ilen);
|
|
||||||
Py_DECREF(iobj);
|
|
||||||
if (!temp)
|
|
||||||
goto error;
|
|
||||||
len = ilen;
|
|
||||||
sign = 1;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Py_DECREF(iobj);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!isnumok) {
|
if (iobj == NULL) {
|
||||||
PyErr_Format(PyExc_TypeError,
|
PyErr_Format(PyExc_TypeError,
|
||||||
"%%%c format: a number is required, "
|
"%%%c format: a number is required, "
|
||||||
"not %.200s", c, Py_TYPE(v)->tp_name);
|
"not %.200s", c, Py_TYPE(v)->tp_name);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
temp = _PyUnicode_FormatLong(iobj, flags & F_ALT, prec, c);
|
||||||
|
Py_DECREF(iobj);
|
||||||
|
if (!temp)
|
||||||
|
goto error;
|
||||||
|
assert(PyUnicode_IS_ASCII(temp));
|
||||||
|
pbuf = (const char *)PyUnicode_1BYTE_DATA(temp);
|
||||||
|
len = PyUnicode_GET_LENGTH(temp);
|
||||||
|
sign = 1;
|
||||||
if (flags & F_ZERO)
|
if (flags & F_ZERO)
|
||||||
fill = '0';
|
fill = '0';
|
||||||
break;
|
break;
|
||||||
|
@ -877,9 +792,9 @@ _PyBytes_Format(PyObject *format, PyObject *args)
|
||||||
fill = '0';
|
fill = '0';
|
||||||
break;
|
break;
|
||||||
case 'c':
|
case 'c':
|
||||||
pbuf = formatbuf;
|
pbuf = &onechar;
|
||||||
len = formatchar(pbuf, sizeof(formatbuf), v);
|
len = byte_converter(v, &onechar);
|
||||||
if (len < 0)
|
if (!len)
|
||||||
goto error;
|
goto error;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -911,12 +826,10 @@ _PyBytes_Format(PyObject *format, PyObject *args)
|
||||||
reslen += rescnt;
|
reslen += rescnt;
|
||||||
if (reslen < 0) {
|
if (reslen < 0) {
|
||||||
Py_DECREF(result);
|
Py_DECREF(result);
|
||||||
PyBuffer_Release(&buf);
|
|
||||||
Py_XDECREF(temp);
|
Py_XDECREF(temp);
|
||||||
return PyErr_NoMemory();
|
return PyErr_NoMemory();
|
||||||
}
|
}
|
||||||
if (_PyBytes_Resize(&result, reslen)) {
|
if (_PyBytes_Resize(&result, reslen)) {
|
||||||
PyBuffer_Release(&buf);
|
|
||||||
Py_XDECREF(temp);
|
Py_XDECREF(temp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -970,11 +883,9 @@ _PyBytes_Format(PyObject *format, PyObject *args)
|
||||||
if (dict && (argidx < arglen) && c != '%') {
|
if (dict && (argidx < arglen) && c != '%') {
|
||||||
PyErr_SetString(PyExc_TypeError,
|
PyErr_SetString(PyExc_TypeError,
|
||||||
"not all arguments converted during bytes formatting");
|
"not all arguments converted during bytes formatting");
|
||||||
PyBuffer_Release(&buf);
|
|
||||||
Py_XDECREF(temp);
|
Py_XDECREF(temp);
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
PyBuffer_Release(&buf);
|
|
||||||
Py_XDECREF(temp);
|
Py_XDECREF(temp);
|
||||||
} /* '%' */
|
} /* '%' */
|
||||||
} /* until end */
|
} /* until end */
|
||||||
|
|
Loading…
Reference in New Issue