[Python-checkins] r68034 - sandbox/trunk/io-c/_textio.c
amaury.forgeotdarc
python-checkins at python.org
Mon Dec 29 23:29:10 CET 2008
Author: amaury.forgeotdarc
Date: Mon Dec 29 23:29:09 2008
New Revision: 68034
Log:
First version of TextIOWrapper.tell().
It crashes - switching to another machine to debug.
Modified:
sandbox/trunk/io-c/_textio.c
Modified: sandbox/trunk/io-c/_textio.c
==============================================================================
--- sandbox/trunk/io-c/_textio.c (original)
+++ sandbox/trunk/io-c/_textio.c Mon Dec 29 23:29:09 2008
@@ -751,6 +751,7 @@
PyObject *next_input = PyNumber_Add(dec_buffer, input_chunk);
if (next_input == NULL)
goto fail;
+ assert (PyBytes_Check(next_input));
Py_DECREF(dec_buffer);
Py_CLEAR(self->snapshot);
self->snapshot = Py_BuildValue("NN", dec_flags, next_input);
@@ -1051,7 +1052,7 @@
}
static PyObject *
-TextIOWrapper_buildCookie(CookieStruct *cookie, PyObject *cookieObj)
+TextIOWrapper_buildCookie(CookieStruct *cookie)
{
char buffer[sizeof(CookieStruct)];
static int one = 1;
@@ -1209,7 +1210,7 @@
goto fail;
Py_DECREF(res);
- self->snapshot = Py_BuildValue("((iy))", cookie.dec_flags, "");
+ self->snapshot = Py_BuildValue("iy", cookie.dec_flags, "");
if (self->snapshot == NULL)
goto fail;
}
@@ -1223,7 +1224,9 @@
if (input_chunk == NULL)
goto fail;
- self->snapshot = Py_BuildValue("((iO))", cookie.dec_flags, input_chunk);
+ assert (PyBytes_Check(input_chunk));
+
+ self->snapshot = Py_BuildValue("iO", cookie.dec_flags, input_chunk);
if (self->snapshot == NULL) {
Py_DECREF(input_chunk);
goto fail;
@@ -1252,6 +1255,163 @@
}
+static PyObject *
+TextIOWrapper_tell(PyTextIOWrapperObject *self, PyObject *args)
+{
+ PyObject *res;
+ PyObject *posobj = NULL;
+ CookieStruct cookie = {0,0,0,0,0};
+ PyObject *next_input;
+ Py_ssize_t chars_to_skip, chars_decoded;
+ PyObject *saved_state = NULL;
+ char *input, *input_end;
+
+ if (!self->seekable) {
+ PyErr_SetString(PyExc_IOError,
+ "underlying stream is not seekable");
+ goto fail;
+ }
+
+ res = PyObject_CallMethod((PyObject *)self, "flush", NULL);
+ if (res == NULL)
+ goto fail;
+ Py_DECREF(res);
+
+ posobj = PyObject_CallMethod(self->buffer, "tell", NULL);
+ if (posobj == NULL)
+ goto fail;
+
+ if(self->decoder == NULL || self->snapshot == NULL) {
+ assert (self->decoded_chars == NULL || PyUnicode_GetSize(self->decoded_chars) == 0);
+ return posobj;
+ }
+
+#if defined(HAVE_LARGEFILE_SUPPORT)
+ cookie.start_pos = PyLong_AsLongLong(posobj);
+#else
+ cookie.start_pos = PyLong_AsLong(posobj);
+#endif
+ if (PyErr_Occurred())
+ goto fail;
+
+ /* Skip backward to the snapshot point (see _read_chunk). */
+ if (!PyArg_Parse(self->snapshot, "(iO)", &cookie.dec_flags, &next_input))
+ goto fail;
+
+ assert (PyBytes_Check(next_input));
+
+ cookie.start_pos -= PyBytes_GET_SIZE(next_input);
+
+ /* How many decoded characters have been used up since the snapshot? */
+ if (self->decoded_chars_used == 0) {
+ /* We haven't moved from the snapshot point. */
+ Py_DECREF(posobj);
+ return TextIOWrapper_buildCookie(&cookie);
+ }
+
+ chars_to_skip = self->decoded_chars_used;
+
+ /* Starting from the snapshot position, we will walk the decoder
+ * forward until it gives us enough decoded characters.
+ */
+ saved_state = PyObject_CallMethod(self->decoder, "getstate", NULL);
+ if (saved_state == NULL)
+ goto fail;
+
+ /* Note our initial start point. */
+ res = PyObject_CallMethod(self->decoder, "setstate",
+ "((yi))", "", cookie.dec_flags);
+ if (res == NULL)
+ goto fail;
+
+ /* Feed the decoder one byte at a time. As we go, note the
+ * nearest "safe start point" before the current location
+ * (a point where the decoder has nothing buffered, so seek()
+ * can safely start from there and advance to this location).
+ */
+ chars_decoded = 0;
+ input = PyBytes_AS_STRING(next_input);
+ input_end = input + PyBytes_GET_SIZE(next_input);
+ while (input < input_end) {
+ PyObject *state;
+ char *dec_buffer;
+ Py_ssize_t dec_buffer_len;
+ int dec_flags;
+
+ PyObject *decoded = PyObject_CallMethod(
+ self->decoder, "decode", "y#", &input, 1);
+ if (decoded == NULL)
+ goto fail;
+ assert (PyUnicode_Check(decoded));
+ chars_decoded += PyUnicode_GET_SIZE(decoded);
+ Py_DECREF(decoded);
+
+ cookie.bytes_to_feed += 1;
+
+ state = PyObject_CallMethod(self->decoder, "getstate", "NULL");
+ if (state == NULL)
+ goto fail;
+ if (!PyArg_Parse(state, "(y#i)", &dec_buffer, &dec_buffer_len, &dec_flags)) {
+ Py_DECREF(state);
+ goto fail;
+ }
+ Py_DECREF(state);
+
+ if (dec_buffer_len == 0) {
+ /* Decoder buffer is empty, so this is a safe start point. */
+ cookie.start_pos += cookie.bytes_to_feed;
+ chars_to_skip -= chars_decoded;
+ cookie.dec_flags = dec_flags;
+ cookie.bytes_to_feed = 0;
+ chars_decoded = 0;
+ }
+ if (chars_decoded >= chars_to_skip)
+ break;
+ }
+ if (chars_decoded < chars_to_skip) {
+ /* We didn't get enough decoded data; signal EOF to get more. */
+ PyObject *decoded = PyObject_CallMethod(
+ self->decoder, "decode", "yi", "", /* final = */ 1);
+ if (decoded == NULL)
+ goto fail;
+ assert (PyUnicode_Check(decoded));
+ chars_decoded += PyUnicode_GET_SIZE(decoded);
+ cookie.need_eof = 1;
+
+ if (chars_decoded < chars_to_skip) {
+ PyErr_SetString(PyExc_IOError,
+ "can't reconstruct logical file position");
+ goto fail;
+ }
+ }
+
+ /* finally */
+ Py_XDECREF(posobj);
+ res = PyObject_CallMethod(self->decoder, "setstate", "(O)", saved_state);
+ Py_DECREF(saved_state);
+ if (res == NULL)
+ return NULL;
+
+ /* The returned cookie corresponds to the last safe start point. */
+ cookie.chars_to_skip = Py_SAFE_DOWNCAST(chars_to_skip, Py_ssize_t, int);
+ return TextIOWrapper_buildCookie(&cookie);
+
+ fail:
+ Py_XDECREF(posobj);
+ if (saved_state) {
+ PyObject *type, *value, *traceback;
+ PyErr_Fetch(&type, &value, &traceback);
+
+ res = PyObject_CallMethod(self->decoder, "setstate", "(O)", saved_state);
+ Py_DECREF(saved_state);
+ if (res == NULL)
+ return NULL;
+ Py_DECREF(res);
+
+ PyErr_Restore(type, value, traceback);
+ }
+ return NULL;
+}
/* Inquiries */
@@ -1356,8 +1516,8 @@
{"isatty", (PyCFunction)TextIOWrapper_isatty, METH_NOARGS},
{"seek", (PyCFunction)TextIOWrapper_seek, METH_VARARGS},
-/* {"tell", (PyCFunction)TextIOWrapper_tell, METH_NOARGS},
- {"truncate", (PyCFunction)TextIOWrapper_truncate, METH_VARARGS},
+ {"tell", (PyCFunction)TextIOWrapper_tell, METH_NOARGS},
+/* {"truncate", (PyCFunction)TextIOWrapper_truncate, METH_VARARGS},
{"readinto", (PyCFunction)TextIOWrapper_readinto, METH_VARARGS},
{"peek", (PyCFunction)TextIOWrapper_peek, METH_VARARGS},
{"read1", (PyCFunction)TextIOWrapper_read1, METH_VARARGS},
More information about the Python-checkins
mailing list