summaryrefslogtreecommitdiffstats
path: root/Objects/fileobject.c
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1991-03-06 13:06:18 (GMT)
committerGuido van Rossum <guido@python.org>1991-03-06 13:06:18 (GMT)
commitce5ba841d996449810bcff72dc167e20a73481fe (patch)
tree5b009862e96fd511329047589c4e092bbe235a1b /Objects/fileobject.c
parent7ff04b39db398ef26ae0aef15112bb7bb3c51a52 (diff)
downloadcpython-ce5ba841d996449810bcff72dc167e20a73481fe.zip
cpython-ce5ba841d996449810bcff72dc167e20a73481fe.tar.gz
cpython-ce5ba841d996449810bcff72dc167e20a73481fe.tar.bz2
Fixed read() and readline() to do arbitrarily long reads.
And readline() now reads null bytes correctly. Added tell(), seek() and flush().
Diffstat (limited to 'Objects/fileobject.c')
-rw-r--r--Objects/fileobject.c215
1 files changed, 178 insertions, 37 deletions
diff --git a/Objects/fileobject.c b/Objects/fileobject.c
index 09f19e5..f038327 100644
--- a/Objects/fileobject.c
+++ b/Objects/fileobject.c
@@ -32,6 +32,8 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
#include "allobjects.h"
+#define BUF(v) GETSTRINGVALUE((stringobject *)v)
+
#include "errno.h"
#ifndef errno
extern int errno;
@@ -161,35 +163,132 @@ file_close(f, args)
}
static object *
-file_read(f, args)
+file_seek(f, args)
fileobject *f;
object *args;
{
- int n;
- object *v;
+ long offset;
+ long whence;
+
if (f->f_fp == NULL) {
err_badarg();
return NULL;
}
- if (args == NULL || !is_intobject(args)) {
+ if (args != NULL && is_intobject(args)) {
+ offset = getintvalue(args);
+ whence = 0; /* SEEK_SET */
+ }
+ else {
+ if (!getlonglongargs(args, &offset, &whence))
+ return NULL;
+ }
+ errno = 0;
+ if (fseek(f->f_fp, offset, (int)whence) != 0) {
+ if (errno == 0)
+ errno = EIO;
+ return err_errno(RuntimeError);
+ }
+ INCREF(None);
+ return None;
+}
+
+static object *
+file_tell(f, args)
+ fileobject *f;
+ object *args;
+{
+ long offset;
+ if (args != NULL || f->f_fp == NULL) {
err_badarg();
return NULL;
}
- n = getintvalue(args);
- if (n < 0) {
+ errno = 0;
+ offset = ftell(f->f_fp);
+ if (offset == -1L) {
+ if (errno == 0)
+ errno = EIO;
+ return err_errno(RuntimeError);
+ }
+ return newintobject(offset);
+}
+
+static object *
+file_flush(f, args)
+ fileobject *f;
+ object *args;
+{
+ if (args != NULL || f->f_fp == NULL) {
+ err_badarg();
+ return NULL;
+ }
+ errno = 0;
+ if (fflush(f->f_fp) != 0) {
+ if (errno == 0)
+ errno = EIO;
+ return err_errno(RuntimeError);
+ }
+ INCREF(None);
+ return None;
+}
+
+static object *
+file_read(f, args)
+ fileobject *f;
+ object *args;
+{
+ int n, n1, n2, n3;
+ object *v;
+
+ if (f->f_fp == NULL) {
err_badarg();
return NULL;
}
- v = newsizedstringobject((char *)NULL, n);
+ if (args == 0)
+ n = 0;
+ else {
+ if (!getintarg(args, &n))
+ return NULL;
+ if (n < 0) {
+ err_badarg();
+ return NULL;
+ }
+ }
+
+ n2 = n != 0 ? n : BUFSIZ;
+ v = newsizedstringobject((char *)NULL, n2);
if (v == NULL)
return NULL;
- n = fread(getstringvalue(v), 1, n, f->f_fp);
- /* EOF is reported as an empty string */
- /* XXX should detect real I/O errors? */
- resizestring(&v, n);
+ n1 = 0;
+ for (;;) {
+ n3 = fread(BUF(v)+n1, 1, n2-n1, f->f_fp);
+ /* XXX Error check? */
+ if (n3 == 0)
+ break;
+ n1 += n3;
+ if (n1 == n)
+ break;
+ if (n == 0) {
+ n2 = n1 + BUFSIZ;
+ if (resizestring(&v, n2) < 0)
+ return NULL;
+ }
+ }
+ if (n1 != n2)
+ resizestring(&v, n1);
return v;
}
+/* Read a line.
+ Without argument, or with a zero argument, read until end of line
+ or EOF, whichever comes first.
+ With a positive argument n, read at most n bytes until end of line
+ or EOF, whichever comes first.
+ Negative and non-integer arguments are illegal.
+ When EOF is hit immediately, return an empty string.
+ A newline character is returned as the last character of the buffer
+ if it is read.
+*/
+
/* XXX Should this be unified with raw_input()? */
static object *
@@ -197,46 +296,84 @@ file_readline(f, args)
fileobject *f;
object *args;
{
- int n;
+ register FILE *fp;
+ register int c;
+ register char *buf, *end;
+ int n, n1, n2;
object *v;
- if (f->f_fp == NULL) {
+
+ if ((fp = f->f_fp) == NULL) {
err_badarg();
return NULL;
}
- if (args == NULL) {
- n = 10000; /* XXX should really be unlimited */
- }
- else if (is_intobject(args)) {
- n = getintvalue(args);
+
+ if (args == NULL)
+ n = 0; /* Unlimited */
+ else {
+ if (!getintarg(args, &n))
+ return NULL;
if (n < 0) {
err_badarg();
return NULL;
}
}
- else {
- err_badarg();
- return NULL;
- }
- v = newsizedstringobject((char *)NULL, n);
+
+ n2 = n != 0 ? n : 100;
+ v = newsizedstringobject((char *)NULL, n2);
if (v == NULL)
return NULL;
-#ifndef THINK_C_3_0
- /* XXX Think C 3.0 wrongly reads up to n characters... */
- n = n+1;
-#endif
- if (fgets(getstringvalue(v), n, f->f_fp) == NULL) {
- /* EOF is reported as an empty string */
- /* XXX should detect real I/O errors? */
- n = 0;
- }
- else {
- n = strlen(getstringvalue(v));
+ buf = BUF(v);
+ end = buf + n2;
+
+ for (;;) {
+ if ((c = getc(fp)) == EOF || (*buf++ = c) == '\n')
+ break;
+ /* XXX Error check? */
+ if (buf == end) {
+ if (n != 0)
+ break;
+ n1 = n2;
+ n2 += 1000;
+ if (resizestring(&v, n2) < 0)
+ return NULL;
+ buf = BUF(v) + n1;
+ end = BUF(v) + n2;
+ }
}
- resizestring(&v, n);
+
+ n1 = buf - BUF(v);
+ if (n1 != n2)
+ resizestring(&v, n1);
return v;
}
static object *
+file_readlines(f, args)
+ fileobject *f;
+ object *args;
+{
+ object *list;
+ object *line;
+
+ if ((list = newlistobject(0)) == NULL)
+ return NULL;
+ for (;;) {
+ line = file_readline(f, args);
+ if (line != NULL && getstringsize(line) == 0) {
+ DECREF(line);
+ break;
+ }
+ if (line == NULL || addlistitem(list, line) != 0) {
+ DECREF(list);
+ XDECREF(line);
+ return NULL;
+ }
+ DECREF(line);
+ }
+ return list;
+}
+
+static object *
file_write(f, args)
fileobject *f;
object *args;
@@ -263,10 +400,14 @@ file_write(f, args)
}
static struct methodlist file_methods[] = {
- {"write", file_write},
+ {"close", file_close},
+ {"flush", file_flush},
{"read", file_read},
{"readline", file_readline},
- {"close", file_close},
+ {"readlines", file_readlines},
+ {"seek", file_seek},
+ {"tell", file_tell},
+ {"write", file_write},
{NULL, NULL} /* sentinel */
};