| /* File object implementation */ |
| |
| /* XXX This should become a built-in module 'io'. It should support more |
| functionality, better exception handling for invalid calls, etc. |
| It should also cooperate with posix to support popen(), which should |
| share most code but have a special close function. */ |
| |
| #include <stdio.h> |
| |
| #include "PROTO.h" |
| #include "object.h" |
| #include "stringobject.h" |
| #include "intobject.h" |
| #include "fileobject.h" |
| #include "methodobject.h" |
| #include "objimpl.h" |
| #include "errors.h" |
| |
| typedef struct { |
| OB_HEAD |
| FILE *f_fp; |
| object *f_name; |
| object *f_mode; |
| /* XXX Should move the 'need space' on printing flag here */ |
| } fileobject; |
| |
| FILE * |
| getfilefile(f) |
| object *f; |
| { |
| if (!is_fileobject(f)) { |
| errno = EBADF; |
| return NULL; |
| } |
| return ((fileobject *)f)->f_fp; |
| } |
| |
| object * |
| newopenfileobject(fp, name, mode) |
| FILE *fp; |
| char *name; |
| char *mode; |
| { |
| fileobject *f = NEWOBJ(fileobject, &Filetype); |
| if (f == NULL) |
| return NULL; |
| f->f_fp = NULL; |
| f->f_name = newstringobject(name); |
| f->f_mode = newstringobject(mode); |
| if (f->f_name == NULL || f->f_mode == NULL) { |
| DECREF(f); |
| errno = ENOMEM; |
| return NULL; |
| } |
| f->f_fp = fp; |
| return (object *) f; |
| } |
| |
| object * |
| newfileobject(name, mode) |
| char *name, *mode; |
| { |
| fileobject *f; |
| FILE *fp; |
| f = (fileobject *) newopenfileobject((FILE *)NULL, name, mode); |
| if (f == NULL) |
| return NULL; |
| if ((f->f_fp = fopen(name, mode)) == NULL) { |
| DECREF(f); |
| return NULL; |
| } |
| return (object *)f; |
| } |
| |
| /* Methods */ |
| |
| static void |
| filedealloc(f) |
| fileobject *f; |
| { |
| if (f->f_fp != NULL) |
| fclose(f->f_fp); |
| if (f->f_name != NULL) |
| DECREF(f->f_name); |
| if (f->f_mode != NULL) |
| DECREF(f->f_mode); |
| free((char *)f); |
| } |
| |
| static void |
| fileprint(f, fp, flags) |
| fileobject *f; |
| FILE *fp; |
| int flags; |
| { |
| fprintf(fp, "<%s file ", f->f_fp == NULL ? "closed" : "open"); |
| printobject(f->f_name, fp, flags); |
| fprintf(fp, ", mode "); |
| printobject(f->f_mode, fp, flags); |
| fprintf(fp, ">"); |
| } |
| |
| static object * |
| filerepr(f) |
| fileobject *f; |
| { |
| char buf[300]; |
| /* XXX This differs from fileprint if the filename contains |
| quotes or other funny characters. */ |
| sprintf(buf, "<%s file '%.256s', mode '%.10s'>", |
| f->f_fp == NULL ? "closed" : "open", |
| getstringvalue(f->f_name), |
| getstringvalue(f->f_mode)); |
| return newstringobject(buf); |
| } |
| |
| static object * |
| fileclose(f, args) |
| fileobject *f; |
| object *args; |
| { |
| if (args != NULL) { |
| errno = EINVAL; |
| return NULL; |
| } |
| if (f->f_fp != NULL) { |
| fclose(f->f_fp); |
| f->f_fp = NULL; |
| } |
| INCREF(None); |
| return None; |
| } |
| |
| static object * |
| fileread(f, args) |
| fileobject *f; |
| object *args; |
| { |
| int n; |
| object *v; |
| if (f->f_fp == NULL) { |
| errno = EBADF; |
| return NULL; |
| } |
| if (args == NULL || !is_intobject(args)) { |
| errno = EINVAL; |
| return NULL; |
| } |
| n = getintvalue(args); |
| if (n < 0) { |
| errno = EDOM; |
| return NULL; |
| } |
| v = newsizedstringobject((char *)NULL, n); |
| if (v == NULL) { |
| errno = ENOMEM; |
| 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); |
| return v; |
| } |
| |
| /* XXX Should this be unified with raw_input()? */ |
| |
| static object * |
| filereadline(f, args) |
| fileobject *f; |
| object *args; |
| { |
| int n; |
| object *v; |
| if (f->f_fp == NULL) { |
| errno = EBADF; |
| return NULL; |
| } |
| if (args == NULL) { |
| n = 10000; /* XXX should really be unlimited */ |
| } |
| else if (is_intobject(args)) { |
| n = getintvalue(args); |
| if (n < 0 || n > 0x7fff /*XXX*/ ) { |
| errno = EDOM; |
| return NULL; |
| } |
| } |
| else { |
| errno = EINVAL; |
| return NULL; |
| } |
| v = newsizedstringobject((char *)NULL, n); |
| if (v == NULL) { |
| errno = ENOMEM; |
| return NULL; |
| } |
| if (fgets(getstringvalue(v), n+1, 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)); |
| } |
| resizestring(&v, n); |
| return v; |
| } |
| |
| static object * |
| filewrite(f, args) |
| fileobject *f; |
| object *args; |
| { |
| int n, n2; |
| if (f->f_fp == NULL) { |
| errno = EBADF; |
| return NULL; |
| } |
| if (args == NULL || !is_stringobject(args)) { |
| errno = EINVAL; |
| return NULL; |
| } |
| errno = 0; |
| n2 = fwrite(getstringvalue(args), 1, n = getstringsize(args), f->f_fp); |
| if (n2 != n) { |
| if (errno == 0) |
| errno = EIO; |
| return NULL; |
| } |
| INCREF(None); |
| return None; |
| } |
| |
| static struct methodlist { |
| char *ml_name; |
| method ml_meth; |
| } filemethods[] = { |
| {"write", filewrite}, |
| {"read", fileread}, |
| {"readline", filereadline}, |
| {"close", fileclose}, |
| {NULL, NULL} /* sentinel */ |
| }; |
| |
| static object * |
| filegetattr(f, name) |
| fileobject *f; |
| char *name; |
| { |
| struct methodlist *ml = filemethods; |
| for (; ml->ml_name != NULL; ml++) { |
| if (strcmp(name, ml->ml_name) == 0) |
| return newmethodobject(ml->ml_name, ml->ml_meth, |
| (object *)f); |
| } |
| err_setstr(NameError, name); |
| return NULL; |
| } |
| |
| typeobject Filetype = { |
| OB_HEAD_INIT(&Typetype) |
| 0, |
| "file", |
| sizeof(fileobject), |
| 0, |
| filedealloc, /*tp_dealloc*/ |
| fileprint, /*tp_print*/ |
| filegetattr, /*tp_getattr*/ |
| 0, /*tp_setattr*/ |
| 0, /*tp_compare*/ |
| filerepr, /*tp_repr*/ |
| }; |