diff options
Diffstat (limited to 'Objects/bytesobject.c')
-rw-r--r-- | Objects/bytesobject.c | 205 |
1 files changed, 123 insertions, 82 deletions
diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index da2e23f..18d0f57 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -5,11 +5,8 @@ #define PY_SSIZE_T_CLEAN #include "Python.h" #include "structmember.h" +#include "bytes_methods.h" -/* The nullbytes are used by the stringlib during partition. - * If partition is removed from bytes, nullbytes and its helper - * Init/Fini should also be removed. - */ static PyBytesObject *nullbytes = NULL; void @@ -37,15 +34,20 @@ PyBytes_Init(void) static int _getbytevalue(PyObject* arg, int *value) { - PyObject *intarg = PyNumber_Int(arg); - if (! intarg) - return 0; - *value = PyInt_AsLong(intarg); - Py_DECREF(intarg); - if (*value < 0 || *value >= 256) { - PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)"); + long face_value; + + if (PyInt_Check(arg)) { + face_value = PyInt_AsLong(arg); + if (face_value < 0 || face_value >= 256) { + PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)"); + return 0; + } + } else { + PyErr_Format(PyExc_TypeError, "an integer is required"); return 0; } + + *value = face_value; return 1; } @@ -80,9 +82,7 @@ _getbuffer(PyObject *obj, Py_buffer *view) { PyBufferProcs *buffer = Py_Type(obj)->tp_as_buffer; - if (buffer == NULL || - PyUnicode_Check(obj) || - buffer->bf_getbuffer == NULL) + if (buffer == NULL || buffer->bf_getbuffer == NULL) { PyErr_Format(PyExc_TypeError, "Type %.100s doesn't support the buffer API", @@ -1035,13 +1035,18 @@ bytes_dealloc(PyBytesObject *self) #define STRINGLIB_CHAR char #define STRINGLIB_CMP memcmp #define STRINGLIB_LEN PyBytes_GET_SIZE +#define STRINGLIB_STR PyBytes_AS_STRING #define STRINGLIB_NEW PyBytes_FromStringAndSize #define STRINGLIB_EMPTY nullbytes +#define STRINGLIB_CHECK_EXACT PyBytes_CheckExact +#define STRINGLIB_MUTABLE 1 #include "stringlib/fastsearch.h" #include "stringlib/count.h" #include "stringlib/find.h" #include "stringlib/partition.h" +#include "stringlib/ctype.h" +#include "stringlib/transmogrify.h" /* The following Py_LOCAL_INLINE and Py_LOCAL functions @@ -1088,7 +1093,6 @@ bytes_find_internal(PyBytesObject *self, PyObject *args, int dir) return res; } - PyDoc_STRVAR(find__doc__, "B.find(sub [,start [,end]]) -> int\n\ \n\ @@ -1118,27 +1122,25 @@ static PyObject * bytes_count(PyBytesObject *self, PyObject *args) { PyObject *sub_obj; - const char *str = PyBytes_AS_STRING(self), *sub; - Py_ssize_t sub_len; + const char *str = PyBytes_AS_STRING(self); Py_ssize_t start = 0, end = PY_SSIZE_T_MAX; + Py_buffer vsub; + PyObject *count_obj; if (!PyArg_ParseTuple(args, "O|O&O&:count", &sub_obj, _PyEval_SliceIndex, &start, _PyEval_SliceIndex, &end)) return NULL; - if (PyBytes_Check(sub_obj)) { - sub = PyBytes_AS_STRING(sub_obj); - sub_len = PyBytes_GET_SIZE(sub_obj); - } - /* XXX --> use the modern buffer interface */ - else if (PyObject_AsCharBuffer(sub_obj, &sub, &sub_len)) + if (_getbuffer(sub_obj, &vsub) < 0) return NULL; _adjust_indices(&start, &end, PyBytes_GET_SIZE(self)); - return PyInt_FromSsize_t( - stringlib_count(str + start, end - start, sub, sub_len) + count_obj = PyInt_FromSsize_t( + stringlib_count(str + start, end - start, vsub.buf, vsub.len) ); + PyObject_ReleaseBuffer(sub_obj, &vsub); + return count_obj; } @@ -1210,36 +1212,39 @@ _bytes_tailmatch(PyBytesObject *self, PyObject *substr, Py_ssize_t start, Py_ssize_t end, int direction) { Py_ssize_t len = PyBytes_GET_SIZE(self); - Py_ssize_t slen; - const char* sub; const char* str; + Py_buffer vsubstr; + int rv; - if (PyBytes_Check(substr)) { - sub = PyBytes_AS_STRING(substr); - slen = PyBytes_GET_SIZE(substr); - } - /* XXX --> Use the modern buffer interface */ - else if (PyObject_AsCharBuffer(substr, &sub, &slen)) - return -1; str = PyBytes_AS_STRING(self); + if (_getbuffer(substr, &vsubstr) < 0) + return -1; + _adjust_indices(&start, &end, len); if (direction < 0) { /* startswith */ - if (start+slen > len) - return 0; + if (start+vsubstr.len > len) { + rv = 0; + goto done; + } } else { /* endswith */ - if (end-start < slen || start > len) - return 0; + if (end-start < vsubstr.len || start > len) { + rv = 0; + goto done; + } - if (end-slen > start) - start = end - slen; + if (end-vsubstr.len > start) + start = end - vsubstr.len; } - if (end-start >= slen) - return ! memcmp(str+start, sub, slen); - return 0; + if (end-start >= vsubstr.len) + rv = ! memcmp(str+start, vsubstr.buf, vsubstr.len); + +done: + PyObject_ReleaseBuffer(substr, &vsubstr); + return rv; } @@ -1324,7 +1329,6 @@ bytes_endswith(PyBytesObject *self, PyObject *args) } - PyDoc_STRVAR(translate__doc__, "B.translate(table [,deletechars]) -> bytes\n\ \n\ @@ -1340,53 +1344,47 @@ bytes_translate(PyBytesObject *self, PyObject *args) register const char *table; register Py_ssize_t i, c, changed = 0; PyObject *input_obj = (PyObject*)self; - const char *table1, *output_start, *del_table=NULL; - Py_ssize_t inlen, tablen, dellen = 0; + const char *output_start; + Py_ssize_t inlen; PyObject *result; int trans_table[256]; PyObject *tableobj, *delobj = NULL; + Py_buffer vtable, vdel; if (!PyArg_UnpackTuple(args, "translate", 1, 2, &tableobj, &delobj)) return NULL; - if (PyBytes_Check(tableobj)) { - table1 = PyBytes_AS_STRING(tableobj); - tablen = PyBytes_GET_SIZE(tableobj); - } - /* XXX -> Use the modern buffer interface */ - else if (PyObject_AsCharBuffer(tableobj, &table1, &tablen)) + if (_getbuffer(tableobj, &vtable) < 0) return NULL; - if (tablen != 256) { + if (vtable.len != 256) { PyErr_SetString(PyExc_ValueError, "translation table must be 256 characters long"); - return NULL; + result = NULL; + goto done; } if (delobj != NULL) { - if (PyBytes_Check(delobj)) { - del_table = PyBytes_AS_STRING(delobj); - dellen = PyBytes_GET_SIZE(delobj); + if (_getbuffer(delobj, &vdel) < 0) { + result = NULL; + goto done; } - /* XXX -> use the modern buffer interface */ - else if (PyObject_AsCharBuffer(delobj, &del_table, &dellen)) - return NULL; } else { - del_table = NULL; - dellen = 0; + vdel.buf = NULL; + vdel.len = 0; } - table = table1; + table = (const char *)vtable.buf; inlen = PyBytes_GET_SIZE(input_obj); result = PyBytes_FromStringAndSize((char *)NULL, inlen); if (result == NULL) - return NULL; + goto done; output_start = output = PyBytes_AsString(result); input = PyBytes_AS_STRING(input_obj); - if (dellen == 0) { + if (vdel.len == 0) { /* If no deletions are required, use faster code */ for (i = inlen; --i >= 0; ) { c = Py_CHARMASK(*input++); @@ -1394,17 +1392,18 @@ bytes_translate(PyBytesObject *self, PyObject *args) changed = 1; } if (changed || !PyBytes_CheckExact(input_obj)) - return result; + goto done; Py_DECREF(result); Py_INCREF(input_obj); - return input_obj; + result = input_obj; + goto done; } for (i = 0; i < 256; i++) trans_table[i] = Py_CHARMASK(table[i]); - for (i = 0; i < dellen; i++) - trans_table[(int) Py_CHARMASK(del_table[i])] = -1; + for (i = 0; i < vdel.len; i++) + trans_table[(int) Py_CHARMASK( ((unsigned char*)vdel.buf)[i] )] = -1; for (i = inlen; --i >= 0; ) { c = Py_CHARMASK(*input++); @@ -1416,11 +1415,17 @@ bytes_translate(PyBytesObject *self, PyObject *args) if (!changed && PyBytes_CheckExact(input_obj)) { Py_DECREF(result); Py_INCREF(input_obj); - return input_obj; + result = input_obj; + goto done; } /* Fix the size of the resulting string */ if (inlen > 0) PyBytes_Resize(result, output - output_start); + +done: + PyObject_ReleaseBuffer(tableobj, &vtable); + if (delobj != NULL) + PyObject_ReleaseBuffer(delobj, &vdel); return result; } @@ -2021,6 +2026,7 @@ replace(PyBytesObject *self, } } + PyDoc_STRVAR(replace__doc__, "B.replace (old, new[, count]) -> bytes\n\ \n\ @@ -2133,7 +2139,6 @@ split_char(const char *s, Py_ssize_t len, char ch, Py_ssize_t maxcount) return NULL; } -#define ISSPACE(c) (isspace(Py_CHARMASK(c)) && ((c) & 0x80) == 0) Py_LOCAL_INLINE(PyObject *) split_whitespace(const char *s, Py_ssize_t len, Py_ssize_t maxcount) @@ -2459,6 +2464,10 @@ end of the bytes."); static PyObject * bytes_extend(PyBytesObject *self, PyObject *arg) { + /* XXX(gps): The docstring says any iterable int will do but the + * bytes_setslice code only accepts something supporting PEP 3118. + * A list or tuple of 0 <= int <= 255 is supposed to work. */ + /* bug being tracked on: http://bugs.python.org/issue1283 */ if (bytes_setslice(self, Py_Size(self), Py_Size(self), arg) == -1) return NULL; Py_RETURN_NONE; @@ -2852,11 +2861,11 @@ bytes.fromhex('10 2030') -> bytes([0x10, 0x20, 0x30])."); static int hex_digit_to_int(int c) { - if (isdigit(c)) + if (ISDIGIT(c)) return c - '0'; else { - if (isupper(c)) - c = tolower(c); + if (ISUPPER(c)) + c = TOLOWER(c); if (c >= 'a' && c <= 'f') return c - 'a' + 10; } @@ -2866,26 +2875,34 @@ hex_digit_to_int(int c) static PyObject * bytes_fromhex(PyObject *cls, PyObject *args) { - PyObject *newbytes; - char *hex, *buf; - Py_ssize_t len, byteslen, i, j; + PyObject *newbytes, *hexobj; + char *buf; + unsigned char *hex; + Py_ssize_t byteslen, i, j; int top, bot; + Py_buffer vhex; + + if (!PyArg_ParseTuple(args, "O:fromhex", &hexobj)) + return NULL; - if (!PyArg_ParseTuple(args, "s#:fromhex", &hex, &len)) + if (_getbuffer(hexobj, &vhex) < 0) return NULL; - byteslen = len / 2; /* max length if there are no spaces */ + byteslen = vhex.len / 2; /* max length if there are no spaces */ + hex = vhex.buf; newbytes = PyBytes_FromStringAndSize(NULL, byteslen); - if (!newbytes) + if (!newbytes) { + PyObject_ReleaseBuffer(hexobj, &vhex); return NULL; + } buf = PyBytes_AS_STRING(newbytes); - for (i = j = 0; i < len; i += 2) { + for (i = j = 0; i < vhex.len; i += 2) { /* skip over spaces in the input */ while (Py_CHARMASK(hex[i]) == ' ') i++; - if (i >= len) + if (i >= vhex.len) break; top = hex_digit_to_int(Py_CHARMASK(hex[i])); bot = hex_digit_to_int(Py_CHARMASK(hex[i+1])); @@ -2900,10 +2917,12 @@ bytes_fromhex(PyObject *cls, PyObject *args) } if (PyBytes_Resize(newbytes, j) < 0) goto error; + PyObject_ReleaseBuffer(hexobj, &vhex); return newbytes; error: Py_DECREF(newbytes); + PyObject_ReleaseBuffer(hexobj, &vhex); return NULL; } @@ -2955,6 +2974,19 @@ bytes_methods[] = { {"endswith", (PyCFunction)bytes_endswith, METH_VARARGS, endswith__doc__}, {"startswith", (PyCFunction)bytes_startswith, METH_VARARGS, startswith__doc__}, + {"lower", (PyCFunction)stringlib_lower, METH_NOARGS, _Py_lower__doc__}, + {"upper", (PyCFunction)stringlib_upper, METH_NOARGS, _Py_upper__doc__}, + {"capitalize", (PyCFunction)stringlib_capitalize, METH_NOARGS, + _Py_capitalize__doc__}, + {"swapcase", (PyCFunction)stringlib_swapcase, METH_NOARGS, + _Py_swapcase__doc__}, + {"islower", (PyCFunction)stringlib_islower, METH_NOARGS,_Py_islower__doc__}, + {"isupper", (PyCFunction)stringlib_isupper, METH_NOARGS,_Py_isupper__doc__}, + {"isspace", (PyCFunction)stringlib_isspace, METH_NOARGS,_Py_isspace__doc__}, + {"isdigit", (PyCFunction)stringlib_isdigit, METH_NOARGS,_Py_isdigit__doc__}, + {"istitle", (PyCFunction)stringlib_istitle, METH_NOARGS,_Py_istitle__doc__}, + {"isalpha", (PyCFunction)stringlib_isalpha, METH_NOARGS,_Py_isalpha__doc__}, + {"isalnum", (PyCFunction)stringlib_isalnum, METH_NOARGS,_Py_isalnum__doc__}, {"replace", (PyCFunction)bytes_replace, METH_VARARGS, replace__doc__}, {"translate", (PyCFunction)bytes_translate, METH_VARARGS, translate__doc__}, {"partition", (PyCFunction)bytes_partition, METH_O, partition__doc__}, @@ -2975,6 +3007,15 @@ bytes_methods[] = { {"fromhex", (PyCFunction)bytes_fromhex, METH_VARARGS|METH_CLASS, fromhex_doc}, {"join", (PyCFunction)bytes_join, METH_O, join_doc}, + {"title", (PyCFunction)stringlib_title, METH_NOARGS, _Py_title__doc__}, + {"ljust", (PyCFunction)stringlib_ljust, METH_VARARGS, ljust__doc__}, + {"rjust", (PyCFunction)stringlib_rjust, METH_VARARGS, rjust__doc__}, + {"center", (PyCFunction)stringlib_center, METH_VARARGS, center__doc__}, + {"zfill", (PyCFunction)stringlib_zfill, METH_VARARGS, zfill__doc__}, + {"expandtabs", (PyCFunction)stringlib_expandtabs, METH_VARARGS, + expandtabs__doc__}, + {"splitlines", (PyCFunction)stringlib_splitlines, METH_VARARGS, + splitlines__doc__}, {"__reduce__", (PyCFunction)bytes_reduce, METH_NOARGS, reduce_doc}, {NULL} }; |