summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2000-03-13 16:27:06 (GMT)
committerGuido van Rossum <guido@python.org>2000-03-13 16:27:06 (GMT)
commitee70ad1e527e67232c61cf47819a0fc264eca435 (patch)
treeb993a835d4c1f849965696bdeb3d70467ec07cc8
parentd724b23420f8e9d73a656c941c45b234e08ff9d6 (diff)
downloadcpython-ee70ad1e527e67232c61cf47819a0fc264eca435.zip
cpython-ee70ad1e527e67232c61cf47819a0fc264eca435.tar.gz
cpython-ee70ad1e527e67232c61cf47819a0fc264eca435.tar.bz2
Checking in the new, improve file.writelines() code.
This (1) avoids thread unsafety whereby another thread could zap the list while we were using it, and (2) now supports writing arbitrary sequences of strings.
-rw-r--r--Objects/fileobject.c102
1 files changed, 78 insertions, 24 deletions
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 60c113f..c8b083e 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -890,40 +890,94 @@ file_writelines(f, args)
PyFileObject *f;
PyObject *args;
{
- int i, n;
+#define CHUNKSIZE 1000
+ PyObject *list, *line;
+ PyObject *result;
+ int i, j, index, len, nwritten, islist;
+
if (f->f_fp == NULL)
return err_closed();
- if (args == NULL || !PyList_Check(args)) {
+ if (args == NULL || !PySequence_Check(args)) {
PyErr_SetString(PyExc_TypeError,
- "writelines() requires list of strings");
+ "writelines() requires sequence of strings");
return NULL;
}
- n = PyList_Size(args);
- f->f_softspace = 0;
- Py_BEGIN_ALLOW_THREADS
- errno = 0;
- for (i = 0; i < n; i++) {
- PyObject *line = PyList_GetItem(args, i);
- int len;
- int nwritten;
- if (!PyString_Check(line)) {
- Py_BLOCK_THREADS
- PyErr_SetString(PyExc_TypeError,
- "writelines() requires list of strings");
+ islist = PyList_Check(args);
+
+ /* Strategy: slurp CHUNKSIZE lines into a private list,
+ checking that they are all strings, then write that list
+ without holding the interpreter lock, then come back for more. */
+ index = 0;
+ if (islist)
+ list = NULL;
+ else {
+ list = PyList_New(CHUNKSIZE);
+ if (list == NULL)
return NULL;
+ }
+ result = NULL;
+
+ for (;;) {
+ if (islist) {
+ Py_XDECREF(list);
+ list = PyList_GetSlice(args, index, index+CHUNKSIZE);
+ if (list == NULL)
+ return NULL;
+ j = PyList_GET_SIZE(list);
}
- len = PyString_Size(line);
- nwritten = fwrite(PyString_AsString(line), 1, len, f->f_fp);
- if (nwritten != len) {
- Py_BLOCK_THREADS
- PyErr_SetFromErrno(PyExc_IOError);
- clearerr(f->f_fp);
- return NULL;
+ else {
+ for (j = 0; j < CHUNKSIZE; j++) {
+ line = PySequence_GetItem(args, index+j);
+ if (line == NULL) {
+ if (PyErr_ExceptionMatches(
+ PyExc_IndexError))
+ {
+ PyErr_Clear();
+ break;
+ }
+ /* Some other error occurred.
+ XXX We may lose some output. */
+ goto error;
+ }
+ if (!PyString_Check(line)) {
+ Py_DECREF(line);
+ PyErr_SetString(PyExc_TypeError,
+ "writelines() requires sequences of strings");
+ goto error;
+ }
+ PyList_SetItem(list, j, line);
+ }
}
+ if (j == 0)
+ break;
+
+ Py_BEGIN_ALLOW_THREADS
+ f->f_softspace = 0;
+ errno = 0;
+ for (i = 0; i < j; i++) {
+ line = PyList_GET_ITEM(list, i);
+ len = PyString_GET_SIZE(line);
+ nwritten = fwrite(PyString_AS_STRING(line),
+ 1, len, f->f_fp);
+ if (nwritten != len) {
+ Py_BLOCK_THREADS
+ PyErr_SetFromErrno(PyExc_IOError);
+ clearerr(f->f_fp);
+ goto error;
+ }
+ }
+ Py_END_ALLOW_THREADS
+
+ if (j < CHUNKSIZE)
+ break;
+ index += CHUNKSIZE;
}
- Py_END_ALLOW_THREADS
+
Py_INCREF(Py_None);
- return Py_None;
+ result = Py_None;
+ error:
+ Py_XDECREF(list);
+ return result;
}
static PyMethodDef file_methods[] = {