From f433be6d9c9ca7010d2c4368030a09a76bb3b98b Mon Sep 17 00:00:00 2001 From: matz Date: Wed, 6 Oct 2004 15:15:12 +0000 Subject: * io.c (rb_io_s_sysopen): preserve path in the buffer allocated by ALLOCA_N() to prevent modification. [ruby-dev:24438] * io.c (rb_io_mode_flags): preserve append mode flag. [ruby-dev:24436] * io.c (rb_io_modenum_mode): do not use external output buffer. * string.c (rb_str_justify): differ pointer retrieval to prevent padding string modification. [ruby-dev:24434] * range.c (range_each_func): allow func to terminate loop by returning RANGE_EACH_BREAK. * range.c (member_i): use RANGE_EACH_BREAK. [ruby-talk:114959] * marshal.c (r_byte): retrieve pointer from string value for each time. [ruby-dev:24404] * marshal.c (r_bytes0): ditto. * enum.c (sort_by_i): re-entrance check added. [ruby-dev:24399] * io.c (io_read): should freeze all reading buffer. [ruby-dev:24400] * string.c (rb_str_sum): should use bignums when bits is greater than or equals to sizeof(long)*CHAR_BITS. [ruby-dev:24395] * eval.c (specific_eval): defer pointer retrieval to prevent unsafe sourcefile string modification. [ruby-dev:24382] * eval.c (specific_eval): defer pointer retrieval to prevent unsafe sourcefile string modification. [ruby-dev:24382] * string.c (rb_str_sum): wrong cast caused wrong result. [ruby-dev:24385] * enum.c (enum_sort_by): hide temporary array from ObjectSpace.each_object. [ruby-dev:24386] * string.c (rb_str_sum): check was done with false pointer. [ruby-dev:24383] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@7003 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 52 ++++++++++++++++++++++++++ eval.c | 2 +- intern.h | 2 + io.c | 117 ++++++++++++++++++++++++++-------------------------------- lib/pstore.rb | 4 ++ marshal.c | 57 ++++++++++++++-------------- range.c | 42 ++++++++++++--------- rubyio.h | 1 + string.c | 51 +++++++++++++------------ struct.c | 59 +++++++++++++++-------------- 10 files changed, 219 insertions(+), 168 deletions(-) diff --git a/ChangeLog b/ChangeLog index bc3743a893..6196688aa0 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,23 @@ +Thu Oct 7 00:08:37 2004 Yukihiro Matsumoto + + * io.c (rb_io_s_sysopen): preserve path in the buffer allocated by + ALLOCA_N() to prevent modification. [ruby-dev:24438] + +Wed Oct 6 09:21:00 2004 Yukihiro Matsumoto + + * io.c (rb_io_mode_flags): preserve append mode flag. + [ruby-dev:24436] + + * io.c (rb_io_modenum_mode): do not use external output buffer. + + * string.c (rb_str_justify): differ pointer retrieval to prevent + padding string modification. [ruby-dev:24434] + + * range.c (range_each_func): allow func to terminate loop by + returning RANGE_EACH_BREAK. + + * range.c (member_i): use RANGE_EACH_BREAK. [ruby-talk:114959] + Mon Oct 4 14:04:14 2004 Nobuyoshi Nakada * io.c (rb_file_open_internal, rb_io_reopen): fname might be altered @@ -25,6 +45,31 @@ Sat Oct 2 20:34:22 2004 Nobuyoshi Nakada Sat Oct 2 00:42:20 2004 Yukihiro Matsumoto + * marshal.c (r_byte): retrieve pointer from string value for each + time. [ruby-dev:24404] + + * marshal.c (r_bytes0): ditto. + + * enum.c (sort_by_i): re-entrance check added. [ruby-dev:24399] + + * io.c (io_read): should freeze all reading buffer. + [ruby-dev:24400] + + * string.c (rb_str_sum): should use bignums when bits is greater + than or equals to sizeof(long)*CHAR_BITS. [ruby-dev:24395] + + * eval.c (specific_eval): defer pointer retrieval to prevent + unsafe sourcefile string modification. [ruby-dev:24382] + + * eval.c (specific_eval): defer pointer retrieval to prevent + unsafe sourcefile string modification. [ruby-dev:24382] + + * string.c (rb_str_sum): wrong cast caused wrong result. + [ruby-dev:24385] + + * enum.c (enum_sort_by): hide temporary array from + ObjectSpace.each_object. [ruby-dev:24386] + * string.c (rb_str_sum): check was done with false pointer. [ruby-dev:24383] @@ -74,6 +119,13 @@ Wed Sep 29 10:58:07 2004 Nobuyoshi Nakada * enum.c (sort_by_i): internally used object must not be changed outside. [ruby-dev:24368] +Mon Sep 27 13:46:45 2004 Nobuyoshi Nakada + + * intern.h, struct.c (rb_struct_s_members, rb_struct_members): public + accessors. [ruby-dev:24342] + + * marshal.c (w_object, r_object0): use accessors. + Mon Sep 27 09:14:03 2004 Yukihiro Matsumoto * ext/socket/socket.c (s_accept): don't retry for EWOULDBLOCK. diff --git a/eval.c b/eval.c index 65a91587a3..4c0f0123fe 100644 --- a/eval.c +++ b/eval.c @@ -6323,10 +6323,10 @@ specific_eval(argc, argv, klass, self) rb_id2name(ruby_frame->last_func), rb_id2name(ruby_frame->last_func)); } + if (argc > 2) line = NUM2INT(argv[2]); if (argc > 1) { file = StringValuePtr(argv[1]); } - if (argc > 2) line = NUM2INT(argv[2]); } return eval_under(klass, self, argv[0], file, line); } diff --git a/intern.h b/intern.h index bc09ca188c..86ff7bdb48 100644 --- a/intern.h +++ b/intern.h @@ -431,6 +431,8 @@ VALUE rb_struct_aref _((VALUE, VALUE)); VALUE rb_struct_aset _((VALUE, VALUE, VALUE)); VALUE rb_struct_getmember _((VALUE, ID)); VALUE rb_struct_iv_get _((VALUE, char*)); +VALUE rb_struct_s_members _((VALUE)); +VALUE rb_struct_members _((VALUE)); /* time.c */ VALUE rb_time_new _((time_t, time_t)); /* variable.c */ diff --git a/io.c b/io.c index 89b907d25d..b5af714e3a 100644 --- a/io.c +++ b/io.c @@ -2152,32 +2152,27 @@ rb_io_flags_mode(flags, mode) int flags; char *mode; { - char *p = mode; - +#ifdef O_BINARY +# define MODE_BINMODE(a,b) ((flags & FMODE_BINMODE) ? (a) : (b)) +#else +# define MODE_BINMODE(a,b) (a) +#endif + if (flags & FMODE_APPEND) { + if ((flags & FMODE_READWRITE) == FMODE_READWRITE) { + return MODE_BINMODE("a+", "ab+"); + } + return MODE_BINMODE("a", "ab"); + } switch (flags & FMODE_READWRITE) { case FMODE_READABLE: - *p++ = 'r'; - break; + return MODE_BINMODE("r", "rb"); case FMODE_WRITABLE: - *p++ = 'w'; - break; + return MODE_BINMODE("w", "wb"); case FMODE_READWRITE: - *p++ = 'r'; - *p++ = '+'; - break; + return MODE_BINMODE("r+", "rb+"); } - *p++ = '\0'; -#ifdef O_BINARY - if (flags & FMODE_BINMODE) { - if (mode[1] == '+') { - mode[1] = 'b'; mode[2] = '+'; mode[3] = '\0'; - } - else { - mode[1] = 'b'; mode[2] = '\0'; - } - } -#endif - return mode; + rb_raise(rb_eArgError, "illegal access mode %o", flags); + return NULL; /* not reached */ } int @@ -2195,7 +2190,7 @@ rb_io_mode_flags(mode) flags |= FMODE_WRITABLE; break; case 'a': - flags |= FMODE_WRITABLE; + flags |= FMODE_WRITABLE | FMODE_APPEND; break; default: error: @@ -2232,10 +2227,13 @@ rb_io_modenum_flags(mode) flags = FMODE_WRITABLE; break; case O_RDWR: - flags = FMODE_WRITABLE|FMODE_READABLE; + flags = FMODE_READWRITE; break; } + if (mode & O_APPEND) { + flags |= FMODE_APPEND; + } #ifdef O_BINARY if (mode & O_BINARY) { flags |= FMODE_BINMODE; @@ -2288,36 +2286,30 @@ rb_io_mode_modenum(mode) #define MODENUM_MAX 4 static char* -rb_io_modenum_mode(flags, mode) +rb_io_modenum_mode(flags) int flags; - char *mode; { - char *p = mode; - +#ifdef O_BINARY +# define MODE_BINARY(a,b) ((mode & O_BINARY) ? (a) : (b)) +#else +# define MODE_BINARY(a,b) (a) +#endif + if (flags & O_APPEND) { + if ((flags & O_RDWR) == O_RDWR) { + return MODE_BINARY("a+", "ab+"); + } + return MODE_BINARY("a", "ab"); + } switch (flags & (O_RDONLY|O_WRONLY|O_RDWR)) { case O_RDONLY: - *p++ = 'r'; - break; + return MODE_BINARY("r", "rb"); case O_WRONLY: - *p++ = 'w'; - break; + return MODE_BINARY("w", "wb"); case O_RDWR: - *p++ = 'r'; - *p++ = '+'; - break; - } - *p++ = '\0'; -#ifdef O_BINARY - if (flags & O_BINARY) { - if (mode[1] == '+') { - mode[1] = 'b'; mode[2] = '+'; mode[3] = '\0'; - } - else { - mode[1] = 'b'; mode[2] = '\0'; - } + return MODE_BINARY("r+", "rb+"); } -#endif - return mode; + rb_raise(rb_eArgError, "illegal access modenum %o", flags); + return NULL; /* not reached */ } static int @@ -2442,15 +2434,14 @@ rb_file_sysopen_internal(io, fname, flags, mode) OpenFile *fptr; int fd; char *m; - char mbuf[MODENUM_MAX]; MakeOpenFile(io, fptr); - fd = rb_sysopen(fname, flags, mode); - m = rb_io_modenum_mode(flags, mbuf); + fptr->path = strdup(fname); + m = rb_io_modenum_mode(flags); fptr->mode = rb_io_modenum_flags(flags); + fd = rb_sysopen(fptr->path, flags, mode); fptr->f = rb_fdopen(fd, m); - fptr->path = strdup(fname); return io; } @@ -2723,7 +2714,7 @@ rb_io_popen(str, argc, argv, klass) mode = "r"; } else if (FIXNUM_P(pmode)) { - mode = rb_io_modenum_mode(FIX2INT(pmode), mbuf); + mode = rb_io_modenum_mode(FIX2INT(pmode)); } else { strncpy(mbuf, StringValuePtr(pmode), sizeof(mbuf) - 1); @@ -2811,12 +2802,11 @@ rb_open_file(argc, argv, io) VALUE io; { VALUE fname, vmode, perm; - char *path, *mode; + char *mode; int flags, fmode; rb_scan_args(argc, argv, "12", &fname, &vmode, &perm); SafeStringValue(fname); - path = RSTRING(fname)->ptr; if (FIXNUM_P(vmode) || !NIL_P(perm)) { if (FIXNUM_P(vmode)) { @@ -2828,7 +2818,7 @@ rb_open_file(argc, argv, io) } fmode = NIL_P(perm) ? 0666 : NUM2INT(perm); - rb_file_sysopen_internal(io, path, flags, fmode); + rb_file_sysopen_internal(io, RSTRING(fname)->ptr, flags, fmode); } else { mode = NIL_P(vmode) ? "r" : StringValuePtr(vmode); @@ -2883,6 +2873,7 @@ rb_io_s_sysopen(argc, argv) { VALUE fname, vmode, perm; int flags, fmode, fd; + char *path; rb_scan_args(argc, argv, "12", &fname, &vmode, &perm); SafeStringValue(fname); @@ -2896,7 +2887,9 @@ rb_io_s_sysopen(argc, argv) if (NIL_P(perm)) fmode = 0666; else fmode = NUM2INT(perm); - fd = rb_sysopen(RSTRING(fname)->ptr, flags, fmode); + path = ALLOCA_N(char, strlen(RSTRING(fname)->ptr)+1); + strcpy(path, RSTRING(fname)->ptr); + fd = rb_sysopen(path, flags, fmode); return INT2NUM(fd); } @@ -3147,7 +3140,7 @@ rb_io_reopen(argc, argv, file) VALUE file; { VALUE fname, nmode; - char mode[MODENUM_MAX]; + char *mode; OpenFile *fptr; rb_secure(4); @@ -3159,7 +3152,6 @@ rb_io_reopen(argc, argv, file) } SafeStringValue(fname); - rb_io_taint_check(file); fptr = RFILE(file)->fptr; if (!fptr) { @@ -3168,11 +3160,7 @@ rb_io_reopen(argc, argv, file) } if (!NIL_P(nmode)) { - strncpy(mode, StringValuePtr(nmode), sizeof(mode)); - mode[sizeof(mode) - 1] = 0; - } - else { - rb_io_flags_mode(fptr->mode, mode); + fptr->mode = rb_io_mode_flags(StringValuePtr(nmode)); } if (fptr->path) { @@ -3181,7 +3169,7 @@ rb_io_reopen(argc, argv, file) } fptr->path = strdup(RSTRING(fname)->ptr); - fptr->mode = rb_io_mode_flags(mode); + mode = rb_io_flags_mode(fptr->mode); if (!fptr->f) { fptr->f = rb_fopen(fptr->path, mode); if (fptr->f2) { @@ -3739,7 +3727,6 @@ rb_io_initialize(argc, argv, io) VALUE fnum, mode; OpenFile *fp; int fd, flags; - char mbuf[MODENUM_MAX]; rb_secure(4); rb_scan_args(argc, argv, "11", &fnum, &mode); @@ -3763,7 +3750,7 @@ rb_io_initialize(argc, argv, io) } MakeOpenFile(io, fp); fp->mode = rb_io_modenum_flags(flags); - fp->f = rb_fdopen(fd, rb_io_modenum_mode(flags, mbuf)); + fp->f = rb_fdopen(fd, rb_io_modenum_mode(flags)); return io; } diff --git a/lib/pstore.rb b/lib/pstore.rb index c4c6dd56a5..50313dcb8f 100644 --- a/lib/pstore.rb +++ b/lib/pstore.rb @@ -99,11 +99,13 @@ class PStore content = nil unless read_only file = File.open(@filename, File::RDWR | File::CREAT) + file.binmode file.flock(File::LOCK_EX) commit_new(file) if FileTest.exist?(new_file) content = file.read() else file = File.open(@filename, File::RDONLY) + file.binmode file.flock(File::LOCK_SH) content = (File.read(new_file) rescue file.read()) end @@ -132,6 +134,7 @@ class PStore content = dump(@table) if !md5 || size != content.size || md5 != Digest::MD5.digest(content) File.open(tmp_file, "w") {|t| + t.binmode t.write(content) } File.rename(tmp_file, new_file) @@ -166,6 +169,7 @@ class PStore f.rewind new_file = @filename + ".new" File.open(new_file) do |nf| + nf.binmode FileUtils.copy_stream(nf, f) end File.unlink(new_file) diff --git a/marshal.c b/marshal.c index f4832a481f..71c6d16699 100644 --- a/marshal.c +++ b/marshal.c @@ -635,10 +635,7 @@ w_object(obj, arg, limit) long i; w_long(len, arg); - mem = rb_struct_iv_get(rb_obj_class(obj), "__member__"); - if (mem == Qnil) { - rb_raise(rb_eTypeError, "uninitialized struct"); - } + mem = rb_struct_members(obj); for (i=0; iptr[i]), arg); w_object(RSTRUCT(obj)->ptr[i], arg, limit); @@ -782,7 +779,8 @@ marshal_dump(argc, argv) } struct load_arg { - char *ptr, *end; + VALUE src; + long offset; st_table *symbols; VALUE data; VALUE proc; @@ -797,18 +795,20 @@ r_byte(arg) { int c; - if (!arg->end) { - VALUE src = (VALUE)arg->ptr; + if (TYPE(arg->src) == T_STRING) { + if (RSTRING(arg->src)->len > arg->offset) { + c = (unsigned char)RSTRING(arg->src)->ptr[arg->offset++]; + } + else { + rb_raise(rb_eArgError, "marshal data too short"); + } + } + else { + VALUE src = arg->src; VALUE v = rb_funcall2(src, s_getc, 0, 0); if (NIL_P(v)) rb_eof_error(); c = (unsigned char)FIX2INT(v); } - else if (arg->ptr < arg->end) { - c = *(unsigned char*)arg->ptr++; - } - else { - rb_raise(rb_eArgError, "marshal data too short"); - } return c; } @@ -871,8 +871,19 @@ r_bytes0(len, arg) { VALUE str; - if (!arg->end) { - VALUE src = (VALUE)arg->ptr; + if (len == 0) return rb_str_new(0, 0); + if (TYPE(arg->src) == T_STRING) { + if (RSTRING(arg->src)->len > arg->offset) { + str = rb_str_new(RSTRING(arg->src)->ptr+arg->offset, len); + arg->offset += len; + } + else { + too_short: + rb_raise(rb_eArgError, "marshal data too short"); + } + } + else { + VALUE src = arg->src; VALUE n = LONG2NUM(len); str = rb_funcall2(src, s_read, 1, &n); if (NIL_P(str)) goto too_short; @@ -880,14 +891,6 @@ r_bytes0(len, arg) if (RSTRING(str)->len != len) goto too_short; if (OBJ_TAINTED(str)) arg->taint = Qtrue; } - else { - if (arg->ptr + len > arg->end) { - too_short: - rb_raise(rb_eArgError, "marshal data too short"); - } - str = rb_str_new(arg->ptr, len); - arg->ptr += len; - } return str; } @@ -1195,7 +1198,7 @@ r_object0(arg, proc, ivp, extmod) ID slot; klass = path2class(r_unique(arg)); - mem = rb_struct_iv_get(klass, "__member__"); + mem = rb_struct_s_members(klass); if (mem == Qnil) { rb_raise(rb_eTypeError, "uninitialized struct"); } @@ -1393,20 +1396,18 @@ marshal_load(argc, argv) if (rb_respond_to(port, rb_intern("to_str"))) { arg.taint = OBJ_TAINTED(port); /* original taintedness */ StringValue(port); /* possible conversion */ - arg.ptr = RSTRING(port)->ptr; - arg.end = arg.ptr + RSTRING(port)->len; } else if (rb_respond_to(port, s_getc) && rb_respond_to(port, s_read)) { if (rb_respond_to(port, s_binmode)) { rb_funcall2(port, s_binmode, 0, 0); } arg.taint = Qtrue; - arg.ptr = (char *)port; - arg.end = 0; } else { rb_raise(rb_eTypeError, "instance of IO needed"); } + arg.src = port; + arg.offset = 0; major = r_byte(&arg); minor = r_byte(&arg); diff --git a/range.c b/range.c index be0896bcfe..a48ee732a4 100644 --- a/range.c +++ b/range.c @@ -230,18 +230,8 @@ str_step(args) return rb_str_upto(args[0], args[1], EXCL(args[2])); } -static VALUE -step_i(i, iter) - VALUE i; - long *iter; -{ - iter[0]--; - if (iter[0] == 0) { - rb_yield(i); - iter[0] = iter[1]; - } - return Qnil; -} +#define RANGE_EACH_BREAK Qfalse +#define RANGE_EACH_CONTINUE Qtrue static void range_each_func(range, func, v, e, arg) @@ -254,19 +244,32 @@ range_each_func(range, func, v, e, arg) if (EXCL(range)) { while (r_lt(v, e)) { - (*func)(v, arg); + if ((*func)(v, arg) == RANGE_EACH_BREAK) break; v = rb_funcall(v, id_succ, 0, 0); } } else { while (RTEST(c = r_le(v, e))) { - (*func)(v, arg); + if ((*func)(v, arg) == RANGE_EACH_BREAK) break; if (c == INT2FIX(0)) break; v = rb_funcall(v, id_succ, 0, 0); } } } +static VALUE +step_i(i, iter) + VALUE i; + long *iter; +{ + iter[0]--; + if (iter[0] == 0) { + rb_yield(i); + iter[0] = iter[1]; + } + return RANGE_EACH_CONTINUE; +} + /* * call-seq: * rng.step(n=1) {| obj | block } => rng @@ -335,7 +338,7 @@ range_step(argc, argv, range) if (unit == 0) rb_raise(rb_eArgError, "step can't be 0"); args[0] = b; args[1] = e; args[2] = range; iter[0] = 1; iter[1] = unit; - rb_iterate((VALUE(*)_((VALUE)))str_step, (VALUE)args, step_i, (VALUE)iter); + rb_iterate(str_step, (VALUE)args, step_i, (VALUE)iter); } else if (rb_obj_is_kind_of(b, rb_cNumeric)) { ID c = rb_intern(EXCL(range) ? "<" : "<="); @@ -368,7 +371,8 @@ each_i(v, arg) VALUE v; void *arg; { - return rb_yield(v); + rb_yield(v); + return RANGE_EACH_CONTINUE; } /* @@ -417,7 +421,7 @@ range_each(range) args[0] = beg; args[1] = end; args[2] = range; iter[0] = 1; iter[1] = 1; - rb_iterate((VALUE(*)_((VALUE)))str_step, (VALUE)args, step_i, (VALUE)iter); + rb_iterate(str_step, (VALUE)args, step_i, (VALUE)iter); } else { range_each_func(range, each_i, beg, end, NULL); @@ -548,14 +552,16 @@ range_inspect(range) return str; } -static void +static VALUE member_i(v, args) VALUE v; VALUE *args; { if (rb_equal(v, args[0])) { args[1] = Qtrue; + return RANGE_EACH_BREAK; } + return RANGE_EACH_CONTINUE; } /* diff --git a/rubyio.h b/rubyio.h index 26f86b0d07..a3d55b81df 100644 --- a/rubyio.h +++ b/rubyio.h @@ -29,6 +29,7 @@ typedef struct OpenFile { #define FMODE_READABLE 1 #define FMODE_WRITABLE 2 #define FMODE_READWRITE 3 +#define FMODE_APPEND 64 #define FMODE_BINMODE 4 #define FMODE_SYNC 8 #define FMODE_WBUF 16 diff --git a/string.c b/string.c index 8782e41bc2..d70ea21868 100644 --- a/string.c +++ b/string.c @@ -4380,35 +4380,35 @@ rb_str_sum(argc, argv, str) ptr = p = RSTRING(str)->ptr; len = RSTRING(str)->len; pend = p + len; - if (bits > sizeof(long)*CHAR_BIT) { - VALUE res = INT2FIX(0); - VALUE mod; - - mod = rb_funcall(INT2FIX(1), rb_intern("<<"), 1, INT2FIX(bits)); - mod = rb_funcall(mod, '-', 1, INT2FIX(1)); + if (bits >= sizeof(long)*CHAR_BIT) { + VALUE sum = INT2FIX(0); while (p < pend) { str_mod_check(str, ptr, len); - res = rb_funcall(res, '+', 1, INT2FIX((unsigned int)*p)); + sum = rb_funcall(sum, '+', 1, INT2FIX((unsigned char)*p)); p++; } - res = rb_funcall(res, '&', 1, mod); - return res; + if (bits != 0) { + VALUE mod; + + mod = rb_funcall(INT2FIX(1), rb_intern("<<"), 1, INT2FIX(bits)); + mod = rb_funcall(mod, '-', 1, INT2FIX(1)); + sum = rb_funcall(sum, '&', 1, mod); + } + return sum; } else { - unsigned int res = 0; - unsigned int mod = (1<len > 0) { - f = RSTRING(pad)->ptr; - flen = RSTRING(pad)->len; - } - } - } + rb_scan_args(argc, argv, "11", &w, &pad); width = NUM2LONG(w); if (width < 0 || RSTRING(str)->len >= width) return rb_str_dup(str); res = rb_str_new5(str, 0, width); + if (argc == 0) { + StringValue(pad); + if (RSTRING(pad)->len > 0) { + f = RSTRING(pad)->ptr; + flen = RSTRING(pad)->len; + } + } p = RSTRING(res)->ptr; if (jflag != 'l') { n = width - RSTRING(str)->len; diff --git a/struct.c b/struct.c index b5454b4bea..a82799de4d 100644 --- a/struct.c +++ b/struct.c @@ -33,8 +33,8 @@ rb_struct_iv_get(c, name) } } -static VALUE -struct_s_members(klass) +VALUE +rb_struct_s_members(klass) VALUE klass; { VALUE members = rb_struct_iv_get(klass, "__members__"); @@ -45,15 +45,12 @@ struct_s_members(klass) return members; } -static VALUE -struct_members(s) +VALUE +rb_struct_members(s) VALUE s; { - VALUE members = struct_s_members(rb_obj_class(s)); + VALUE members = rb_struct_s_members(rb_obj_class(s)); - if (NIL_P(members)) { - rb_bug("non-initialized struct"); - } if (RSTRUCT(s)->len != RARRAY(members)->len) { rb_raise(rb_eTypeError, "struct size differs (%d required %d given)", RARRAY(members)->len, RSTRUCT(s)->len); @@ -62,13 +59,13 @@ struct_members(s) } static VALUE -rb_struct_s_members(klass) +rb_struct_s_members_m(klass) VALUE klass; { VALUE members, ary; VALUE *p, *pend; - members = struct_s_members(klass); + members = rb_struct_s_members(klass); ary = rb_ary_new2(RARRAY(members)->len); p = RARRAY(members)->ptr; pend = p + RARRAY(members)->len; while (p < pend) { @@ -92,10 +89,10 @@ rb_struct_s_members(klass) */ static VALUE -rb_struct_members(obj) +rb_struct_members_m(obj) VALUE obj; { - return rb_struct_s_members(rb_obj_class(obj)); + return rb_struct_s_members_m(rb_obj_class(obj)); } VALUE @@ -106,10 +103,7 @@ rb_struct_getmember(obj, id) VALUE members, slot; long i; - members = rb_struct_iv_get(rb_obj_class(obj), "__members__"); - if (NIL_P(members)) { - rb_bug("uninitialized struct"); - } + members = rb_struct_members(obj); slot = ID2SYM(id); for (i=0; ilen; i++) { if (RARRAY(members)->ptr[i] == slot) { @@ -167,10 +161,7 @@ rb_struct_set(obj, val) VALUE members, slot; long i; - members = rb_struct_iv_get(rb_obj_class(obj), "__members__"); - if (NIL_P(members)) { - rb_bug("uninitialized struct"); - } + members = rb_struct_members(obj); rb_struct_modify(obj); for (i=0; ilen; i++) { slot = RARRAY(members)->ptr[i]; @@ -215,7 +206,7 @@ make_struct(name, members, klass) rb_define_alloc_func(nstr, struct_alloc); rb_define_singleton_method(nstr, "new", rb_class_new_instance, -1); rb_define_singleton_method(nstr, "[]", rb_class_new_instance, -1); - rb_define_singleton_method(nstr, "members", rb_struct_s_members, 0); + rb_define_singleton_method(nstr, "members", rb_struct_s_members_m, 0); for (i=0; i< RARRAY(members)->len; i++) { ID id = SYM2ID(RARRAY(members)->ptr[i]); if (i<10) { @@ -315,12 +306,19 @@ rb_struct_s_def(argc, argv, klass) id = rb_to_id(RARRAY(rest)->ptr[i]); RARRAY(rest)->ptr[i] = ID2SYM(id); } - if (!NIL_P(name) && TYPE(name) != T_STRING) { - id = rb_to_id(name); - rb_ary_unshift(rest, ID2SYM(id)); - name = Qnil; + if (!NIL_P(name)) { + VALUE tmp = rb_check_string_type(name); + + if (NIL_P(tmp)) { + id = rb_to_id(name); + rb_ary_unshift(rest, ID2SYM(id)); + name = Qnil; + } } st = make_struct(name, rest, klass); + if (rb_block_given_p()) { + rb_mod_module_eval(0, 0, st); + } return st; } @@ -456,7 +454,7 @@ rb_struct_each_pair(s) VALUE members; long i; - members = struct_members(s); + members = rb_struct_members(s); for (i=0; ilen; i++) { rb_yield_values(2, rb_ary_entry(members, i), RSTRUCT(s)->ptr[i]); } @@ -471,7 +469,7 @@ inspect_struct(s) VALUE str, members; long i; - members = struct_members(s); + members = rb_struct_members(s); str = rb_str_buf_new2("#len, RSTRUCT(s)->ptr); } +/* :nodoc: */ static VALUE rb_struct_init_copy(copy, s) VALUE copy, s; @@ -561,7 +560,7 @@ rb_struct_aref_id(s, id) VALUE members; long i, len; - members = struct_members(s); + members = rb_struct_members(s); len = RARRAY(members)->len; for (i=0; iptr[i]) == id) { @@ -620,7 +619,7 @@ rb_struct_aset_id(s, id, val) VALUE members; long i, len; - members = struct_members(s); + members = rb_struct_members(s); rb_struct_modify(s); len = RARRAY(members)->len; if (RSTRUCT(s)->len != RARRAY(members)->len) { @@ -907,5 +906,5 @@ Init_Struct() rb_define_method(rb_cStruct, "select", rb_struct_select, -1); rb_define_method(rb_cStruct, "values_at", rb_struct_values_at, -1); - rb_define_method(rb_cStruct, "members", rb_struct_members, 0); + rb_define_method(rb_cStruct, "members", rb_struct_members_m, 0); } -- cgit v1.2.3