diff options
author | Georg Brandl <georg@python.org> | 2007-10-24 18:55:37 (GMT) |
---|---|---|
committer | Georg Brandl <georg@python.org> | 2007-10-24 18:55:37 (GMT) |
commit | bd1c68c94f0d5bc25b48f62c7527f51c754f2b6b (patch) | |
tree | a468fcccf4193f6d26ce71246e2596de6ffc9eec /Objects | |
parent | 97f9d4f31224e72e5c714ea7e509c4fd0044f0e2 (diff) | |
download | cpython-bd1c68c94f0d5bc25b48f62c7527f51c754f2b6b.zip cpython-bd1c68c94f0d5bc25b48f62c7527f51c754f2b6b.tar.gz cpython-bd1c68c94f0d5bc25b48f62c7527f51c754f2b6b.tar.bz2 |
Patch #1303: Adapt str8 constructor to bytes (now buffer) one.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/stringobject.c | 145 |
1 files changed, 140 insertions, 5 deletions
diff --git a/Objects/stringobject.c b/Objects/stringobject.c index 6371aa3..eba3284 100644 --- a/Objects/stringobject.c +++ b/Objects/stringobject.c @@ -3020,16 +3020,151 @@ str_subtype_new(PyTypeObject *type, PyObject *args, PyObject *kwds); static PyObject * string_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { - PyObject *x = NULL; - static char *kwlist[] = {"object", 0}; + PyObject *x = NULL, *it; + PyObject *(*iternext)(PyObject *); + const char *encoding = NULL; + const char *errors = NULL; + PyObject *new = NULL; + Py_ssize_t i, size; + static char *kwlist[] = {"object", "encoding", "errors", 0}; if (type != &PyString_Type) return str_subtype_new(type, args, kwds); - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O:str8", kwlist, &x)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:str8", kwlist, &x, + &encoding, &errors)) return NULL; - if (x == NULL) + if (x == NULL) { + if (encoding != NULL || errors != NULL) { + PyErr_SetString(PyExc_TypeError, + "encoding or errors without sequence " + "argument"); + return NULL; + } return PyString_FromString(""); - return PyObject_Str(x); + } + + if (PyUnicode_Check(x)) { + /* Encode via the codec registry */ + if (encoding == NULL) { + PyErr_SetString(PyExc_TypeError, + "string argument without an encoding"); + return NULL; + } + new = PyCodec_Encode(x, encoding, errors); + if (new == NULL) + return NULL; + /* XXX(gb): must accept bytes here since codecs output bytes + at the moment */ + if (PyBytes_Check(new)) { + PyObject *str; + str = PyString_FromString(PyBytes_AsString(new)); + Py_DECREF(new); + if (!str) + return NULL; + return str; + } + if (!PyString_Check(new)) { + PyErr_Format(PyExc_TypeError, + "encoder did not return a str8 " + "object (type=%.400s)", + Py_Type(new)->tp_name); + Py_DECREF(new); + return NULL; + } + return new; + } + + /* If it's not unicode, there can't be encoding or errors */ + if (encoding != NULL || errors != NULL) { + PyErr_SetString(PyExc_TypeError, + "encoding or errors without a string argument"); + return NULL; + } + + /* Use the modern buffer interface */ + if (PyObject_CheckBuffer(x)) { + Py_buffer view; + if (PyObject_GetBuffer(x, &view, PyBUF_FULL_RO) < 0) + return NULL; + new = PyString_FromStringAndSize(NULL, view.len); + if (!new) + goto fail; + // XXX(brett.cannon): Better way to get to internal buffer? + if (PyBuffer_ToContiguous(((PyStringObject *)new)->ob_sval, + &view, view.len, 'C') < 0) + goto fail; + PyObject_ReleaseBuffer(x, &view); + return new; + fail: + Py_XDECREF(new); + PyObject_ReleaseBuffer(x, &view); + return NULL; + } + + /* For the iterator version, create a string object and resize as needed. */ + /* XXX(gb): is 64 a good value? also, optimize this if length is known */ + size = 64; + new = PyString_FromStringAndSize(NULL, size); + if (new == NULL) + return NULL; + + /* XXX Optimize this if the arguments is a list, tuple */ + + /* Get the iterator */ + it = PyObject_GetIter(x); + if (it == NULL) + goto error; + // XXX(brett.cannon): No API for this? + iternext = *Py_Type(it)->tp_iternext; + + /* Run the iterator to exhaustion */ + for (i = 0; ; i++) { + PyObject *item; + Py_ssize_t value; + + /* Get the next item */ + item = iternext(it); + if (item == NULL) { + if (PyErr_Occurred()) { + if (!PyErr_ExceptionMatches(PyExc_StopIteration)) + goto error; + PyErr_Clear(); + } + break; + } + + /* Interpret it as an int (__index__) */ + value = PyNumber_AsSsize_t(item, PyExc_ValueError); + Py_DECREF(item); + if (value == -1 && PyErr_Occurred()) + goto error; + + /* Range check */ + if (value < 0 || value >= 256) { + PyErr_SetString(PyExc_ValueError, + "bytes must be in range(0, 256)"); + goto error; + } + + /* Append the byte */ + if (i >= size) { + size *= 2; + if (_PyString_Resize(&new, size) < 0) + goto error; + } + ((PyStringObject *)new)->ob_sval[i] = value; + } + _PyString_Resize(&new, i); + + /* Clean up and return success */ + Py_DECREF(it); + return new; + + error: + /* Error handling when it != NULL */ + Py_XDECREF(it); + Py_DECREF(new); + return NULL; } static PyObject * |