]> granicus.if.org Git - python/commitdiff
Restructured get_line() for clarity and speed.
authorGuido van Rossum <guido@python.org>
Fri, 5 Jan 2001 14:43:05 +0000 (14:43 +0000)
committerGuido van Rossum <guido@python.org>
Fri, 5 Jan 2001 14:43:05 +0000 (14:43 +0000)
- The raw_input() functionality is moved to a separate function.

- Drop GNU getline() in favor of getc_unlocked(), which exists on more
  platforms (and is even a tad faster on my system).

Objects/fileobject.c

index ea8fe9dccfe909e5bc01f8f8aa4db20d5159785b..35d1034362402b6c565e402a48e708c473d60f71 100644 (file)
@@ -639,49 +639,28 @@ file_readinto(PyFileObject *f, PyObject *args)
    Size argument interpretation:
    > 0: max length;
    = 0: read arbitrary line;
-   < 0: strip trailing '\n', raise EOFError if EOF reached immediately
+   < 0: illegal (use get_line_raw() instead)
 */
 
+#ifdef HAVE_GETC_UNLOCKED
+#define GETC(f) getc_unlocked(f)
+#define FLOCKFILE(f) flockfile(f)
+#define FUNLOCKFILE(f) funlockfile(f)
+#else
+#define GETC(f) getc(f)
+#define FLOCKFILE(f)
+#define FUNLOCKFILE(f)
+#endif
+
 static PyObject *
 get_line(PyFileObject *f, int n)
 {
-       register FILE *fp = f->f_fp;
-       register int c;
+       FILE *fp = f->f_fp;
+       int c;
        char *buf, *end;
        size_t n1, n2;
        PyObject *v;
 
-#if defined(HAVE_GETLINE) && defined(_GNU_SOURCE)
-       /* Use GNU libc extension getline() for arbitrary-sized lines */
-       if (n == 0) {
-               size_t size = 0;
-               buf = NULL;
-               Py_BEGIN_ALLOW_THREADS
-               n1 = getline(&buf, &size, fp);
-               Py_END_ALLOW_THREADS
-               if (n1 == -1) {
-                       if (buf){
-                               free(buf);
-                       }
-                       clearerr(fp);
-                       if (PyErr_CheckSignals()) {
-                               return NULL;
-                       }
-                       if (n < 0 && feof(fp)) {
-                               PyErr_SetString(PyExc_EOFError,
-                                               "EOF when reading a line");
-                               return NULL;
-                       }
-                       return PyString_FromStringAndSize(NULL, 0);
-               }
-               /* No error */
-               
-               v = PyString_FromStringAndSize(buf, n1);
-               free(buf);
-               return v;
-       }
-#endif
-
        n2 = n > 0 ? n : 100;
        v = PyString_FromStringAndSize((char *)NULL, n2);
        if (v == NULL)
@@ -689,48 +668,40 @@ get_line(PyFileObject *f, int n)
        buf = BUF(v);
        end = buf + n2;
 
-       Py_BEGIN_ALLOW_THREADS
        for (;;) {
-               if ((c = getc(fp)) == EOF) {
+               Py_BEGIN_ALLOW_THREADS
+               FLOCKFILE(fp);
+               while ((c = GETC(fp)) != EOF &&
+                      (*buf++ = c) != '\n' &&
+                       buf != end)
+                       ;
+               FUNLOCKFILE(fp);
+               Py_END_ALLOW_THREADS
+               if (c == '\n')
+                       break;
+               if (c == EOF) {
                        clearerr(fp);
-                       Py_BLOCK_THREADS
                        if (PyErr_CheckSignals()) {
                                Py_DECREF(v);
                                return NULL;
                        }
-                       if (n < 0 && buf == BUF(v)) {
-                               Py_DECREF(v);
-                               PyErr_SetString(PyExc_EOFError,
-                                          "EOF when reading a line");
-                               return NULL;
-                       }
-                       Py_UNBLOCK_THREADS
                        break;
                }
-               if ((*buf++ = c) == '\n') {
-                       if (n < 0)
-                               buf--;
+               /* Must be because buf == end */
+               if (n > 0)
                        break;
+               n1 = n2;
+               n2 += 1000;
+               if (n2 > INT_MAX) {
+                       PyErr_SetString(PyExc_OverflowError,
+                           "line is longer than a Python string can hold");
+                       return NULL;
                }
-               if (buf == end) {
-                       if (n > 0)
-                               break;
-                       n1 = n2;
-                       n2 += 1000;
-                       if (n2 > INT_MAX) {
-                               PyErr_SetString(PyExc_OverflowError,
-                                       "line is longer than a Python string can hold");
-                               return NULL;
-                       }
-                       Py_BLOCK_THREADS
-                       if (_PyString_Resize(&v, n2) < 0)
-                               return NULL;
-                       Py_UNBLOCK_THREADS
-                       buf = BUF(v) + n1;
-                       end = BUF(v) + n2;
-               }
+               if (_PyString_Resize(&v, n2) < 0)
+                       return NULL;
+               buf = BUF(v) + n1;
+               end = BUF(v) + n2;
        }
-       Py_END_ALLOW_THREADS
 
        n1 = buf - BUF(v);
        if (n1 != n2)
@@ -738,6 +709,25 @@ get_line(PyFileObject *f, int n)
        return v;
 }
 
+/* Internal routine to get a line for raw_input():
+   strip trailing '\n', raise EOFError if EOF reached immediately
+*/
+
+static PyObject *
+get_line_raw(PyFileObject *f)
+{
+       PyObject *line;
+
+       line = get_line(f, 0);
+       if (line == NULL || PyString_GET_SIZE(line) > 0)
+               return line;
+       else {
+               Py_DECREF(line);
+               PyErr_SetString(PyExc_EOFError, "EOF when reading a line");
+               return NULL;
+       }
+}
+
 /* External C interface */
 
 PyObject *
@@ -796,7 +786,10 @@ PyFile_GetLine(PyObject *f, int n)
        }
        if (((PyFileObject*)f)->f_fp == NULL)
                return err_closed();
-       return get_line((PyFileObject *)f, n);
+       if (n < 0)
+               return get_line_raw((PyFileObject *)f);
+       else
+               return get_line((PyFileObject *)f, n);
 }
 
 /* Python method */