diff options
Diffstat (limited to 'io.c')
-rw-r--r-- | io.c | 885 |
1 files changed, 596 insertions, 289 deletions
@@ -6,7 +6,7 @@ $Date: 1995/01/10 10:42:39 $ created at: Fri Oct 15 18:08:59 JST 1993 - Copyright (C) 1993-1995 Yukihiro Matsumoto + Copyright (C) 1993-1996 Yukihiro Matsumoto ************************************************/ @@ -16,8 +16,9 @@ #include <errno.h> #include <sys/types.h> -#include <sys/stat.h> +#ifndef DJGPP #include <sys/ioctl.h> +#endif #ifdef HAVE_SYS_TIME_H # include <sys/time.h> @@ -31,26 +32,94 @@ struct timeval { #include <vfork.h> #endif +#include <sys/stat.h> + +#ifdef DJGPP +#include <fcntl.h> +#endif + VALUE rb_ad_string(); VALUE cIO; extern VALUE cFile; +VALUE eEOFError; +VALUE eIOError; VALUE rb_stdin, rb_stdout, rb_stderr, rb_defout; VALUE FS, OFS; VALUE RS, ORS; +VALUE RS_default; static VALUE argf; ID id_write, id_fd, id_print_on; +VALUE lastline_get(); +void lastline_set(); + extern char *inplace; +struct timeval time_timeval(); + +#ifdef _STDIO_USES_IOSTREAM /* GNU libc */ +# ifdef _IO_fpos_t +# define READ_DATA_PENDING(fp) ((fp)->_IO_read_ptr != (fp)->_IO_read_end) +# else +# define READ_DATA_PENDING(fp) ((fp)->_gptr < (fp)->_egptr) +# endif +#else +# ifdef FILE_COUNT +# define READ_DATA_PENDING(fp) ((fp)->FILE_COUNT > 0) +# else +/* requires systems own version of the ReadDataPending() */ +extern int ReadDataPending(); +# define READ_DATA_PENDING(fp) ReadDataPending(fp) +# endif +#endif + +#ifndef THREAD +# define READ_CHECK(fp) 0 +#else +# define READ_CHECK(fp) do {\ + if (!READ_DATA_PENDING(fp)) thread_wait_fd(fileno(fp));\ +} while(0) +#endif + +void +eof_error() +{ + Raise(eEOFError, "End of file reached"); +} + +void +io_writable(fptr) + OpenFile *fptr; +{ + if (!(fptr->mode & FMODE_WRITABLE)) { + Raise(eIOError, "not opened for writing"); + } +} + +void +io_readable(fptr) + OpenFile *fptr; +{ + if (!(fptr->mode & FMODE_READABLE)) { + Raise(eIOError, "not opened for reading"); + } +} + +static void +closed() +{ + Raise(eIOError, "closed stream"); +} + /* writing functions */ VALUE -io_write(obj, str) - VALUE obj; +io_write(io, str) + VALUE io; struct RString *str; { OpenFile *fptr; @@ -58,19 +127,17 @@ io_write(obj, str) VALUE out; int n; - GetOpenFile(obj, fptr); - if (!(fptr->mode & FMODE_WRITABLE)) { - Fail("not opened for writing"); - } + GetOpenFile(io, fptr); + io_writable(fptr); f = (fptr->f2) ? fptr->f2 : fptr->f; - if (f == NULL) Fail("closed stream"); + if (f == NULL) closed(); if (TYPE(str) != T_STRING) str = (struct RString*)obj_as_string(str); if (str->len == 0) return INT2FIX(0); - n = fwrite(str->ptr, sizeof(char), str->len, f); + n = fwrite(str->ptr, 1, str->len, f); if (n == 0 || ferror(f)) { rb_sys_fail(fptr->path); } @@ -82,44 +149,43 @@ io_write(obj, str) } static VALUE -io_puts(obj, str) - VALUE obj, str; +io_puts(io, str) + VALUE io, str; { - io_write(obj, str); - return obj; + io_write(io, str); + return io; } static VALUE -io_flush(obj) - VALUE obj; +io_flush(io) + VALUE io; { OpenFile *fptr; FILE *f; - GetOpenFile(obj, fptr); - if (!(fptr->mode & FMODE_WRITABLE)) { - Fail("not opend for writing"); - } + GetOpenFile(io, fptr); + io_writable(fptr); f = (fptr->f2) ? fptr->f2 : fptr->f; - if (f == NULL) Fail("closed stream"); + if (f == NULL) closed(); - if (fflush(f) == EOF) rb_sys_fail(Qnil); + if (fflush(f) == EOF) rb_sys_fail(0); - return obj; + return io; } static VALUE -io_eof(obj) - VALUE obj; +io_eof(io) + VALUE io; { OpenFile *fptr; int ch; - GetOpenFile(obj, fptr); -#ifdef STDSTDIO /* (the code works without this) */ - if (fptr->f->_cnt > 0) /* cheat a little, since */ - return FALSE; /* this is the most usual case */ -#endif + GetOpenFile(io, fptr); + io_readable(fptr); + if (fptr->f == NULL) closed(); + + if (READ_DATA_PENDING(fptr->f)) return FALSE; + if (feof(fptr->f)) return TRUE; TRAP_BEG; ch = getc(fptr->f); @@ -129,31 +195,27 @@ io_eof(obj) (void)ungetc(ch, fptr->f); return FALSE; } -#ifdef STDSTDIO - if (fptr->f->_cnt < -1) - fptr->f->_cnt = -1; -#endif return TRUE; } static VALUE -io_sync(obj) - VALUE obj; +io_sync(io) + VALUE io; { OpenFile *fptr; - GetOpenFile(obj, fptr); + GetOpenFile(io, fptr); return (fptr->mode & FMODE_SYNC) ? TRUE : FALSE; } static VALUE -io_set_sync(obj, mode) - VALUE obj, mode; +io_set_sync(io, mode) + VALUE io, mode; { OpenFile *fptr; - GetOpenFile(obj, fptr); - if (mode) { + GetOpenFile(io, fptr); + if (RTEST(mode)) { fptr->mode |= FMODE_SYNC; } else { @@ -163,13 +225,13 @@ io_set_sync(obj, mode) } static VALUE -io_fileno(obj) - VALUE obj; +io_fileno(io) + VALUE io; { OpenFile *fptr; int fd; - GetOpenFile(obj, fptr); + GetOpenFile(io, fptr); fd = fileno(fptr->f); return INT2FIX(fd); } @@ -185,54 +247,50 @@ read_all(port) int n; GetOpenFile(port, fptr); - if (!(fptr->mode & FMODE_READABLE)) { - Fail("not opend for reading"); - } - if (fptr->f == NULL) Fail("closed stream"); + io_readable(fptr); + if (fptr->f == NULL) closed(); str = str_new(0, 0); for (;;) { + READ_CHECK(fptr->f); TRAP_BEG; n = fread(buf, 1, BUFSIZ, fptr->f); TRAP_END; - if (n == 0) { - if (feof(fptr->f)) break; - rb_sys_fail(Qnil); - } + if (n == 0) break; + if (n < 0) rb_sys_fail(0); str_cat(str, buf, n); } return str; } static VALUE -io_read(argc, argv, obj) +io_read(argc, argv, io) int argc; VALUE *argv; - VALUE obj; + VALUE io; { OpenFile *fptr; int n, lgt; VALUE len, str; if (rb_scan_args(argc, argv, "01", &len) == 0) { - return read_all(obj); + return read_all(io); } lgt = NUM2INT(len); - GetOpenFile(obj, fptr); - if (!(fptr->mode & FMODE_READABLE)) { - Fail("not opend for reading"); - } - if (fptr->f == NULL) Fail("closed stream"); + GetOpenFile(io, fptr); + io_readable(fptr); + if (fptr->f == NULL) closed(); str = str_new(0, lgt); + READ_CHECK(fptr->f); TRAP_BEG; n = fread(RSTRING(str)->ptr, 1, RSTRING(str)->len, fptr->f); TRAP_END; if (n == 0) { if (feof(fptr->f)) return Qnil; - rb_sys_fail(Qnil); + rb_sys_fail(fptr->path); } RSTRING(str)->len = n; @@ -241,42 +299,54 @@ io_read(argc, argv, obj) return str; } -VALUE rb_lastline; static VALUE lineno; -static VALUE -io_gets(obj) - VALUE obj; +VALUE +io_gets_method(argc, argv, io) + int argc; + VALUE argv; + VALUE io; { OpenFile *fptr; FILE *f; struct RString *str; int c, newline; - int rslen; + char *rsptr; + int rslen, rspara = 0; + VALUE rs; - GetOpenFile(obj, fptr); - if (!(fptr->mode & FMODE_READABLE)) { - Fail("not opend for reading"); + if (rb_scan_args(argc, argv, "01", &rs) == 1) { + if (!NIL_P(rs)) Check_Type(rs, T_STRING); } + else { + rs = RS; + } + + GetOpenFile(io, fptr); + io_readable(fptr); f = fptr->f; - if (f == NULL) Fail("closed stream"); + if (f == NULL) closed(); - if (RS) { - rslen = RSTRING(RS)->len; + if (!NIL_P(rs)) { + rslen = RSTRING(rs)->len; if (rslen == 0) { - newline = '\n'; + rsptr = "\n\n"; + rslen = 2; + rspara = 1; } else { - newline = RSTRING(RS)->ptr[rslen-1]; + rsptr = RSTRING(rs)->ptr; } } else { - newline = 0777; /* non matching char */ - rslen = 1; + rsptr = 0; + rslen = 0; } + newline = rslen ? rsptr[rslen - 1] : 0777; - if (rslen == 0) { + if (rspara) { do { + READ_CHECK(f); TRAP_BEG; c = getc(f); TRAP_END; @@ -290,51 +360,54 @@ io_gets(obj) { char buf[8192]; char *bp, *bpe = buf + sizeof buf - 3; + int cnt; int append = 0; again: bp = buf; - retry: - TRAP_BEG; - while ((c = getc(f)) != EOF && (*bp++ = c) != newline && bp < bpe) - ; - TRAP_END; + if (rslen) { + for (;;) { + READ_CHECK(f); + TRAP_BEG; + c = getc(f); + TRAP_END; + if (c == EOF) break; + if ((*bp++ = c) == newline) break; + if (bp == bpe) break; + } + cnt = bp - buf; + } + else { + cnt = fread(buf, 1, sizeof(buf), f); + c = cnt ? buf[cnt - 1]: EOF; + } if (c == EOF) { - if (!feof(f)) goto retry; - if (!append && bp == buf) { - str = Qnil; + if (!append && cnt == 0) { + str = RSTRING(Qnil); goto return_gets; } } if (append) - str_cat(str, buf, bp - buf); + str_cat(str, buf, cnt); else - str = (struct RString*)str_new(buf, bp - buf); - - if (c != EOF - && - (c != newline - || - (rslen > 1 - && - (str->len < rslen - || - memcmp(str->ptr+str->len-rslen, RSTRING(RS)->ptr, rslen) - ) - ) - ) - ) { + str = (struct RString*)str_new(buf, cnt); + + if (c != EOF && + (!rslen || + str->len < rslen || + memcmp(str->ptr+str->len-rslen, rsptr, rslen))) { append = 1; goto again; } } return_gets: - if (rslen == 0) { + if (rspara) { while (c != EOF) { + READ_CHECK(f); TRAP_BEG; c = getc(f); TRAP_END; @@ -349,82 +422,132 @@ io_gets(obj) fptr->lineno++; lineno = INT2FIX(fptr->lineno); } - return rb_lastline = (VALUE)str; + lastline_set(str); + + return (VALUE)str; +} + +VALUE +io_gets(io) + VALUE io; +{ + return io_gets_method(0, 0, io); } static VALUE -io_each_line(obj) - VALUE obj; +io_readline(argc, argv, io) + int argc; + VALUE argv; + VALUE io; +{ + VALUE line = io_gets_method(argc, argv, io); + + if (NIL_P(line)) { + eof_error(); + } + return line; +} + +static VALUE +io_each_line(argc, argv, io) + int argc; + VALUE argv; + VALUE io; { VALUE str; - while (str = io_gets(obj)) { + while (!NIL_P(str = io_gets_method(argc, argv, io))) { rb_yield(str); } return Qnil; } static VALUE -io_each_byte(obj) - VALUE obj; +io_each_byte(io) + VALUE io; { OpenFile *fptr; FILE *f; int c; - GetOpenFile(obj, fptr); - if (!(fptr->mode & FMODE_READABLE)) { - Fail("not opend for reading"); - } + GetOpenFile(io, fptr); + io_readable(fptr); f = fptr->f; - if (f == NULL) Fail("closed stream"); + if (f == NULL) closed(); for (;;) { + READ_CHECK(f); TRAP_BEG; c = getc(f); TRAP_END; if (c == EOF) break; rb_yield(INT2FIX(c & 0xff)); } - if (ferror(f) != 0) rb_sys_fail(Qnil); - return obj; + if (ferror(f) != 0) rb_sys_fail(fptr->path); + return Qnil; } -static VALUE -io_getc(obj) - VALUE obj; +VALUE +io_getc(io) + VALUE io; { OpenFile *fptr; FILE *f; int c; - GetOpenFile(obj, fptr); - if (!(fptr->mode & FMODE_READABLE)) { - Fail("not opend for reading"); - } + GetOpenFile(io, fptr); + io_readable(fptr); f = fptr->f; - if (f == NULL) Fail("closed stream"); + if (f == NULL) closed(); + READ_CHECK(f); TRAP_BEG; c = getc(f); TRAP_END; if (c == EOF) { - if (ferror(f) != 0) rb_sys_fail(Qnil); + if (ferror(f) != 0) rb_sys_fail(fptr->path); return Qnil; } return INT2FIX(c & 0xff); } static VALUE -io_isatty(obj) - VALUE obj; +io_readchar(io) + VALUE io; +{ + VALUE c = io_getc(io); + + if (NIL_P(c)) { + eof_error(); + } + return c; +} + +VALUE +io_ungetc(io, c) + VALUE io, c; +{ + OpenFile *fptr; + + Check_Type(c, T_FIXNUM); + GetOpenFile(io, fptr); + io_readable(fptr); + if (fptr->f == NULL) closed(); + + if (ungetc(FIX2INT(c), fptr->f) == EOF) + rb_sys_fail(fptr->path); +} + +static VALUE +io_isatty(io) + VALUE io; { OpenFile *fptr; #ifndef NT - GetOpenFile(obj, fptr); - if (fptr->f == NULL) Fail("closed stream"); + GetOpenFile(io, fptr); + if (fptr->f == NULL) closed(); if (isatty(fileno(fptr->f)) == 0) return FALSE; #endif @@ -466,30 +589,30 @@ io_fptr_finalize(fptr) } VALUE -io_close(obj) - VALUE obj; +io_close(io) + VALUE io; { OpenFile *fptr; - GetOpenFile(obj, fptr); + GetOpenFile(io, fptr); io_fptr_finalize(fptr); return Qnil; } static VALUE -io_closed(obj) - VALUE obj; +io_closed(io) + VALUE io; { OpenFile *fptr; - GetOpenFile(obj, fptr); + GetOpenFile(io, fptr); return fptr->f?FALSE:TRUE; } static VALUE -io_syswrite(obj, str) - VALUE obj, str; +io_syswrite(io, str) + VALUE io, str; { OpenFile *fptr; FILE *f; @@ -498,43 +621,45 @@ io_syswrite(obj, str) if (TYPE(str) != T_STRING) str = obj_as_string(str); - GetOpenFile(obj, fptr); - if (!(fptr->mode & FMODE_WRITABLE)) { - Fail("not opend for writing"); - } + GetOpenFile(io, fptr); + io_writable(fptr); f = (fptr->f2) ? fptr->f2 : fptr->f; - if (f == NULL) Fail("closed stream"); + if (f == NULL) closed(); +#ifdef THREAD + thread_fd_writable(fileno(f)); +#endif n = write(fileno(f), RSTRING(str)->ptr, RSTRING(str)->len); - if (n == -1) rb_sys_fail(Qnil); + if (n == -1) rb_sys_fail(fptr->path); return INT2FIX(n); } static VALUE -io_sysread(obj, len) - VALUE obj, len; +io_sysread(io, len) + VALUE io, len; { OpenFile *fptr; int n, ilen; VALUE str; ilen = NUM2INT(len); - GetOpenFile(obj, fptr); - if (!(fptr->mode & FMODE_READABLE)) { - Fail("not opend for reading"); - } - if (fptr->f == NULL) Fail("closed stream"); + GetOpenFile(io, fptr); + io_readable(fptr); + if (fptr->f == NULL) closed(); str = str_new(0, ilen); +#ifdef THREAD + thread_wait_fd(fileno(fptr->f)); +#endif TRAP_BEG; n = read(fileno(fptr->f), RSTRING(str)->ptr, RSTRING(str)->len); TRAP_END; - if (n == -1) rb_sys_fail(Qnil); - if (n == 0) return Qnil; /* EOF */ + if (n == -1) rb_sys_fail(fptr->path); + if (n == 0) eof_error(); RSTRING(str)->len = n; RSTRING(str)->ptr[n] = '\0'; @@ -542,21 +667,21 @@ io_sysread(obj, len) } static VALUE -io_binmode(obj) - VALUE obj; +io_binmode(io) + VALUE io; { -#ifdef NT +#if defined(NT) || defined(DJGPP) OpenFile *fptr; - GetOpenFile(obj, fptr); - if (setmode(fileno(fptr), O_BINARY) == -1) - rb_sys_fail(Qnil); + GetOpenFile(io, fptr); + if (fptr->f && setmode(fileno(fptr->f), O_BINARY) == -1) + rb_sys_fail(fptr->path); + if (fptr->f2 && setmode(fileno(fptr->f2), O_BINARY) == -1) + rb_sys_fail(fptr->path); #endif - return obj; + return io; } -VALUE obj_alloc(); - int io_mode_flags(mode) char *mode; @@ -574,7 +699,7 @@ io_mode_flags(mode) flags |= FMODE_WRITABLE; break; default: - Fail("illegal access mode"); + ArgError("illegal access mode"); } if (mode[1] == '+') { flags |= FMODE_READABLE | FMODE_WRITABLE; @@ -584,6 +709,26 @@ io_mode_flags(mode) } FILE * +rb_fopen(fname, mode) + char *fname; + char *mode; +{ + FILE *f; + + f = fopen(fname, mode); + if (f == NULL) { + if (errno == EMFILE || errno == ENFILE) { + gc(); + f = fopen(fname, mode); + } + if (f == NULL) { + rb_sys_fail(fname); + } + } + return f; +} + +FILE * rb_fdopen(fd, mode) int fd; char *mode; @@ -596,13 +741,13 @@ rb_fdopen(fd, mode) f = fdopen(fd, mode); } if (f == NULL) { - rb_sys_fail(Qnil); + rb_sys_fail(0); } } return f; } -#ifdef NT +#if defined (NT) || defined(DJGPP) static void pipe_finalize(fptr) OpenFile *fptr; @@ -619,29 +764,30 @@ pipe_open(pname, mode) char *pname, *mode; { int modef = io_mode_flags(mode); - VALUE port; OpenFile *fptr; -#ifdef NT +#if defined(NT) || defined(DJGPP) FILE *f = popen(pname, mode); if (f == NULL) rb_sys_fail(pname); + else { + NEWOBJ(port, struct RFile); + OBJSETUP(port, cIO, T_FILE); + MakeOpenFile(port, fptr); + fptr->finalize = pipe_finalize; - port = obj_alloc(cIO); - MakeOpenFile(port, fptr); - fptr->finalize = pipe_finalize; - - if (modef & FMODE_READABLE) fptr->f = f; - if (modef & FMODE_WRITABLE) fptr->f2 = f; - fptr->mode = modef | FMODE_SYNC; - return port; + if (modef & FMODE_READABLE) fptr->f = f; + if (modef & FMODE_WRITABLE) fptr->f2 = f; + fptr->mode = modef | FMODE_SYNC; + return (VALUE)port; + } #else int pid, pr[2], pw[2]; volatile int doexec; if (((modef & FMODE_READABLE) && pipe(pr) == -1) || ((modef & FMODE_WRITABLE) && pipe(pw) == -1)) - rb_sys_fail(Qnil); + rb_sys_fail(pname); doexec = (strcmp("-", pname) != 0); if (!doexec) { @@ -688,28 +834,52 @@ pipe_open(pname, mode) break; default: /* parent */ - port = obj_alloc(cIO); - MakeOpenFile(port, fptr); - if (modef & FMODE_READABLE) close(pr[1]); - if (modef & FMODE_WRITABLE) close(pw[0]); - fptr->mode = modef; - fptr->mode |= FMODE_SYNC; + { + NEWOBJ(port, struct RFile); + OBJSETUP(port, cIO, T_FILE); + MakeOpenFile(port, fptr); + if (modef & FMODE_READABLE) close(pr[1]); + if (modef & FMODE_WRITABLE) close(pw[0]); + fptr->mode = modef; + fptr->mode |= FMODE_SYNC; + fptr->pid = pid; + + if (modef & FMODE_READABLE) fptr->f = rb_fdopen(pr[0], "r"); + if (modef & FMODE_WRITABLE) fptr->f2 = rb_fdopen(pw[1], "w"); + + return (VALUE)port; + } } +#endif +} - fptr->pid = pid; - if (modef & FMODE_READABLE) fptr->f = rb_fdopen(pr[0], "r"); - if (modef & FMODE_WRITABLE) fptr->f2 = rb_fdopen(pw[1], "w"); +static VALUE +io_popen(argc, argv, self) + int argc; + VALUE *argv; + VALUE self; +{ + char *mode; + VALUE pname, pmode; - return port; -#endif + rb_scan_args(argc, argv, "11", &pname, &pmode); + Check_Type(pname, T_STRING); + if (NIL_P(pmode)) { + mode = "r"; + } + else { + Check_Type(pmode, T_STRING); + if (RSTRING(pmode)->len == 0 || RSTRING(pmode)->len > 2) + ArgError("illegal access mode"); + mode = RSTRING(pmode)->ptr; + } + return pipe_open(RSTRING(pname)->ptr, mode); } static VALUE io_open(fname, mode) char *fname, *mode; { - int pipe = 0; - if (fname[0] == '|') { return pipe_open(fname+1, mode); } @@ -725,19 +895,17 @@ f_open(argc, argv, self) VALUE self; { char *mode; - VALUE port; - int pipe = 0; VALUE pname, pmode; rb_scan_args(argc, argv, "11", &pname, &pmode); Check_Type(pname, T_STRING); - if (pmode == Qnil) { + if (NIL_P(pmode)) { mode = "r"; } else { Check_Type(pmode, T_STRING); if (RSTRING(pmode)->len == 0 || RSTRING(pmode)->len > 2) - Fail("illegal access mode"); + ArgError("illegal access mode"); mode = RSTRING(pmode)->ptr; } return io_open(RSTRING(pname)->ptr, mode); @@ -765,13 +933,13 @@ f_printf(argc, argv) if (TYPE(argv[0]) == T_STRING) { out = rb_defout; } - else if (rb_responds_to(argv[0], id_write)) { + else if (rb_respond_to(argv[0], id_write)) { out = argv[0]; argv++; argc--; } else { - Fail("output must responds to `write'"); + NameError("output must responds to `write'"); } rb_funcall(out, id_write, 1, f_sprintf(argc, argv)); @@ -790,30 +958,26 @@ io_print(argc, argv, out) /* if no argument given, print `$_' */ if (argc == 0) { argc = 1; - if (rb_lastline) - argv = &rb_lastline; - else { - line = str_new(0,0); - argv = &line; - } + line = lastline_get(); + argv = &line; } for (i=0; i<argc; i++) { - if (OFS && i>0) { + if (!NIL_P(OFS) && i>0) { io_write(out, OFS); } switch (TYPE(argv[i])) { case T_STRING: io_write(out, argv[i]); break; - case T_ARRAY: - ary_print_on(argv[i], out); + case T_NIL: + io_write(out, str_new2("nil")); break; default: rb_funcall(argv[i], id_print_on, 1, out); break; } } - if (ORS) { + if (!NIL_P(ORS)) { io_write(out, ORS); } @@ -829,6 +993,17 @@ f_print(argc, argv) return Qnil; } +VALUE +f_p(obj, val) +{ + VALUE str = rb_inspect(val); + + Check_Type(str, T_STRING); + io_write(rb_defout, str); + io_write(rb_defout, str_new2("\n")); + return Qnil; +} + static VALUE io_defset(val, id) VALUE val; @@ -838,7 +1013,7 @@ io_defset(val, id) val = io_open(RSTRING(val)->ptr, "w"); } if (!obj_is_kind_of(val, cIO)) { - Fail("$< must be a file, %s given", rb_class2name(CLASS_OF(val))); + TypeError("$< must be a file, %s given", rb_class2name(CLASS_OF(val))); } return rb_defout = val; } @@ -855,14 +1030,15 @@ prep_stdio(f, mode) FILE *f; int mode; { - VALUE obj = obj_alloc(cIO); OpenFile *fp; + NEWOBJ(obj, struct RFile); + OBJSETUP(obj, cIO, T_FILE); MakeOpenFile(obj, fp); fp->f = f; fp->mode = mode; - return obj; + return (VALUE)obj; } static VALUE filename, file; @@ -900,9 +1076,8 @@ next_argv() } } else { - FILE *fr = fopen(fn, "r"); + FILE *fr = rb_fopen(fn, "r"); - if (!fr) rb_sys_fail(fn); if (inplace) { struct stat st, st2; VALUE str; @@ -919,25 +1094,40 @@ next_argv() #else str_cat(str, inplace, strlen(inplace)); #endif +#if defined(MSDOS) || defined(__BOW__) + (void)fclose(fr); + (void)unlink(RSTRING(str)->ptr); + (void)rename(fn, RSTRING(str)->ptr); + fr = rb_fopen(RSTRING(str)->ptr, "r"); +#else if (rename(fn, RSTRING(str)->ptr) < 0) { Warning("Can't rename %s to %s: %s, skipping file", fn, RSTRING(str)->ptr, strerror(errno)); fclose(fr); goto retry; } +#endif } - else if (unlink(fn) < 0) { - Warning("Can't remove %s: %s, skipping file", + else { +#if !defined(MSDOS) && !defined(__BOW__) + if (unlink(fn) < 0) { + Warning("Can't remove %s: %s, skipping file", fn, strerror(errno)); - fclose(fr); - goto retry; + fclose(fr); + goto retry; + } +#else + Fatal("Can't do inplace edit without backup"); +#endif } - fw = fopen(fn, "w"); + fw = rb_fopen(fn, "w"); +#if !defined(DJGPP) && !defined(__CYGWIN32__) fstat(fileno(fw), &st2); fchmod(fileno(fw), st.st_mode); if (st.st_uid!=st2.st_uid || st.st_gid!=st2.st_gid) { fchown(fileno(fw), st.st_uid, st.st_gid); } +#endif rb_defout = prep_stdio(fw, FMODE_WRITABLE); } file = prep_stdio(fr, FMODE_READABLE); @@ -952,25 +1142,48 @@ next_argv() } static VALUE -f_gets() +f_gets_method(argc, argv) + int argc; + VALUE argv; { VALUE line; retry: if (!next_argv()) return Qnil; - line = io_gets(file); - if (line == Qnil && next_p != -1) { + line = io_gets_method(argc, argv, file); + if (NIL_P(line) && next_p != -1) { io_close(file); next_p = 1; goto retry; } - gets_lineno++; lineno = INT2FIX(gets_lineno); return line; } +VALUE +f_gets(argc, argv) + int argc; + VALUE argv; +{ + return f_gets_method(0,0); +} + +static VALUE +f_readline(argc, argv) + int argc; + VALUE argv; +{ + VALUE line = f_gets_method(argc, argv); + + if (NIL_P(line)) { + eof_error(); + } + + return line; +} + static VALUE f_eof() { @@ -990,13 +1203,36 @@ f_getc() } static VALUE -f_readlines(obj) - VALUE obj; +f_ungetc(obj, c) + VALUE obj, c; +{ + if (!next_argv()) { + ArgError("no stream to ungetc"); + } + + return io_ungetc(file, c); +} + +static VALUE +f_readchar() +{ + VALUE c = f_getc(); + + if (NIL_P(c)) { + eof_error(); + } + return c; +} + +static VALUE +f_readlines(argc, argv) + int argc; + VALUE argv; { VALUE line, ary; ary = ary_new(); - while (line = f_gets(obj)) { + while (RTEST(line = f_gets_method(argc, argv))) { ary_push(ary, line); } @@ -1009,14 +1245,15 @@ rb_str_setter(val, id, var) ID id; VALUE *var; { - if (val && TYPE(val) != T_STRING) { - Fail("value of %s must be String", rb_id2name(id)); + if (!NIL_P(val) && TYPE(val) != T_STRING) { + TypeError("value of %s must be String", rb_id2name(id)); } return *var = val; } -VALUE -rb_xstring(str) +static VALUE +f_backquote(obj, str) + VALUE obj; struct RString *str; { VALUE port, result; @@ -1031,21 +1268,8 @@ rb_xstring(str) return result; } -struct timeval *time_timeval(); - -#ifdef _STDIO_USES_IOSTREAM /* GNU libc */ -# ifdef _IO_fpos_t -# define READ_DATA_PENDING(fp) ((fp)->_IO_read_ptr < (fp)->_IO_read_end) -# else -# define READ_DATA_PENDING(fp) ((fp)->_gptr < (fp)->_egptr) -# endif -#else -# ifdef FILE_COUNT -# define READ_DATA_PENDING(fp) ((fp)->FILE_COUNT > 0) -# else -extern int ReadDataPending(); -# define READ_DATA_PENDING(fp) ReadDataPending(fp) -# endif +#ifdef HAVE_SYS_SELECT_H +#include <sys/select.h> #endif static VALUE @@ -1063,28 +1287,31 @@ f_select(argc, argv, obj) int interrupt = 0; rb_scan_args(argc, argv, "13", &read, &write, &except, &timeout); - if (timeout) { - tp = time_timeval(timeout); + if (NIL_P(timeout)) { + tp = NULL; } else { - tp = NULL; + timerec = time_timeval(timeout); + tp = &timerec; } FD_ZERO(&pset); - if (read) { + if (!NIL_P(read)) { int pending = 0; Check_Type(read, T_ARRAY); rp = &rset; FD_ZERO(rp); for (i=0; i<RARRAY(read)->len; i++) { + Check_Type(RARRAY(read)->ptr[i], T_FILE); GetOpenFile(RARRAY(read)->ptr[i], fptr); + if (fptr->f == NULL) closed(); FD_SET(fileno(fptr->f), rp); if (READ_DATA_PENDING(fptr->f)) { /* check for buffered data */ pending++; FD_SET(fileno(fptr->f), &pset); } - if (max < (int)fileno(fptr->f)) max = fileno(fptr->f); + if (max < fileno(fptr->f)) max = fileno(fptr->f); } if (pending) { /* no blocking if there's buffered data */ timerec.tv_sec = timerec.tv_usec = 0; @@ -1094,14 +1321,16 @@ f_select(argc, argv, obj) else rp = NULL; - if (write) { + if (!NIL_P(write)) { Check_Type(write, T_ARRAY); wp = &wset; FD_ZERO(wp); for (i=0; i<RARRAY(write)->len; i++) { + Check_Type(RARRAY(write)->ptr[i], T_FILE); GetOpenFile(RARRAY(write)->ptr[i], fptr); + if (fptr->f == NULL) closed(); FD_SET(fileno(fptr->f), wp); - if (max > (int)fileno(fptr->f)) max = fileno(fptr->f); + if (max > fileno(fptr->f)) max = fileno(fptr->f); if (fptr->f2) { FD_SET(fileno(fptr->f2), wp); if (max < (int)fileno(fptr->f2)) max = fileno(fptr->f2); @@ -1111,14 +1340,16 @@ f_select(argc, argv, obj) else wp = NULL; - if (except) { + if (!NIL_P(except)) { Check_Type(except, T_ARRAY); ep = &eset; FD_ZERO(ep); for (i=0; i<RARRAY(except)->len; i++) { + Check_Type(RARRAY(except)->ptr[i], T_FILE); GetOpenFile(RARRAY(except)->ptr[i], fptr); + if (fptr->f == NULL) closed(); FD_SET(fileno(fptr->f), ep); - if (max < (int)fileno(fptr->f)) max = fileno(fptr->f); + if (max < fileno(fptr->f)) max = fileno(fptr->f); if (fptr->f2) { FD_SET(fileno(fptr->f2), ep); if (max > (int)fileno(fptr->f2)) max = fileno(fptr->f2); @@ -1130,17 +1361,24 @@ f_select(argc, argv, obj) max++; +#ifdef THREAD + n = thread_select(max, rp, wp, ep, tp); + if (n < 0) { + rb_sys_fail(0); + } +#else retry: TRAP_BEG; n = select(max, rp, wp, ep, tp); TRAP_END; if (n < 0) { if (errno != EINTR) { - rb_sys_fail(Qnil); + rb_sys_fail(0); } if (tp == NULL) goto retry; interrupt = 1; } +#endif res = ary_new2(3); ary_push(res, rp?ary_new():ary_new2(0)); @@ -1191,16 +1429,17 @@ f_select(argc, argv, obj) } void -io_ctl(obj, req, arg, io_p) - VALUE obj, req; +io_ctl(io, req, arg, io_p) + VALUE io, req; struct RString *arg; int io_p; { +#if !defined(MSDOS) int cmd = NUM2INT(req); OpenFile *fptr; int len, fd; - GetOpenFile(obj, fptr); + GetOpenFile(io, fptr); #ifdef IOCPARM_MASK #ifndef IOCPARM_LEN @@ -1216,9 +1455,7 @@ io_ctl(obj, req, arg, io_p) Check_Type(arg, T_STRING); str_modify(arg); - if (arg->len < len) { - str_grow(arg, len+1); - } + str_resize(arg, len+1); arg->ptr[len] = 17; fd = fileno(fptr->f); #ifdef HAVE_FCNTL @@ -1227,22 +1464,25 @@ io_ctl(obj, req, arg, io_p) } #else if (!io_p) { - Bug("fcntl() not implemented"); + rb_notimplement(); } if (ioctl(fd, cmd, arg->ptr)<0) rb_sys_fail(fptr->path); #endif if (arg->ptr[len] != 17) { - Fail("Return value overflowed string"); + ArgError("Return value overflowed string"); } +#else + rb_notimplement(); +#endif } static VALUE -io_ioctl(obj, req, arg) - VALUE obj, req; +io_ioctl(io, req, arg) + VALUE io, req; struct RString *arg; { - io_ctl(obj, req, arg, 1); - return obj; + io_ctl(io, req, arg, 1); + return io; } static VALUE @@ -1279,7 +1519,7 @@ f_syscall(argc, argv) } switch (argc) { case 0: - Fail("Too few args to syscall"); + ArgError("Too few args to syscall"); case 1: retval = syscall(arg[0]); break; @@ -1335,13 +1575,57 @@ f_syscall(argc, argv) if (retval == -1) rb_sys_fail(0); return INT2FIX(0); #else - Fail("syscall() unimplemented"); + rb_notimplement(); #endif } static VALUE -arg_read(obj) - VALUE obj; +io_pipe() +{ + int pipes[2]; + VALUE r, w, ary; + + if (pipe(pipes) == -1) + rb_sys_fail(0); + r = prep_stdio(fdopen(pipes[0], "r"), FMODE_READABLE); + w = prep_stdio(fdopen(pipes[1], "w"), FMODE_WRITABLE); + + ary = ary_new2(2); + ary_push(ary, r); + ary_push(ary, w); + + return ary; +} + + +static VALUE +io_foreach_line(io) + VALUE io; +{ + VALUE str; + + while (!NIL_P(str = io_gets(io))) { + rb_yield(str); + } + return Qnil; +} + +static VALUE +io_foreach(io, fname) + VALUE io; + struct RString *fname; +{ + VALUE f, v; + + Check_Type(fname, T_STRING); + f = io_open(fname->ptr, "r"); + return rb_ensure(io_foreach_line, f, io_close, f); +} + +static VALUE +arg_read(argc, argv) + int argc; + VALUE argv; { VALUE str, str2; @@ -1349,13 +1633,13 @@ arg_read(obj) for (;;) { retry: if (!next_argv()) return Qnil; - str2 = io_read(0, Qnil, file); - if (str2 == Qnil && next_p != -1) { + str2 = io_read(argc, argv, file); + if (NIL_P(str2) && next_p != -1) { io_close(file); next_p = 1; goto retry; } - if (str2 == Qnil) break; + if (NIL_P(str2)) break; str_cat(str, RSTRING(str2)->ptr, RSTRING(str2)->len); } @@ -1370,7 +1654,7 @@ arg_getc() retry: if (!next_argv()) return Qnil; byte = io_getc(file); - if (byte == Qnil && next_p != -1) { + if (NIL_P(byte) && next_p != -1) { io_close(file); next_p = 1; goto retry; @@ -1380,11 +1664,13 @@ arg_getc() } static VALUE -arg_each_line() +arg_each_line(argc, argv) + int argc; + VALUE argv; { VALUE str; - while (str = f_gets()) { + while (RTEST(str = f_gets_method(argc, argv))) { rb_yield(str); } return Qnil; @@ -1395,7 +1681,7 @@ arg_each_byte() { VALUE byte; - while (byte = arg_getc()) { + while (!NIL_P(byte = arg_getc())) { rb_yield(byte); } return Qnil; @@ -1419,6 +1705,9 @@ void Init_IO() { extern VALUE cKernel; + extern VALUE eException; + + eEOFError = rb_define_class("EOFError", eException); id_write = rb_intern("write"); id_fd = rb_intern("fd"); @@ -1429,32 +1718,46 @@ Init_IO() rb_define_private_method(cKernel, "open", f_open, -1); rb_define_private_method(cKernel, "printf", f_printf, -1); rb_define_private_method(cKernel, "print", f_print, -1); - rb_define_private_method(cKernel, "gets", f_gets, 0); - rb_define_alias(cKernel,"readline", "gets"); + rb_define_private_method(cKernel, "gets", f_gets_method, -1); + rb_define_private_method(cKernel, "readline", f_readline, -1); rb_define_private_method(cKernel, "eof", f_eof, 0); rb_define_private_method(cKernel, "getc", f_getc, 0); + rb_define_private_method(cKernel, "readchar", f_readchar, 0); rb_define_private_method(cKernel, "select", f_select, -1); + rb_define_private_method(cKernel, "ungetc", f_ungetc, 1); - rb_define_private_method(cKernel, "readlines", f_readlines, 0); + rb_define_private_method(cKernel, "readlines", f_readlines, -1); rb_define_method(cKernel, "print_on", f_print_on, 1); + rb_define_private_method(cKernel, "`", f_backquote, 1); + rb_define_private_method(cKernel, "pipe", io_pipe, 0); + + rb_define_private_method(cKernel, "p", f_p, 1); + cIO = rb_define_class("IO", cObject); rb_include_module(cIO, mEnumerable); + rb_define_singleton_method(cIO, "popen", io_popen, -1); + rb_define_singleton_method(cIO, "foreach", io_foreach, 1); + rb_define_singleton_method(cIO, "select", f_select, -1); + + FS = OFS = Qnil; rb_define_hooked_variable("$;", &FS, 0, rb_str_setter); rb_define_hooked_variable("$,", &OFS, 0, rb_str_setter); - RS = str_new2("\n"); + RS = RS_default = str_new2("\n"); ORS = Qnil; + rb_global_variable(&RS_default); rb_define_hooked_variable("$/", &RS, 0, rb_str_setter); rb_define_hooked_variable("$\\", &ORS, 0, rb_str_setter); rb_define_variable("$.", &lineno); - rb_define_variable("$_", &rb_lastline); + rb_define_virtual_variable("$_", lastline_get, lastline_set); rb_define_method(cIO, "print", io_print, -1); + rb_define_method(cIO, "printf", io_printf, -1); - rb_define_method(cIO, "each", io_each_line, 0); + rb_define_method(cIO, "each", io_each_line, -1); rb_define_method(cIO, "each_line", io_each_line, 0); rb_define_method(cIO, "each_byte", io_each_byte, 0); @@ -1469,11 +1772,13 @@ Init_IO() rb_define_alias(cIO, "readlines", "to_a"); - rb_define_method(cIO, "read", io_read, -2); + rb_define_method(cIO, "read", io_read, -1); rb_define_method(cIO, "write", io_write, 1); - rb_define_method(cIO, "gets", io_gets, 0); - rb_define_alias(cIO, "readline", "gets"); + rb_define_method(cIO, "gets", io_gets_method, -1); + rb_define_method(cIO, "readline", io_readline, -1); rb_define_method(cIO, "getc", io_getc, 0); + rb_define_method(cIO, "readchar", io_readchar, 0); + rb_define_method(cIO, "ungetc",io_ungetc, 1); rb_define_method(cIO, "puts", io_puts, 1); rb_define_method(cIO, "<<", io_puts, 1); rb_define_method(cIO, "flush", io_flush, 0); @@ -1497,27 +1802,29 @@ Init_IO() rb_defout = rb_stdout; rb_define_hooked_variable("$>", &rb_defout, 0, io_defset); - rb_define_const(cObject, "STDIN", rb_stdin); - rb_define_const(cObject, "STDOUT", rb_stdout); - rb_define_const(cObject, "STDERR", rb_stderr); + rb_define_global_const("STDIN", rb_stdin); + rb_define_global_const("STDOUT", rb_stdout); + rb_define_global_const("STDERR", rb_stderr); argf = obj_alloc(cObject); rb_extend_object(argf, mEnumerable); rb_define_readonly_variable("$<", &argf); rb_define_readonly_variable("$ARGF", &argf); + rb_define_global_const("ARGF", argf); rb_define_singleton_method(argf, "each", arg_each_line, 0); - rb_define_singleton_method(argf, "each_line", arg_each_line, 0); + rb_define_singleton_method(argf, "each_line", arg_each_line, -1); rb_define_singleton_method(argf, "each_byte", arg_each_byte, 0); - rb_define_singleton_method(argf, "read", arg_read, 0); - rb_define_singleton_method(argf, "readlines", f_readlines, 0); - rb_define_singleton_method(argf, "gets", f_gets, 0); - rb_define_singleton_method(argf, "readline", f_gets, 0); + rb_define_singleton_method(argf, "read", arg_read, -1); + rb_define_singleton_method(argf, "readlines", f_readlines, -1); + rb_define_singleton_method(argf, "gets", f_gets_method, -1); + rb_define_singleton_method(argf, "readline", f_readline, -1); rb_define_singleton_method(argf, "getc", arg_getc, 0); rb_define_singleton_method(argf, "eof", f_eof, 0); rb_define_singleton_method(argf, "eof?", f_eof, 0); + rb_define_singleton_method(argf, "ungetc", f_ungetc, 1); rb_define_singleton_method(argf, "to_s", arg_filename, 0); rb_define_singleton_method(argf, "filename", arg_filename, 0); |