home *** CD-ROM | disk | FTP | other *** search
- /***********************************************************
- Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
- The Netherlands.
-
- All Rights Reserved
-
- Permission to use, copy, modify, and distribute this software and its
- documentation for any purpose and without fee is hereby granted,
- provided that the above copyright notice appear in all copies and that
- both that copyright notice and this permission notice appear in
- supporting documentation, and that the names of Stichting Mathematisch
- Centrum or CWI or Corporation for National Research Initiatives or
- CNRI not be used in advertising or publicity pertaining to
- distribution of the software without specific, written prior
- permission.
-
- While CWI is the initial source for this software, a modified version
- is made available by the Corporation for National Research Initiatives
- (CNRI) at the Internet address ftp://ftp.python.org.
-
- STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
- REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
- MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
- CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
- DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
- PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
- TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- PERFORMANCE OF THIS SOFTWARE.
-
- ******************************************************************/
-
- /* File object implementation */
-
- #include "allobjects.h"
- #include "modsupport.h"
- #include "structmember.h"
- #include "ceval.h"
-
- #ifdef THINK_C
- #define HAVE_FOPENRF
- #endif
- #ifdef __MWERKS__
- /* Mwerks fopen() doesn't always set errno */
- #define NO_FOPEN_ERRNO
- #endif
-
- #define BUF(v) GETSTRINGVALUE((stringobject *)v)
-
- #include <errno.h>
-
- typedef struct {
- OB_HEAD
- FILE *f_fp;
- object *f_name;
- object *f_mode;
- int (*f_close) PROTO((FILE *));
- int f_softspace; /* Flag used by 'print' command */
- } fileobject;
-
- #include "protos/fileobject_protos.h"
-
- FILE *
- getfilefile(f)
- object *f;
- {
- if (f == NULL || !is_fileobject(f))
- return NULL;
- else
- return ((fileobject *)f)->f_fp;
- }
-
- object *
- getfilename(f)
- object *f;
- {
- if (f == NULL || !is_fileobject(f))
- return NULL;
- else
- return ((fileobject *)f)->f_name;
- }
-
- object *
- newopenfileobject(fp, name, mode, close)
- FILE *fp;
- char *name;
- char *mode;
- int (*close) FPROTO((FILE *));
- {
- fileobject *f = NEWOBJ(fileobject, &Filetype);
- if (f == NULL)
- return NULL;
- f->f_fp = NULL;
- f->f_name = newstringobject(name);
- f->f_mode = newstringobject(mode);
- f->f_close = close;
- f->f_softspace = 0;
- if (f->f_name == NULL || f->f_mode == NULL) {
- DECREF(f);
- return NULL;
- }
- f->f_fp = fp;
- return (object *) f;
- }
-
- object *
- newfileobject(name, mode)
- char *name, *mode;
- {
- extern int fclose PROTO((FILE *));
- fileobject *f;
- f = (fileobject *) newopenfileobject((FILE *)NULL, name, mode, fclose);
- if (f == NULL)
- return NULL;
- #ifdef HAVE_FOPENRF
- if (*mode == '*') {
- FILE *fopenRF();
- f->f_fp = fopenRF(name, mode+1);
- }
- else
- #endif
- {
- BGN_SAVE
- f->f_fp = fopen(name, mode);
- END_SAVE
- }
- if (f->f_fp == NULL) {
- #ifdef NO_FOPEN_ERRNO
- if ( errno == 0 ) {
- err_setstr(IOError, "Cannot open file");
- DECREF(f);
- return NULL;
- }
- #endif
- err_errno(IOError);
- DECREF(f);
- return NULL;
- }
- return (object *)f;
- }
-
- void
- setfilebufsize(f, bufsize)
- object *f;
- int bufsize;
- {
- if (bufsize >= 0) {
- #ifdef HAVE_SETVBUF
- int type;
- switch (bufsize) {
- case 0:
- type = _IONBF;
- break;
- case 1:
- type = _IOLBF;
- bufsize = BUFSIZ;
- break;
- default:
- type = _IOFBF;
- }
- setvbuf(((fileobject *)f)->f_fp, (char *)NULL, type, bufsize);
- #endif /* HAVE_SETVBUF */
- }
- }
-
- static object *
- err_closed()
- {
- err_setstr(ValueError, "I/O operation on closed file");
- return NULL;
- }
-
- /* Methods */
-
- static void
- file_dealloc(f)
- fileobject *f;
- {
- if (f->f_fp != NULL && f->f_close != NULL) {
- BGN_SAVE
- (*f->f_close)(f->f_fp);
- END_SAVE
- }
- if (f->f_name != NULL)
- DECREF(f->f_name);
- if (f->f_mode != NULL)
- DECREF(f->f_mode);
- free((char *)f);
- }
-
- static object *
- file_repr(f)
- fileobject *f;
- {
- char buf[300];
- sprintf(buf, "<%s file '%.256s', mode '%.10s' at %lx>",
- f->f_fp == NULL ? "closed" : "open",
- getstringvalue(f->f_name),
- getstringvalue(f->f_mode),
- (long)f);
- return newstringobject(buf);
- }
-
- static object *
- file_close(f, args)
- fileobject *f;
- object *args;
- {
- int sts = 0;
- if (!getnoarg(args))
- return NULL;
- if (f->f_fp != NULL) {
- if (f->f_close != NULL) {
- BGN_SAVE
- errno = 0;
- sts = (*f->f_close)(f->f_fp);
- END_SAVE
- }
- f->f_fp = NULL;
- }
- if (sts == EOF)
- return err_errno(IOError);
- if (sts != 0)
- return newintobject((long)sts);
- INCREF(None);
- return None;
- }
-
- static object *
- file_seek(f, args)
- fileobject *f;
- object *args;
- {
- long offset;
- int whence;
- int ret;
-
- if (f->f_fp == NULL)
- return err_closed();
- whence = 0;
- if (!getargs(args, "l", &offset)) {
- err_clear();
- if (!getargs(args, "(li)", &offset, &whence))
- return NULL;
- }
- BGN_SAVE
- errno = 0;
- ret = fseek(f->f_fp, offset, whence);
- END_SAVE
- if (ret != 0) {
- err_errno(IOError);
- clearerr(f->f_fp);
- return NULL;
- }
- INCREF(None);
- return None;
- }
-
- #ifdef HAVE_FTRUNCATE
- static object *
- file_truncate(f, args)
- fileobject *f;
- object *args;
- {
- long newsize;
- int ret;
-
- if (f->f_fp == NULL)
- return err_closed();
- if (!getargs(args, "l", &newsize)) {
- err_clear();
- if (!getnoarg(args))
- return NULL;
- BGN_SAVE
- errno = 0;
- newsize = ftell(f->f_fp); /* default to current position*/
- END_SAVE
- if (newsize == -1L) {
- err_errno(IOError);
- clearerr(f->f_fp);
- return NULL;
- }
- }
- BGN_SAVE
- errno = 0;
- ret = fflush(f->f_fp);
- END_SAVE
- if (ret == 0) {
- BGN_SAVE
- errno = 0;
- ret = ftruncate(fileno(f->f_fp), newsize);
- END_SAVE
- }
- if (ret != 0) {
- err_errno(IOError);
- clearerr(f->f_fp);
- return NULL;
- }
- INCREF(None);
- return None;
- }
- #endif /* HAVE_FTRUNCATE */
-
- static object *
- file_tell(f, args)
- fileobject *f;
- object *args;
- {
- long offset;
- if (f->f_fp == NULL)
- return err_closed();
- if (!getnoarg(args))
- return NULL;
- BGN_SAVE
- errno = 0;
- offset = ftell(f->f_fp);
- END_SAVE
- if (offset == -1L) {
- err_errno(IOError);
- clearerr(f->f_fp);
- return NULL;
- }
- return newintobject(offset);
- }
-
- static object *
- file_fileno(f, args)
- fileobject *f;
- object *args;
- {
- if (f->f_fp == NULL)
- return err_closed();
- if (!getnoarg(args))
- return NULL;
- return newintobject((long) fileno(f->f_fp));
- }
-
- static object *
- file_flush(f, args)
- fileobject *f;
- object *args;
- {
- int res;
-
- if (f->f_fp == NULL)
- return err_closed();
- if (!getnoarg(args))
- return NULL;
- BGN_SAVE
- errno = 0;
- res = fflush(f->f_fp);
- END_SAVE
- if (res != 0) {
- err_errno(IOError);
- clearerr(f->f_fp);
- return NULL;
- }
- INCREF(None);
- return None;
- }
-
- static object *
- file_isatty(f, args)
- fileobject *f;
- object *args;
- {
- long res;
- if (f->f_fp == NULL)
- return err_closed();
- if (!getnoarg(args))
- return NULL;
- BGN_SAVE
- res = isatty((int)fileno(f->f_fp));
- END_SAVE
- return newintobject(res);
- }
-
- static object *
- file_read(f, args)
- fileobject *f;
- object *args;
- {
- int n, n1, n2, n3;
- object *v;
-
- if (f->f_fp == NULL)
- return err_closed();
- if (args == NULL)
- n = -1;
- else {
- if (!getargs(args, "i", &n))
- return NULL;
- }
- n2 = n >= 0 ? n : BUFSIZ;
- v = newsizedstringobject((char *)NULL, n2);
- if (v == NULL)
- return NULL;
- n1 = 0;
- BGN_SAVE
- 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;
- RET_SAVE
- if (resizestring(&v, n2) < 0)
- return NULL;
- RES_SAVE
- }
- }
- END_SAVE
- if (n1 != n2)
- resizestring(&v, n1);
- return v;
- }
-
- /* Internal routine to get a line.
- Size argument interpretation:
- > 0: max length;
- = 0: read arbitrary line;
- < 0: strip trailing '\n', raise EOFError if EOF reached immediately
- */
-
- static object *
- getline(f, n)
- fileobject *f;
- int n;
- {
- register FILE *fp;
- register int c;
- register char *buf, *end;
- int n1, n2;
- object *v;
-
- fp = f->f_fp;
- n2 = n > 0 ? n : 100;
- v = newsizedstringobject((char *)NULL, n2);
- if (v == NULL)
- return NULL;
- buf = BUF(v);
- end = buf + n2;
-
- BGN_SAVE
- for (;;) {
- if ((c = getc(fp)) == EOF) {
- clearerr(fp);
- if (sigcheck()) {
- RET_SAVE
- DECREF(v);
- return NULL;
- }
- if (n < 0 && buf == BUF(v)) {
- RET_SAVE
- DECREF(v);
- err_setstr(EOFError,
- "EOF when reading a line");
- return NULL;
- }
- break;
- }
- if ((*buf++ = c) == '\n') {
- if (n < 0)
- buf--;
- break;
- }
- if (buf == end) {
- if (n > 0)
- break;
- n1 = n2;
- n2 += 1000;
- RET_SAVE
- if (resizestring(&v, n2) < 0)
- return NULL;
- RES_SAVE
- buf = BUF(v) + n1;
- end = BUF(v) + n2;
- }
- }
- END_SAVE
-
- n1 = buf - BUF(v);
- if (n1 != n2)
- resizestring(&v, n1);
- return v;
- }
-
- /* External C interface */
-
- object *
- filegetline(f, n)
- object *f;
- int n;
- {
- if (f == NULL) {
- err_badcall();
- return NULL;
- }
- if (!is_fileobject(f)) {
- object *reader;
- object *args;
- object *result;
- reader = getattr(f, "readline");
- if (reader == NULL)
- return NULL;
- if (n <= 0)
- args = mkvalue("()");
- else
- args = mkvalue("(i)", n);
- if (args == NULL) {
- DECREF(reader);
- return NULL;
- }
- result = call_object(reader, args);
- DECREF(reader);
- DECREF(args);
- if (result != NULL && !is_stringobject(result)) {
- DECREF(result);
- result = NULL;
- err_setstr(TypeError,
- "object.readline() returned non-string");
- }
- if (n < 0 && result != NULL) {
- char *s = getstringvalue(result);
- int len = getstringsize(result);
- if (len == 0) {
- DECREF(result);
- result = NULL;
- err_setstr(EOFError,
- "EOF when reading a line");
- }
- else if (s[len-1] == '\n') {
- if (result->ob_refcnt == 1)
- resizestring(&result, len-1);
- else {
- object *v;
- v = newsizedstringobject(s, len-1);
- DECREF(result);
- result = v;
- }
- }
- }
- return result;
- }
- if (((fileobject*)f)->f_fp == NULL)
- return err_closed();
- return getline((fileobject *)f, n);
- }
-
- /* Python method */
-
- static object *
- file_readline(f, args)
- fileobject *f;
- object *args;
- {
- int n;
-
- if (f->f_fp == NULL)
- return err_closed();
- if (args == NULL)
- n = 0; /* Unlimited */
- else {
- if (!getintarg(args, &n))
- return NULL;
- if (n == 0)
- return newstringobject("");
- if (n < 0)
- n = 0;
- }
-
- return getline(f, n);
- }
-
- static object *
- file_readlines(f, args)
- fileobject *f;
- object *args;
- {
- object *list;
- object *line;
-
- if (f->f_fp == NULL)
- return err_closed();
- if (!getnoarg(args))
- return NULL;
- if ((list = newlistobject(0)) == NULL)
- return NULL;
- for (;;) {
- line = getline(f, 0);
- 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;
- {
- char *s;
- int n, n2;
- if (f->f_fp == NULL)
- return err_closed();
- if (!getargs(args, "s#", &s, &n))
- return NULL;
- f->f_softspace = 0;
- BGN_SAVE
- errno = 0;
- n2 = fwrite(s, 1, n, f->f_fp);
- END_SAVE
- if (n2 != n) {
- err_errno(IOError);
- clearerr(f->f_fp);
- return NULL;
- }
- INCREF(None);
- return None;
- }
-
- static object *
- file_writelines(f, args)
- fileobject *f;
- object *args;
- {
- int i, n;
- if (f->f_fp == NULL)
- return err_closed();
- if (args == NULL || !is_listobject(args)) {
- err_setstr(TypeError,
- "writelines() requires list of strings");
- return NULL;
- }
- n = getlistsize(args);
- f->f_softspace = 0;
- BGN_SAVE
- errno = 0;
- for (i = 0; i < n; i++) {
- object *line = getlistitem(args, i);
- int len;
- int nwritten;
- if (!is_stringobject(line)) {
- RET_SAVE
- err_setstr(TypeError,
- "writelines() requires list of strings");
- return NULL;
- }
- len = getstringsize(line);
- nwritten = fwrite(getstringvalue(line), 1, len, f->f_fp);
- if (nwritten != len) {
- RET_SAVE
- err_errno(IOError);
- clearerr(f->f_fp);
- return NULL;
- }
- }
- END_SAVE
- INCREF(None);
- return None;
- }
-
- static struct methodlist file_methods[] = {
- {"close", (method)file_close, 0},
- {"flush", (method)file_flush, 0},
- {"fileno", (method)file_fileno, 0},
- {"isatty", (method)file_isatty, 0},
- {"read", (method)file_read, 0},
- {"readline", (method)file_readline, 0},
- {"readlines", (method)file_readlines, 0},
- {"seek", (method)file_seek, 0},
- #ifdef HAVE_FTRUNCATE
- {"truncate", (method)file_truncate, 0},
- #endif
- {"tell", (method)file_tell, 0},
- {"write", (method)file_write, 0},
- {"writelines", (method)file_writelines, 0},
- {NULL, NULL} /* sentinel */
- };
-
- #define OFF(x) offsetof(fileobject, x)
-
- static struct memberlist file_memberlist[] = {
- {"softspace", T_INT, OFF(f_softspace)},
- {"mode", T_OBJECT, OFF(f_mode), RO},
- {"name", T_OBJECT, OFF(f_name), RO},
- /* getattr(f, "closed") is implemented without this table */
- {"closed", T_INT, 0, RO},
- {NULL} /* Sentinel */
- };
-
- static object *
- file_getattr(f, name)
- fileobject *f;
- char *name;
- {
- object *res;
-
- res = findmethod(file_methods, (object *)f, name);
- if (res != NULL)
- return res;
- err_clear();
- if (strcmp(name, "closed") == 0)
- return newintobject((long)(f->f_fp == 0));
- return getmember((char *)f, file_memberlist, name);
- }
-
- static int
- file_setattr(f, name, v)
- fileobject *f;
- char *name;
- object *v;
- {
- if (v == NULL) {
- err_setstr(AttributeError, "can't delete file attributes");
- return -1;
- }
- return setmember((char *)f, file_memberlist, name, v);
- }
-
- typeobject Filetype = {
- OB_HEAD_INIT(&Typetype)
- 0,
- "file",
- sizeof(fileobject),
- 0,
- (destructor)file_dealloc, /*tp_dealloc*/
- 0, /*tp_print*/
- (getattrfunc)file_getattr, /*tp_getattr*/
- (setattrfunc)file_setattr, /*tp_setattr*/
- 0, /*tp_compare*/
- (reprfunc)file_repr, /*tp_repr*/
- };
-
- /* Interface for the 'soft space' between print items. */
-
- int
- softspace(f, newflag)
- object *f;
- int newflag;
- {
- int oldflag = 0;
- if (f == NULL) {
- /* Do nothing */
- }
- else if (is_fileobject(f)) {
- oldflag = ((fileobject *)f)->f_softspace;
- ((fileobject *)f)->f_softspace = newflag;
- }
- else {
- object *v;
- v = getattr(f, "softspace");
- if (v == NULL)
- err_clear();
- else {
- if (is_intobject(v))
- oldflag = getintvalue(v);
- DECREF(v);
- }
- v = newintobject((long)newflag);
- if (v == NULL)
- err_clear();
- else {
- if (setattr(f, "softspace", v) != 0)
- err_clear();
- DECREF(v);
- }
- }
- return oldflag;
- }
-
- /* Interfaces to write objects/strings to file-like objects */
-
- int
- writeobject(v, f, flags)
- object *v;
- object *f;
- int flags;
- {
- object *writer, *value, *args, *result;
- if (f == NULL) {
- err_setstr(TypeError, "writeobject with NULL file");
- return -1;
- }
- else if (is_fileobject(f)) {
- FILE *fp = getfilefile(f);
- if (fp == NULL) {
- err_closed();
- return -1;
- }
- return printobject(v, fp, flags);
- }
- writer = getattr(f, "write");
- if (writer == NULL)
- return -1;
- if (flags & PRINT_RAW)
- value = strobject(v);
- else
- value = reprobject(v);
- if (value == NULL) {
- DECREF(writer);
- return -1;
- }
- args = mkvalue("(O)", value);
- if (value == NULL) {
- DECREF(value);
- DECREF(writer);
- return -1;
- }
- result = call_object(writer, args);
- DECREF(args);
- DECREF(value);
- DECREF(writer);
- if (result == NULL)
- return -1;
- DECREF(result);
- return 0;
- }
-
- void
- writestring(s, f)
- char *s;
- object *f;
- {
- if (f == NULL) {
- /* Do nothing */
- }
- else if (is_fileobject(f)) {
- FILE *fp = getfilefile(f);
- if (fp != NULL)
- fputs(s, fp);
- }
- else if (!err_occurred()) {
- object *v = newstringobject(s);
- if (v == NULL) {
- err_clear();
- }
- else {
- if (writeobject(v, f, PRINT_RAW) != 0)
- err_clear();
- DECREF(v);
- }
- }
- }
-