summaryrefslogtreecommitdiff
path: root/io.c
diff options
context:
space:
mode:
Diffstat (limited to 'io.c')
-rw-r--r--io.c885
1 files changed, 596 insertions, 289 deletions
diff --git a/io.c b/io.c
index 47bd4b0fb0..43e2458668 100644
--- a/io.c
+++ b/io.c
@@ -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);