Issue #23383: Cleaned up bytes formatting.

This commit is contained in:
Serhiy Storchaka 2015-02-10 23:23:12 +02:00
parent 4163cc0d9f
commit ea5ce5a15e
1 changed files with 51 additions and 140 deletions

View File

@ -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");
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);
buf[1] = '\0';
return 1; return 1;
}
error: }
Py_XDECREF(w); PyErr_SetString(PyExc_TypeError,
return -1; "%c requires an integer in range(256) or a single byte");
return 0;
} }
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 (iobj == NULL) {
if (!isnumok) {
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 */