1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

* array.c (rb_ary_modify): should copy the internal buffer if the

modifying buffer is shared.

* array.c (ary_make_shared): make an internal buffer of an array
  to be shared.

* array.c (rb_ary_shift): avoid sliding an internal buffer by
  using shared buffer.

* array.c (rb_ary_subseq): avoid copying the buffer.

* parse.y (gettable): should freeze __LINE__ string.

* io.c (rb_io_puts): old behavoir restored.  rationale: a) if you
  want to call to_s for arrays, you can just call print a, "\n".
  b) to_s wastes memory if array (and sum of its contents) is
  huge.  c) now any object that has to_ary is treated as an array,
  using rb_check_convert_type().

* hash.c (rb_hash_initialize): now accepts a block to calculate
  the default value. [new]

* hash.c (rb_hash_aref): call "default" method to get the value
  corrensponding to the non existing key.

* hash.c (rb_hash_default): get the default value based on the
  block given to 'new'.  Now it takes an optinal "key" argument.
  "default" became the method to get the value for non existing
  key.  Users may override "default" method to change the hash
  behavior.

* hash.c (rb_hash_set_default): clear the flag if a block is given
  to 'new'

* object.c (Init_Object): undef Data.allocate, left Data.new.

* ext/curses/curses.c (window_scrollok): use RTEST().

* ext/curses/curses.c (window_idlok): ditto.

* ext/curses/curses.c (window_keypad): ditto.

* ext/curses/curses.c (window_idlok): idlok() may return void on
  some platforms; so don't use return value.

* ext/curses/curses.c (window_scrollok): ditto for consistency.

* ext/curses/curses.c: replace FIX2INT() by typechecking NUM2INT().

* parse.y (str_extend): should not process immature #$x and
  #@x interpolation, e.g #@#@ etc.

* enum.c (enum_sort_by): sort_by does not have to be stable always.

* enum.c (enum_sort_by): call qsort directly to gain performance.

* util.c (ruby_qsort): ruby_qsort(qs6) is now native thread safe.

* error.c (rb_sys_fail): it must be a bug if it's called when
  errno == 0.

* regex.c (WC2MBC1ST): should not pass through > 0x80 number in UTF-8.


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1896 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 2001-12-10 07:18:16 +00:00
parent 3493ea5c7a
commit 2f8d3bdc21
19 changed files with 651 additions and 334 deletions

126
ChangeLog
View file

@ -1,15 +1,53 @@
Sun Dec 9 23:00:54 2001 Keiju Ishitsuka <keiju@ishitsuka.com> Mon Dec 10 02:09:28 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* matrix.rb: Vector#* bug. reported from Massimiliano Mirra
<info@chromatic-harp.com>.
Sun Dec 9 22:15:59 2001 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp> * array.c (rb_ary_modify): should copy the internal buffer if the
modifying buffer is shared.
* enum.c (enum_sort_by): should replace with last elements. * array.c (ary_make_shared): make an internal buffer of an array
to be shared.
* array.c (rb_ary_shift): avoid sliding an internal buffer by
using shared buffer.
* array.c (rb_ary_subseq): avoid copying the buffer.
Mon Dec 10 01:06:56 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* parse.y (gettable): should freeze __LINE__ string.
Sun Dec 9 18:06:26 2001 Minero Aoki <aamine@loveruby.net> Sun Dec 9 18:06:26 2001 Minero Aoki <aamine@loveruby.net>
* lib/net/protocol.rb: calls on_connect before conn_command * lib/net/protocol.rb: calls on_connect before conn_command
Sat Dec 8 23:27:44 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* io.c (rb_io_puts): old behavoir restored. rationale: a) if you
want to call to_s for arrays, you can just call print a, "\n".
b) to_s wastes memory if array (and sum of its contents) is
huge. c) now any object that has to_ary is treated as an array,
using rb_check_convert_type().
Sat Dec 8 22:40:38 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* hash.c (rb_hash_initialize): now accepts a block to calculate
the default value. [new]
* hash.c (rb_hash_aref): call "default" method to get the value
corrensponding to the non existing key.
* hash.c (rb_hash_default): get the default value based on the
block given to 'new'. Now it takes an optinal "key" argument.
"default" became the method to get the value for non existing
key. Users may override "default" method to change the hash
behavior.
* hash.c (rb_hash_set_default): clear the flag if a block is given
to 'new'
Sat Dec 8 02:29:54 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* object.c (Init_Object): undef Data.allocate, left Data.new.
Fri Dec 7 19:12:14 2001 Minero Aoki <aamine@loveruby.net> Fri Dec 7 19:12:14 2001 Minero Aoki <aamine@loveruby.net>
* lib/net/smtp.rb: SMTP.new requires at least one arg. * lib/net/smtp.rb: SMTP.new requires at least one arg.
@ -27,12 +65,83 @@ Fri Dec 7 15:49:39 2001 Usaku Nakamura <usa@ruby-lang.org>
* ext/extmk.rb.in: ignore adding -Wl,-R to DLDFLAGS when the directory * ext/extmk.rb.in: ignore adding -Wl,-R to DLDFLAGS when the directory
is $topdir. is $topdir.
Fri Dec 7 13:58:58 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* ext/curses/curses.c (window_scrollok): use RTEST().
* ext/curses/curses.c (window_idlok): ditto.
* ext/curses/curses.c (window_keypad): ditto.
* ext/curses/curses.c (window_idlok): idlok() may return void on
some platforms; so don't use return value.
* ext/curses/curses.c (window_scrollok): ditto for consistency.
* ext/curses/curses.c: replace FIX2INT() by typechecking NUM2INT().
Fri Dec 7 09:51:00 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* parse.y (str_extend): should not process immature #$x and
#@x interpolation, e.g #@#@ etc.
Fri Dec 7 03:21:18 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* enum.c (enum_sort_by): sort_by does not have to be stable always.
* enum.c (enum_sort_by): call qsort directly to gain performance.
Thu Dec 6 18:52:28 2001 Usaku Nakamura <usa@ruby-lang.org> Thu Dec 6 18:52:28 2001 Usaku Nakamura <usa@ruby-lang.org>
* ext/extmk.rb.in: add -Wl,-R flags to DLDFLAGS on netbsdelf. * ext/extmk.rb.in: add -Wl,-R flags to DLDFLAGS on netbsdelf.
* lib/mkmf.rb: ditto. * lib/mkmf.rb: ditto.
Thu Dec 6 09:15:14 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* util.c (ruby_qsort): ruby_qsort(qs6) is now native thread safe.
* error.c (rb_sys_fail): it must be a bug if it's called when
errno == 0.
Wed Dec 5 23:36:56 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* regex.c (WC2MBC1ST): should not pass through > 0x80 number in UTF-8.
Tue Dec 4 17:43:10 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* ruby.h (DUPSETUP): new SETUP macro for duplication.
* time.c (time_dup): implement in Time class using DUPSETUP.
* time.c (time_getlocaltime): new method; probably requires
better name than getlocaltime. [new,experimental]
* time.c (time_getgmtime): ditto.
* array.c (rb_ary_dup): uses DUPSETUP.
* string.c (rb_str_dup): uses DUPSETUP. now properly copies
instance variables too.
Tue Dec 4 03:49:06 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* io.c (io_fread): EAGAIN/EWOULDBLOCK should not terminate and
throw away the input.
* time.c (time_new_internal): underflow adjustment must not use
negative div/mod.
* time.c (time_cmp): should consider tv_usec on non Fixnum number
comparison.
Sun Dec 9 23:00:54 2001 Keiju Ishitsuka <keiju@ishitsuka.com>
* matrix.rb: Vector#* bug. reported from Massimiliano Mirra
<info@chromatic-harp.com>.
Sun Dec 9 22:15:59 2001 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp>
* enum.c (enum_sort_by): should replace with last elements.
Mon Dec 3 16:06:57 2001 WATANABE Hirofumi <eban@ruby-lang.org> Mon Dec 3 16:06:57 2001 WATANABE Hirofumi <eban@ruby-lang.org>
* ext/socket/extconf.rb: remove -L/usr/local/lib. * ext/socket/extconf.rb: remove -L/usr/local/lib.
@ -43,6 +152,13 @@ Mon Dec 3 16:04:16 2001 Usaku Nakamura <usa@ruby-lang.org>
* configure.in: not use X11BASE, since it's not always set. * configure.in: not use X11BASE, since it's not always set.
Mon Dec 3 13:53:49 2001 Tanaka Akira <akr@m17n.org>
* time.c (rb_strftime): buffer length condition was wrong.
* time.c (time_strftime): should backup buf to the original
buffer.
Mon Dec 3 09:59:08 2001 Yukihiro Matsumoto <matz@ruby-lang.org> Mon Dec 3 09:59:08 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* time.c (time_plus): must detect result overflow. * time.c (time_plus): must detect result overflow.

10
ToDo
View file

@ -71,9 +71,11 @@ Standard Libraries
- fork_and_kill_other_threads. - fork_and_kill_other_threads.
- signal list (Signal::trap, Signal::list). - signal list (Signal::trap, Signal::list).
- move NameError under StandardError. - move NameError under StandardError.
- Integer#to_s(base)
- Hash::new{default}
- hash etc. should handle self referenceing array/hash
* String#scanf(?) * String#scanf(?)
* Object#fmt(?) * Object#fmt(?)
* Integer#{bin,oct,hex,heX}
* Time::strptime * Time::strptime
* Integer[num], Float[num]; Fixnum[num]? * Integer[num], Float[num]; Fixnum[num]?
* method to retrieve non-number trailer for to_i/to_f. * method to retrieve non-number trailer for to_i/to_f.
@ -86,16 +88,16 @@ Standard Libraries
* Array#&, Array#| to allow duplication. ??? * Array#&, Array#| to allow duplication. ???
* way to specify immortal (fork endurance) thread; * way to specify immortal (fork endurance) thread;
* or raise ForkException to every thread but fork caller. * or raise ForkException to every thread but fork caller.
* Hash::new{default} or recommend Hash#fetch?
* new user-defined marshal scheme. _dump(dumper), _load(restorer) * new user-defined marshal scheme. _dump(dumper), _load(restorer)
* hash etc. should handle self referenceing array/hash
* library to load per-user profile seeking .ruby_profile or ruby.ini file. * library to load per-user profile seeking .ruby_profile or ruby.ini file.
* warning framework (warn, warning for Ruby level) * warning framework (warn, warning for Ruby level)
* marshal should not depend on sprintf/strtod (works bad for locale). * marshal should not depend on sprintf/strtod (works bad with locale).
* ternary arg pow: a.pow(b,c) == a**b%c * ternary arg pow: a.pow(b,c) == a**b%c
* new caller(), e.g. call_stack; needs better name. * new caller(), e.g. call_stack; needs better name.
* remove dependency on MAXPATHLEN. * remove dependency on MAXPATHLEN.
* pointer share mechanism similar to one in String for Array. * pointer share mechanism similar to one in String for Array.
* Array#select(n1,n2...) works like Array#indexes(n1,n2...)
* deprecate Array#indexes, and Array#indices.
Extension Libraries Extension Libraries

209
array.c
View file

@ -17,7 +17,7 @@
#include "st.h" #include "st.h"
VALUE rb_cArray; VALUE rb_cArray;
static ID cmp; static ID id_cmp;
#define ARY_DEFAULT_SIZE 16 #define ARY_DEFAULT_SIZE 16
@ -45,7 +45,7 @@ memfill(mem, size, val)
#define ARY_TMPLOCK FL_USER1 #define ARY_TMPLOCK FL_USER1
static void static void
rb_ary_modify(ary) rb_ary_modify_check(ary)
VALUE ary; VALUE ary;
{ {
if (OBJ_FROZEN(ary)) rb_error_frozen("array"); if (OBJ_FROZEN(ary)) rb_error_frozen("array");
@ -55,6 +55,21 @@ rb_ary_modify(ary)
rb_raise(rb_eSecurityError, "Insecure: can't modify array"); rb_raise(rb_eSecurityError, "Insecure: can't modify array");
} }
static void
rb_ary_modify(ary)
VALUE ary;
{
VALUE *ptr;
rb_ary_modify_check(ary);
if (!FL_TEST(ary, ELTS_SHARED)) return;
ptr = ALLOC_N(VALUE, RARRAY(ary)->len);
FL_UNSET(ary, ELTS_SHARED);
RARRAY(ary)->aux.capa = RARRAY(ary)->len;
MEMCPY(ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
RARRAY(ary)->ptr = ptr;
}
VALUE VALUE
rb_ary_freeze(ary) rb_ary_freeze(ary)
VALUE ary; VALUE ary;
@ -79,14 +94,14 @@ rb_ary_s_alloc(klass)
OBJSETUP(ary, klass, T_ARRAY); OBJSETUP(ary, klass, T_ARRAY);
ary->len = 0; ary->len = 0;
ary->capa = 0;
ary->ptr = 0; ary->ptr = 0;
ary->aux.capa = 0;
return (VALUE)ary; return (VALUE)ary;
} }
VALUE static VALUE
rb_ary_new0(klass, len) ary_new(klass, len)
VALUE klass; VALUE klass;
long len; long len;
{ {
@ -100,7 +115,7 @@ rb_ary_new0(klass, len)
} }
if (len == 0) len++; if (len == 0) len++;
RARRAY(ary)->ptr = ALLOC_N(VALUE, len); RARRAY(ary)->ptr = ALLOC_N(VALUE, len);
RARRAY(ary)->capa = len; RARRAY(ary)->aux.capa = len;
return ary; return ary;
} }
@ -109,7 +124,7 @@ VALUE
rb_ary_new2(len) rb_ary_new2(len)
long len; long len;
{ {
return rb_ary_new0(rb_cArray, len); return ary_new(rb_cArray, len);
} }
@ -228,9 +243,9 @@ rb_ary_initialize(argc, argv, ary)
if (len > 0 && len*sizeof(VALUE) <= 0) { if (len > 0 && len*sizeof(VALUE) <= 0) {
rb_raise(rb_eArgError, "array size too big"); rb_raise(rb_eArgError, "array size too big");
} }
if (len > RARRAY(ary)->capa) { if (len > RARRAY(ary)->aux.capa) {
RARRAY(ary)->capa = len; RARRAY(ary)->aux.capa = len;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
} }
memfill(RARRAY(ary)->ptr, len, val); memfill(RARRAY(ary)->ptr, len, val);
RARRAY(ary)->len = len; RARRAY(ary)->len = len;
@ -250,7 +265,7 @@ rb_ary_s_create(argc, argv, klass)
RARRAY(ary)->ptr = ALLOC_N(VALUE, argc); RARRAY(ary)->ptr = ALLOC_N(VALUE, argc);
MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc); MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc);
} }
RARRAY(ary)->len = RARRAY(ary)->capa = argc; RARRAY(ary)->len = RARRAY(ary)->aux.capa = argc;
return ary; return ary;
} }
@ -270,13 +285,13 @@ rb_ary_store(ary, idx, val)
} }
} }
if (idx >= RARRAY(ary)->capa) { if (idx >= RARRAY(ary)->aux.capa) {
long capa_inc = RARRAY(ary)->capa / 2; long capa_inc = RARRAY(ary)->aux.capa / 2;
if (capa_inc < ARY_DEFAULT_SIZE) { if (capa_inc < ARY_DEFAULT_SIZE) {
capa_inc = ARY_DEFAULT_SIZE; capa_inc = ARY_DEFAULT_SIZE;
} }
RARRAY(ary)->capa = idx + capa_inc; RARRAY(ary)->aux.capa = idx + capa_inc;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
} }
if (idx > RARRAY(ary)->len) { if (idx > RARRAY(ary)->len) {
rb_mem_clear(RARRAY(ary)->ptr+RARRAY(ary)->len, rb_mem_clear(RARRAY(ary)->ptr+RARRAY(ary)->len,
@ -319,34 +334,45 @@ VALUE
rb_ary_pop(ary) rb_ary_pop(ary)
VALUE ary; VALUE ary;
{ {
rb_ary_modify(ary); rb_ary_modify_check(ary);
if (RARRAY(ary)->len == 0) return Qnil; if (RARRAY(ary)->len == 0) return Qnil;
if (RARRAY(ary)->len * 10 < RARRAY(ary)->capa && RARRAY(ary)->capa > ARY_DEFAULT_SIZE) { if (RARRAY(ary)->len * 10 < RARRAY(ary)->aux.capa && RARRAY(ary)->aux.capa > ARY_DEFAULT_SIZE) {
RARRAY(ary)->capa = RARRAY(ary)->len * 2; RARRAY(ary)->aux.capa = RARRAY(ary)->len * 2;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
} }
return RARRAY(ary)->ptr[--RARRAY(ary)->len]; return RARRAY(ary)->ptr[--RARRAY(ary)->len];
} }
static void
ary_make_shared(ary)
VALUE ary;
{
if (FL_TEST(ary, ELTS_SHARED)) return;
else {
NEWOBJ(shared, struct RArray);
OBJSETUP(shared, rb_cArray, T_ARRAY);
shared->len = RARRAY(ary)->len;
shared->ptr = RARRAY(ary)->ptr;
shared->aux.capa = RARRAY(ary)->aux.capa;
RARRAY(ary)->aux.shared = (VALUE)shared;
FL_SET(ary, ELTS_SHARED);
}
}
VALUE VALUE
rb_ary_shift(ary) rb_ary_shift(ary)
VALUE ary; VALUE ary;
{ {
VALUE top; VALUE top;
rb_ary_modify(ary); rb_ary_modify_check(ary);
if (RARRAY(ary)->len == 0) return Qnil; if (RARRAY(ary)->len == 0) return Qnil;
top = RARRAY(ary)->ptr[0]; top = RARRAY(ary)->ptr[0];
ary_make_shared(ary);
RARRAY(ary)->ptr++; /* shift ptr */
RARRAY(ary)->len--; RARRAY(ary)->len--;
/* sliding items */
MEMMOVE(RARRAY(ary)->ptr, RARRAY(ary)->ptr+1, VALUE, RARRAY(ary)->len);
if (RARRAY(ary)->len * 10 < RARRAY(ary)->capa && RARRAY(ary)->capa > ARY_DEFAULT_SIZE) {
RARRAY(ary)->capa = RARRAY(ary)->len * 2;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa);
}
return top; return top;
} }
@ -355,13 +381,13 @@ rb_ary_unshift(ary, item)
VALUE ary, item; VALUE ary, item;
{ {
rb_ary_modify(ary); rb_ary_modify(ary);
if (RARRAY(ary)->len >= RARRAY(ary)->capa) { if (RARRAY(ary)->len >= RARRAY(ary)->aux.capa) {
long capa_inc = RARRAY(ary)->capa / 2; long capa_inc = RARRAY(ary)->aux.capa / 2;
if (capa_inc < ARY_DEFAULT_SIZE) { if (capa_inc < ARY_DEFAULT_SIZE) {
capa_inc = ARY_DEFAULT_SIZE; capa_inc = ARY_DEFAULT_SIZE;
} }
RARRAY(ary)->capa+=capa_inc; RARRAY(ary)->aux.capa+=capa_inc;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
} }
/* sliding items */ /* sliding items */
@ -429,11 +455,14 @@ rb_ary_subseq(ary, beg, len)
len = 0; len = 0;
} }
klass = rb_obj_class(ary); klass = rb_obj_class(ary);
if (len == 0) return rb_ary_new0(klass,0); if (len == 0) return ary_new(klass,0);
ary2 = rb_ary_new0(klass, len); ary_make_shared(ary);
MEMCPY(RARRAY(ary2)->ptr, RARRAY(ary)->ptr+beg, VALUE, len); ary2 = rb_obj_alloc(klass);
RARRAY(ary2)->ptr = RARRAY(ary)->ptr+beg;
RARRAY(ary2)->len = len; RARRAY(ary2)->len = len;
RARRAY(ary2)->aux.shared = RARRAY(ary)->aux.shared;
FL_SET(ary2, ELTS_SHARED);
return ary2; return ary2;
} }
@ -609,9 +638,9 @@ rb_ary_update(ary, beg, len, rpl)
rb_ary_modify(ary); rb_ary_modify(ary);
if (beg >= RARRAY(ary)->len) { if (beg >= RARRAY(ary)->len) {
len = beg + rlen; len = beg + rlen;
if (len >= RARRAY(ary)->capa) { if (len >= RARRAY(ary)->aux.capa) {
RARRAY(ary)->capa=len; RARRAY(ary)->aux.capa=len;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
} }
rb_mem_clear(RARRAY(ary)->ptr+RARRAY(ary)->len, beg-RARRAY(ary)->len); rb_mem_clear(RARRAY(ary)->ptr+RARRAY(ary)->len, beg-RARRAY(ary)->len);
MEMCPY(RARRAY(ary)->ptr+beg, RARRAY(rpl)->ptr, VALUE, rlen); MEMCPY(RARRAY(ary)->ptr+beg, RARRAY(rpl)->ptr, VALUE, rlen);
@ -625,9 +654,9 @@ rb_ary_update(ary, beg, len, rpl)
} }
alen = RARRAY(ary)->len + rlen - len; alen = RARRAY(ary)->len + rlen - len;
if (alen >= RARRAY(ary)->capa) { if (alen >= RARRAY(ary)->aux.capa) {
RARRAY(ary)->capa = alen; RARRAY(ary)->aux.capa = alen;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
} }
if (len != rlen) { if (len != rlen) {
@ -748,33 +777,52 @@ rb_ary_empty_p(ary)
return Qfalse; return Qfalse;
} }
static VALUE
ary_copy(ary, clone)
VALUE ary;
int clone;
{
VALUE copy;
ary_make_shared(ary);
copy = rb_obj_alloc(rb_cArray);
if (clone) CLONESETUP(copy, ary);
else DUPSETUP(copy, ary);
RARRAY(copy)->ptr = RARRAY(ary)->ptr;
RARRAY(copy)->len = RARRAY(ary)->len;
RARRAY(copy)->aux.shared = RARRAY(ary)->aux.shared;
FL_SET(copy, ELTS_SHARED);
return copy;
}
static VALUE static VALUE
rb_ary_clone(ary) rb_ary_clone(ary)
VALUE ary; VALUE ary;
{ {
VALUE clone = rb_ary_new2(RARRAY(ary)->len); return ary_copy(ary, Qtrue);
CLONESETUP(clone, ary);
MEMCPY(RARRAY(clone)->ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
RARRAY(clone)->len = RARRAY(ary)->len;
return clone;
} }
VALUE VALUE
rb_ary_dup(ary) rb_ary_dup(ary)
VALUE ary; VALUE ary;
{
return ary_copy(ary, Qfalse);
}
static VALUE
ary_dup(ary)
VALUE ary;
{ {
VALUE dup = rb_ary_new2(RARRAY(ary)->len); VALUE dup = rb_ary_new2(RARRAY(ary)->len);
OBJSETUP(dup, rb_obj_class(ary), T_ARRAY); DUPSETUP(dup, ary);
MEMCPY(RARRAY(dup)->ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); MEMCPY(RARRAY(dup)->ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
RARRAY(dup)->len = RARRAY(ary)->len; RARRAY(dup)->len = RARRAY(ary)->len;
OBJ_INFECT(dup, ary);
return dup; return dup;
} }
extern VALUE rb_output_fs; extern VALUE rb_output_fs;
extern VALUE rb_default_rs;
static VALUE static VALUE
inspect_join(ary, arg) inspect_join(ary, arg)
@ -861,9 +909,6 @@ rb_ary_to_s(ary)
if (RARRAY(ary)->len == 0) return rb_str_new(0, 0); if (RARRAY(ary)->len == 0) return rb_str_new(0, 0);
sep = rb_output_fs; sep = rb_output_fs;
#if 1
if (NIL_P(rb_output_fs)) sep = rb_default_rs; /* newline */
#endif
str = rb_ary_join(ary, sep); str = rb_ary_join(ary, sep);
return str; return str;
} }
@ -1006,7 +1051,7 @@ static VALUE
rb_ary_reverse_m(ary) rb_ary_reverse_m(ary)
VALUE ary; VALUE ary;
{ {
return rb_ary_reverse(rb_ary_dup(ary)); return rb_ary_reverse(ary_dup(ary));
} }
int int
@ -1018,8 +1063,8 @@ rb_cmpint(cmp)
if (RBIGNUM(cmp)->sign) return 1; if (RBIGNUM(cmp)->sign) return 1;
return -1; return -1;
} }
if (rb_funcall(cmp, '>', 1, INT2FIX(0))) return 1; if (rb_funcall(id_cmp, '>', 1, INT2FIX(0))) return 1;
if (rb_funcall(cmp, '<', 1, INT2FIX(0))) return -1; if (rb_funcall(id_cmp, '<', 1, INT2FIX(0))) return -1;
return 0; return 0;
} }
@ -1044,7 +1089,7 @@ sort_2(a, b)
return rb_str_cmp(*a, *b); return rb_str_cmp(*a, *b);
} }
retval = rb_funcall(*a, cmp, 1, *b); retval = rb_funcall(*a, id_cmp, 1, *b);
return rb_cmpint(retval); return rb_cmpint(retval);
} }
@ -1081,31 +1126,11 @@ VALUE
rb_ary_sort(ary) rb_ary_sort(ary)
VALUE ary; VALUE ary;
{ {
ary = rb_ary_dup(ary); ary = ary_dup(ary);
rb_ary_sort_bang(ary); rb_ary_sort_bang(ary);
return ary; return ary;
} }
static VALUE
sort_inplace(ary)
VALUE ary;
{
qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE),sort_2);
return ary;
}
VALUE
rb_ary_sort_inplace(ary)
VALUE ary;
{
rb_ary_modify(ary);
if (RARRAY(ary)->len <= 1) return ary;
FL_SET(ary, ARY_TMPLOCK); /* prohibit modification during sort */
rb_ensure(sort_inplace, ary, sort_unlock, ary);
return ary;
}
static VALUE static VALUE
rb_ary_collect(ary) rb_ary_collect(ary)
VALUE ary; VALUE ary;
@ -1269,7 +1294,7 @@ static VALUE
rb_ary_reject(ary) rb_ary_reject(ary)
VALUE ary; VALUE ary;
{ {
ary = rb_ary_dup(ary); ary = ary_dup(ary);
rb_ary_reject_bang(ary); rb_ary_reject_bang(ary);
return ary; return ary;
} }
@ -1297,9 +1322,9 @@ rb_ary_clear(ary)
{ {
rb_ary_modify(ary); rb_ary_modify(ary);
RARRAY(ary)->len = 0; RARRAY(ary)->len = 0;
if (ARY_DEFAULT_SIZE*3 < RARRAY(ary)->capa) { if (ARY_DEFAULT_SIZE*3 < RARRAY(ary)->aux.capa) {
RARRAY(ary)->capa = ARY_DEFAULT_SIZE * 2; RARRAY(ary)->aux.capa = ARY_DEFAULT_SIZE * 2;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
} }
return ary; return ary;
} }
@ -1337,9 +1362,9 @@ rb_ary_fill(argc, argv, ary)
rb_ary_modify(ary); rb_ary_modify(ary);
end = beg + len; end = beg + len;
if (end > RARRAY(ary)->len) { if (end > RARRAY(ary)->len) {
if (end >= RARRAY(ary)->capa) { if (end >= RARRAY(ary)->aux.capa) {
RARRAY(ary)->capa = end; RARRAY(ary)->aux.capa = end;
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->capa); REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
} }
if (beg > RARRAY(ary)->len) { if (beg > RARRAY(ary)->len) {
rb_mem_clear(RARRAY(ary)->ptr+RARRAY(ary)->len,end-RARRAY(ary)->len); rb_mem_clear(RARRAY(ary)->ptr+RARRAY(ary)->len,end-RARRAY(ary)->len);
@ -1397,7 +1422,7 @@ rb_ary_times(ary, times)
} }
len *= RARRAY(ary)->len; len *= RARRAY(ary)->len;
ary2 = rb_ary_new0(rb_obj_class(ary), len); ary2 = ary_new(rb_obj_class(ary), len);
RARRAY(ary2)->len = len; RARRAY(ary2)->len = len;
for (i=0; i<len; i+=RARRAY(ary)->len) { for (i=0; i<len; i+=RARRAY(ary)->len) {
@ -1521,7 +1546,7 @@ rb_ary_cmp(ary, ary2)
len = RARRAY(ary2)->len; len = RARRAY(ary2)->len;
} }
for (i=0; i<len; i++) { for (i=0; i<len; i++) {
VALUE v = rb_funcall(RARRAY(ary)->ptr[i],cmp,1,RARRAY(ary2)->ptr[i]); VALUE v = rb_funcall(RARRAY(ary)->ptr[i],id_cmp,1,RARRAY(ary2)->ptr[i]);
if (v != INT2FIX(0)) { if (v != INT2FIX(0)) {
return v; return v;
} }
@ -1646,7 +1671,7 @@ static VALUE
rb_ary_uniq(ary) rb_ary_uniq(ary)
VALUE ary; VALUE ary;
{ {
ary = rb_ary_dup(ary); ary = ary_dup(ary);
rb_ary_uniq_bang(ary); rb_ary_uniq_bang(ary);
return ary; return ary;
} }
@ -1667,7 +1692,7 @@ rb_ary_compact_bang(ary)
if (RARRAY(ary)->len == (p - RARRAY(ary)->ptr)) { if (RARRAY(ary)->len == (p - RARRAY(ary)->ptr)) {
return Qnil; return Qnil;
} }
RARRAY(ary)->len = RARRAY(ary)->capa = (p - RARRAY(ary)->ptr); RARRAY(ary)->len = RARRAY(ary)->aux.capa = (p - RARRAY(ary)->ptr);
REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len); REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
return ary; return ary;
@ -1677,7 +1702,7 @@ static VALUE
rb_ary_compact(ary) rb_ary_compact(ary)
VALUE ary; VALUE ary;
{ {
ary = rb_ary_dup(ary); ary = ary_dup(ary);
rb_ary_compact_bang(ary); rb_ary_compact_bang(ary);
return ary; return ary;
} }
@ -1755,7 +1780,7 @@ static VALUE
rb_ary_flatten(ary) rb_ary_flatten(ary)
VALUE ary; VALUE ary;
{ {
ary = rb_ary_dup(ary); ary = ary_dup(ary);
rb_ary_flatten_bang(ary); rb_ary_flatten_bang(ary);
return ary; return ary;
} }
@ -1847,5 +1872,5 @@ Init_Array()
rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, 0); rb_define_method(rb_cArray, "flatten!", rb_ary_flatten_bang, 0);
rb_define_method(rb_cArray, "nitems", rb_ary_nitems, 0); rb_define_method(rb_cArray, "nitems", rb_ary_nitems, 0);
cmp = rb_intern("<=>"); id_cmp = rb_intern("<=>");
} }

View file

@ -87,7 +87,8 @@ rb_mod_dup(mod)
VALUE mod; VALUE mod;
{ {
VALUE dup = rb_mod_clone(mod); VALUE dup = rb_mod_clone(mod);
OBJSETUP(dup, RBASIC(mod)->klass, BUILTIN_TYPE(mod));
DUPSETUP(dup, mod);
if (FL_TEST(mod, FL_SINGLETON)) { if (FL_TEST(mod, FL_SINGLETON)) {
FL_SET(dup, FL_SINGLETON); FL_SET(dup, FL_SINGLETON);
} }

47
enum.c
View file

@ -12,6 +12,7 @@
#include "ruby.h" #include "ruby.h"
#include "node.h" #include "node.h"
#include "util.h"
VALUE rb_mEnumerable; VALUE rb_mEnumerable;
static ID id_each, id_eqq, id_cmp; static ID id_each, id_eqq, id_cmp;
@ -204,53 +205,41 @@ enum_sort(obj)
} }
static VALUE static VALUE
sort_by_i(i, memo) sort_by_i(i, ary)
VALUE i; VALUE i, ary;
NODE *memo;
{ {
VALUE v, e; VALUE v, e;
v = rb_yield(i); v = rb_yield(i);
if (TYPE(v) == T_ARRAY) { e = rb_assoc_new(v, i);
int j, len = RARRAY(v)->len; rb_ary_push(ary, e);
e = rb_ary_new2(len+2);
for (j=0; j<len; j++) {
RARRAY(e)->ptr[j] = RARRAY(v)->ptr[j];
}
RARRAY(e)->ptr[j++] = INT2NUM(memo->u3.cnt);
RARRAY(e)->ptr[j] = i;
RARRAY(e)->len = len + 2;
}
else {
e = rb_ary_new3(3, v, INT2NUM(memo->u3.cnt), i);
}
rb_ary_push(memo->u1.value, e);
memo->u3.cnt++;
return Qnil; return Qnil;
} }
static VALUE static int
sort_by_sort_body(a) sort_by_cmp(a, b)
VALUE a; VALUE *a, *b;
{ {
return rb_ary_cmp(RARRAY(a)->ptr[0], RARRAY(a)->ptr[1]); VALUE retval;
retval = rb_funcall(RARRAY(*a)->ptr[0], id_cmp, 1, RARRAY(*b)->ptr[0]);
return rb_cmpint(retval);
} }
static VALUE static VALUE
enum_sort_by(obj) enum_sort_by(obj)
VALUE obj; VALUE obj;
{ {
VALUE ary = rb_ary_new2(2000); VALUE ary;
NODE *memo = rb_node_newnode(NODE_MEMO, ary, 0, 0);
long i; long i;
rb_iterate(rb_each, obj, sort_by_i, (VALUE)memo); ary = rb_ary_new2((TYPE(obj) == T_ARRAY) ? RARRAY(obj)->len : 2000);
rb_gc_force_recycle((VALUE)memo); rb_iterate(rb_each, obj, sort_by_i, ary);
rb_ary_sort_inplace(ary); if (RARRAY(ary)->len <= 1) return ary;
qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE), sort_by_cmp);
for (i=0; i<RARRAY(ary)->len; i++) { for (i=0; i<RARRAY(ary)->len; i++) {
VALUE e = RARRAY(ary)->ptr[i]; VALUE e = RARRAY(ary)->ptr[i];
RARRAY(ary)->ptr[i] = RARRAY(e)->ptr[RARRAY(e)->len - 1]; RARRAY(ary)->ptr[i] = RARRAY(e)->ptr[1];
} }
return ary; return ary;

View file

@ -718,6 +718,10 @@ rb_sys_fail(mesg)
int n = errno; int n = errno;
VALUE ee; VALUE ee;
if (errno == 0) {
rb_bug("rb_sys_fail() - errno == 0");
}
err = strerror(errno); err = strerror(errno);
if (mesg) { if (mesg) {
volatile VALUE tmp = rb_str_inspect(rb_str_new2(mesg)); volatile VALUE tmp = rb_str_inspect(rb_str_new2(mesg));

View file

@ -460,18 +460,20 @@ static VALUE
curses_curs_set(VALUE obj, VALUE visibility) curses_curs_set(VALUE obj, VALUE visibility)
{ {
int n; int n;
return (n = curs_set(FIX2INT(visibility)) != ERR) ? INT2FIX(n) : Qnil; return (n = curs_set(NUM2INT(visibility)) != ERR) ? INT2FIX(n) : Qnil;
} }
static VALUE static VALUE
curses_scrl(VALUE obj, VALUE n) curses_scrl(VALUE obj, VALUE n)
{ {
/* may have to raise exception on ERR */
return (scrl(NUM2INT(n)) == OK) ? Qtrue : Qfalse; return (scrl(NUM2INT(n)) == OK) ? Qtrue : Qfalse;
} }
static VALUE static VALUE
curses_setscrreg(VALUE obj, VALUE top, VALUE bottom) curses_setscrreg(VALUE obj, VALUE top, VALUE bottom)
{ {
/* may have to raise exception on ERR */
return (setscrreg(NUM2INT(top), NUM2INT(bottom)) == OK) ? Qtrue : Qfalse; return (setscrreg(NUM2INT(top), NUM2INT(bottom)) == OK) ? Qtrue : Qfalse;
} }
@ -479,21 +481,21 @@ static VALUE
curses_attroff(VALUE obj, VALUE attrs) curses_attroff(VALUE obj, VALUE attrs)
{ {
return window_attroff(rb_stdscr,attrs); return window_attroff(rb_stdscr,attrs);
/* return INT2FIX(attroff(FIX2INT(attrs))); */ /* return INT2FIX(attroff(NUM2INT(attrs))); */
} }
static VALUE static VALUE
curses_attron(VALUE obj, VALUE attrs) curses_attron(VALUE obj, VALUE attrs)
{ {
return window_attron(rb_stdscr,attrs); return window_attron(rb_stdscr,attrs);
/* return INT2FIX(attroff(FIX2INT(attrs))); */ /* return INT2FIX(attroff(NUM2INT(attrs))); */
} }
static VALUE static VALUE
curses_attrset(VALUE obj, VALUE attrs) curses_attrset(VALUE obj, VALUE attrs)
{ {
return window_attrset(rb_stdscr,attrs); return window_attrset(rb_stdscr,attrs);
/* return INT2FIX(attroff(FIX2INT(attrs))); */ /* return INT2FIX(attroff(NUM2INT(attrs))); */
} }
static VALUE static VALUE
@ -513,20 +515,23 @@ curses_bkgd(VALUE obj, VALUE ch)
static VALUE static VALUE
curses_start_color(VALUE obj) curses_start_color(VALUE obj)
{ {
/* may have to raise exception on ERR */
return (start_color() == OK) ? Qtrue : Qfalse; return (start_color() == OK) ? Qtrue : Qfalse;
} }
static VALUE static VALUE
curses_init_pair(VALUE obj, VALUE pair, VALUE f, VALUE b) curses_init_pair(VALUE obj, VALUE pair, VALUE f, VALUE b)
{ {
return (init_pair(FIX2INT(pair),FIX2INT(f),FIX2INT(b)) == OK) ? Qtrue : Qfalse; /* may have to raise exception on ERR */
return (init_pair(NUM2INT(pair),NUM2INT(f),NUM2INT(b)) == OK) ? Qtrue : Qfalse;
} }
static VALUE static VALUE
curses_init_color(VALUE obj, VALUE color, VALUE r, VALUE g, VALUE b) curses_init_color(VALUE obj, VALUE color, VALUE r, VALUE g, VALUE b)
{ {
return (init_color(FIX2INT(color),FIX2INT(r), /* may have to raise exception on ERR */
FIX2INT(g),FIX2INT(b)) == OK) ? Qtrue : Qfalse; return (init_color(NUM2INT(color),NUM2INT(r),
NUM2INT(g),NUM2INT(b)) == OK) ? Qtrue : Qfalse;
} }
static VALUE static VALUE
@ -546,7 +551,7 @@ curses_color_content(VALUE obj, VALUE color)
{ {
short r,g,b; short r,g,b;
color_content(FIX2INT(color),&r,&g,&b); color_content(NUM2INT(color),&r,&g,&b);
return rb_ary_new3(3,INT2FIX(r),INT2FIX(g),INT2FIX(b)); return rb_ary_new3(3,INT2FIX(r),INT2FIX(g),INT2FIX(b));
} }
@ -555,20 +560,20 @@ curses_pair_content(VALUE obj, VALUE pair)
{ {
short f,b; short f,b;
pair_content(FIX2INT(pair),&f,&b); pair_content(NUM2INT(pair),&f,&b);
return rb_ary_new3(2,INT2FIX(f),INT2FIX(b)); return rb_ary_new3(2,INT2FIX(f),INT2FIX(b));
} }
static VALUE static VALUE
curses_color_pair(VALUE obj, VALUE attrs) curses_color_pair(VALUE obj, VALUE attrs)
{ {
return INT2FIX(COLOR_PAIR(FIX2INT(attrs))); return INT2FIX(COLOR_PAIR(NUM2INT(attrs)));
} }
static VALUE static VALUE
curses_pair_number(VALUE obj, VALUE attrs) curses_pair_number(VALUE obj, VALUE attrs)
{ {
return INT2FIX(PAIR_NUMBER(FIX2INT(attrs))); return INT2FIX(PAIR_NUMBER(NUM2INT(attrs)));
} }
#endif #endif
@ -591,7 +596,7 @@ no_mevent()
static void static void
curses_mousedata_free(struct mousedata *mdata) curses_mousedata_free(struct mousedata *mdata)
{ {
if( mdata->mevent ) if (mdata->mevent)
free(mdata->mevent); free(mdata->mevent);
}; };
@ -604,7 +609,7 @@ curses_getmouse(VALUE obj)
val = Data_Make_Struct(cMouseEvent,struct mousedata, val = Data_Make_Struct(cMouseEvent,struct mousedata,
0,curses_mousedata_free,mdata); 0,curses_mousedata_free,mdata);
mdata->mevent = (MEVENT*)malloc(sizeof(MEVENT)); mdata->mevent = (MEVENT*)malloc(sizeof(MEVENT));
return ( getmouse(mdata->mevent) == OK ) ? val : Qnil; return (getmouse(mdata->mevent) == OK) ? val : Qnil;
}; };
static VALUE static VALUE
@ -898,8 +903,8 @@ window_box(argc, argv, self)
c = NUM2CHR(corn); c = NUM2CHR(corn);
getyx(winp->window, cur_y, cur_x); getyx(winp->window, cur_y, cur_x);
x = FIX2INT(window_maxx(self)) - 1; x = NUM2INT(window_maxx(self)) - 1;
y = FIX2INT(window_maxy(self)) - 1; y = NUM2INT(window_maxy(self)) - 1;
wmove(winp->window, 0, 0); wmove(winp->window, 0, 0);
waddch(winp->window, c); waddch(winp->window, c);
wmove(winp->window, y, 0); wmove(winp->window, y, 0);
@ -1062,11 +1067,10 @@ static VALUE
window_scrollok(VALUE obj, VALUE bf) window_scrollok(VALUE obj, VALUE bf)
{ {
struct windata *winp; struct windata *winp;
int res;
GetWINDOW(obj, winp); GetWINDOW(obj, winp);
res = scrollok(winp->window, (bf == Qtrue) ? TRUE : FALSE); scrollok(winp->window, RTEST(bf) ? TRUE : FALSE);
return (res == OK) ? Qtrue : Qfalse; return Qnil;
} }
static VALUE static VALUE
@ -1076,8 +1080,8 @@ window_idlok(VALUE obj, VALUE bf)
int res; int res;
GetWINDOW(obj, winp); GetWINDOW(obj, winp);
res = idlok(winp->window, (bf == Qtrue) ? TRUE : FALSE); idlok(winp->window, RTEST(bf) ? TRUE : FALSE);
return (res == OK) ? Qtrue : Qfalse; return Qnil;
} }
static VALUE static VALUE
@ -1088,6 +1092,7 @@ window_setscrreg(VALUE obj, VALUE top, VALUE bottom)
GetWINDOW(obj, winp); GetWINDOW(obj, winp);
res = wsetscrreg(winp->window, NUM2INT(top), NUM2INT(bottom)); res = wsetscrreg(winp->window, NUM2INT(top), NUM2INT(bottom));
/* may have to raise exception on ERR */
return (res == OK) ? Qtrue : Qfalse; return (res == OK) ? Qtrue : Qfalse;
}; };
@ -1097,6 +1102,7 @@ window_scroll(VALUE obj)
struct windata *winp; struct windata *winp;
GetWINDOW(obj, winp); GetWINDOW(obj, winp);
/* may have to raise exception on ERR */
return (scroll(winp->window) == OK) ? Qtrue : Qfalse; return (scroll(winp->window) == OK) ? Qtrue : Qfalse;
} }
@ -1106,6 +1112,7 @@ window_scrl(VALUE obj, VALUE n)
struct windata *winp; struct windata *winp;
GetWINDOW(obj, winp); GetWINDOW(obj, winp);
/* may have to raise exception on ERR */
return (wscrl(winp->window,NUM2INT(n)) == OK) ? Qtrue : Qfalse; return (wscrl(winp->window,NUM2INT(n)) == OK) ? Qtrue : Qfalse;
} }
@ -1115,7 +1122,7 @@ window_attroff(VALUE obj, VALUE attrs)
struct windata *winp; struct windata *winp;
GetWINDOW(obj,winp); GetWINDOW(obj,winp);
return INT2FIX(wattroff(winp->window,FIX2INT(attrs))); return INT2FIX(wattroff(winp->window,NUM2INT(attrs)));
}; };
static VALUE static VALUE
@ -1125,10 +1132,10 @@ window_attron(VALUE obj, VALUE attrs)
VALUE val; VALUE val;
GetWINDOW(obj,winp); GetWINDOW(obj,winp);
val = INT2FIX(wattron(winp->window,FIX2INT(attrs))); val = INT2FIX(wattron(winp->window,NUM2INT(attrs)));
if( rb_block_given_p() ){ if( rb_block_given_p() ){
rb_yield(val); rb_yield(val);
wattroff(winp->window,FIX2INT(attrs)); wattroff(winp->window,NUM2INT(attrs));
return val; return val;
} }
else{ else{
@ -1142,7 +1149,7 @@ window_attrset(VALUE obj, VALUE attrs)
struct windata *winp; struct windata *winp;
GetWINDOW(obj,winp); GetWINDOW(obj,winp);
return INT2FIX(wattrset(winp->window,FIX2INT(attrs))); return INT2FIX(wattrset(winp->window,NUM2INT(attrs)));
} }
static VALUE static VALUE
@ -1182,10 +1189,11 @@ window_keypad(VALUE obj, VALUE val)
GetWINDOW(obj,winp); GetWINDOW(obj,winp);
/* keypad() of NetBSD's libcurses returns no value */ /* keypad() of NetBSD's libcurses returns no value */
#if defined(__NetBSD__) && !defined(NCURSES_VERSION) #if defined(__NetBSD__) && !defined(NCURSES_VERSION)
keypad(winp->window,(val == Qtrue ? TRUE : FALSE)); keypad(winp->window,(RTEST(val) ? TRUE : FALSE));
return Qnil; return Qnil;
#else #else
return (keypad(winp->window,(val == Qtrue) ? TRUE : FALSE)) == OK ? /* may have to raise exception on ERR */
return (keypad(winp->window,RTEST(val) ? TRUE : FALSE)) == OK ?
Qtrue : Qfalse; Qtrue : Qfalse;
#endif #endif
}; };

12
gc.c
View file

@ -756,6 +756,8 @@ rb_gc_mark_children(ptr)
for (i=0; i < len; i++) for (i=0; i < len; i++)
rb_gc_mark(*ptr++); rb_gc_mark(*ptr++);
} }
if (FL_TEST(obj, ELTS_SHARED))
rb_gc_mark(obj->as.array.aux.shared);
break; break;
case T_HASH: case T_HASH:
@ -764,8 +766,9 @@ rb_gc_mark_children(ptr)
break; break;
case T_STRING: case T_STRING:
if (obj->as.string.orig) { #define STR_ASSOC FL_USER2 /* copied from string.c */
rb_gc_mark((VALUE)obj->as.string.orig); if (FL_TEST(obj, ELTS_SHARED|STR_ASSOC)) {
rb_gc_mark(obj->as.string.aux.shared);
} }
break; break;
@ -945,13 +948,12 @@ obj_free(obj)
} }
break; break;
case T_STRING: case T_STRING:
#define STR_NO_ORIG FL_USER2 /* copied from string.c */ if (RANY(obj)->as.string.ptr && !FL_TEST(obj, ELTS_SHARED)) {
if (!RANY(obj)->as.string.orig || FL_TEST(obj, STR_NO_ORIG)) {
RUBY_CRITICAL(free(RANY(obj)->as.string.ptr)); RUBY_CRITICAL(free(RANY(obj)->as.string.ptr));
} }
break; break;
case T_ARRAY: case T_ARRAY:
if (RANY(obj)->as.array.ptr) { if (RANY(obj)->as.array.ptr && !FL_TEST(obj, ELTS_SHARED)) {
RUBY_CRITICAL(free(RANY(obj)->as.array.ptr)); RUBY_CRITICAL(free(RANY(obj)->as.array.ptr));
} }
break; break;

39
hash.c
View file

@ -18,6 +18,7 @@
#include "rubysig.h" #include "rubysig.h"
#define HASH_DELETED FL_USER1 #define HASH_DELETED FL_USER1
#define HASH_PROC_DEFAULT FL_USER2
static void static void
rb_hash_modify(hash) rb_hash_modify(hash)
@ -38,13 +39,13 @@ rb_hash_freeze(hash)
VALUE rb_cHash; VALUE rb_cHash;
static VALUE envtbl; static VALUE envtbl;
static ID hash; static ID id_hash, id_yield, id_default;
VALUE VALUE
rb_hash(obj) rb_hash(obj)
VALUE obj; VALUE obj;
{ {
return rb_funcall(obj, hash, 0); return rb_funcall(obj, id_hash, 0);
} }
static VALUE static VALUE
@ -93,7 +94,7 @@ rb_any_hash(a)
default: default:
DEFER_INTS; DEFER_INTS;
hval = rb_funcall(a, hash, 0); hval = rb_funcall(a, id_hash, 0);
if (FIXNUM_P(hval)) { if (FIXNUM_P(hval)) {
hval %= 536870917; hval %= 536870917;
} }
@ -198,9 +199,18 @@ rb_hash_initialize(argc, argv, hash)
{ {
VALUE ifnone; VALUE ifnone;
rb_scan_args(argc, argv, "01", &ifnone);
rb_hash_modify(hash); rb_hash_modify(hash);
if (rb_block_given_p()) {
if (argc > 1) {
rb_raise(rb_eArgError, "wrong number of arguments", argc);
}
RHASH(hash)->ifnone = rb_f_lambda();
FL_SET(hash, HASH_PROC_DEFAULT);
}
else {
rb_scan_args(argc, argv, "01", &ifnone);
RHASH(hash)->ifnone = ifnone; RHASH(hash)->ifnone = ifnone;
}
return hash; return hash;
} }
@ -284,7 +294,7 @@ rb_hash_aref(hash, key)
VALUE val; VALUE val;
if (!st_lookup(RHASH(hash)->tbl, key, &val)) { if (!st_lookup(RHASH(hash)->tbl, key, &val)) {
return RHASH(hash)->ifnone; return rb_funcall(hash, id_default, 1, key);
} }
return val; return val;
} }
@ -316,9 +326,17 @@ rb_hash_fetch(argc, argv, hash)
} }
static VALUE static VALUE
rb_hash_default(hash) rb_hash_default(argc, argv, hash)
int argc;
VALUE *argv;
VALUE hash; VALUE hash;
{ {
VALUE key;
rb_scan_args(argc, argv, "01", &key);
if (FL_TEST(hash, HASH_PROC_DEFAULT)) {
return rb_funcall(RHASH(hash)->ifnone, id_yield, 2, hash, key);
}
return RHASH(hash)->ifnone; return RHASH(hash)->ifnone;
} }
@ -328,6 +346,7 @@ rb_hash_set_default(hash, ifnone)
{ {
rb_hash_modify(hash); rb_hash_modify(hash);
RHASH(hash)->ifnone = ifnone; RHASH(hash)->ifnone = ifnone;
FL_UNSET(hash, HASH_PROC_DEFAULT);
return hash; return hash;
} }
@ -392,7 +411,7 @@ rb_hash_delete(hash, key)
if (rb_block_given_p()) { if (rb_block_given_p()) {
return rb_yield(key); return rb_yield(key);
} }
return RHASH(hash)->ifnone; return Qnil;
} }
struct shift_var { struct shift_var {
@ -1433,7 +1452,9 @@ env_reject()
void void
Init_Hash() Init_Hash()
{ {
hash = rb_intern("hash"); id_hash = rb_intern("hash");
id_yield = rb_intern("yield");
id_default = rb_intern("default");
rb_cHash = rb_define_class("Hash", rb_cObject); rb_cHash = rb_define_class("Hash", rb_cObject);
@ -1456,7 +1477,7 @@ Init_Hash()
rb_define_method(rb_cHash,"fetch", rb_hash_fetch, -1); rb_define_method(rb_cHash,"fetch", rb_hash_fetch, -1);
rb_define_method(rb_cHash,"[]=", rb_hash_aset, 2); rb_define_method(rb_cHash,"[]=", rb_hash_aset, 2);
rb_define_method(rb_cHash,"store", rb_hash_aset, 2); rb_define_method(rb_cHash,"store", rb_hash_aset, 2);
rb_define_method(rb_cHash,"default", rb_hash_default, 0); rb_define_method(rb_cHash,"default", rb_hash_default, -1);
rb_define_method(rb_cHash,"default=", rb_hash_set_default, 1); rb_define_method(rb_cHash,"default=", rb_hash_set_default, 1);
rb_define_method(rb_cHash,"index", rb_hash_index, 1); rb_define_method(rb_cHash,"index", rb_hash_index, 1);
rb_define_method(rb_cHash,"indexes", rb_hash_indexes, -1); rb_define_method(rb_cHash,"indexes", rb_hash_indexes, -1);

31
io.c
View file

@ -513,6 +513,10 @@ io_fread(ptr, len, f)
eof: eof:
if (ferror(f)) { if (ferror(f)) {
if (errno == EINTR) continue; if (errno == EINTR) continue;
if (errno == EAGAIN) return len - n;
#if defined(EWOULDBLOCK) && EWOULDBLOCK != EAGAIN
if (errno == EWOULDBLOCK) return len - n;
#endif
rb_sys_fail(0); rb_sys_fail(0);
} }
*ptr = '\0'; *ptr = '\0';
@ -2187,6 +2191,25 @@ rb_f_putc(recv, ch)
return rb_io_putc(rb_defout, ch); return rb_io_putc(rb_defout, ch);
} }
static VALUE rb_io_puts _((int, VALUE*, VALUE));
static VALUE
io_puts_ary(ary, out)
VALUE ary, out;
{
VALUE tmp;
int i;
for (i=0; i<RARRAY(ary)->len; i++) {
tmp = RARRAY(ary)->ptr[i];
if (rb_inspecting_p(tmp)) {
tmp = rb_str_new2("[...]");
}
rb_io_puts(1, &tmp, out);
}
return Qnil;
}
static VALUE static VALUE
rb_io_puts(argc, argv, out) rb_io_puts(argc, argv, out)
int argc; int argc;
@ -2206,11 +2229,11 @@ rb_io_puts(argc, argv, out)
line = rb_str_new2("nil"); line = rb_str_new2("nil");
} }
else { else {
#if 0 line = rb_check_convert_type(argv[i], T_ARRAY, "Array", "to_ary");
if (TYPE(argv[i]) == T_ARRAY) { if (!NIL_P(line)) {
rb_warn("puts behavior changed for Array"); rb_protect_inspect(io_puts_ary, line, out);
continue;
} }
#endif
line = rb_obj_as_string(argv[i]); line = rb_obj_as_string(argv[i]);
} }
rb_io_write(out, line); rb_io_write(out, line);

View file

@ -313,7 +313,6 @@ rb_obj_freeze(obj)
if (rb_safe_level() >= 4 && !OBJ_TAINTED(obj)) { if (rb_safe_level() >= 4 && !OBJ_TAINTED(obj)) {
rb_raise(rb_eSecurityError, "Insecure: can't freeze object"); rb_raise(rb_eSecurityError, "Insecure: can't freeze object");
} }
OBJ_FREEZE(obj); OBJ_FREEZE(obj);
} }
return obj; return obj;
@ -1292,7 +1291,7 @@ Init_Object()
rb_undef_method(rb_cClass, "append_features"); rb_undef_method(rb_cClass, "append_features");
rb_cData = rb_define_class("Data", rb_cObject); rb_cData = rb_define_class("Data", rb_cObject);
rb_undef_method(CLASS_OF(rb_cData), "new"); rb_undef_method(CLASS_OF(rb_cData), "allocate");
ruby_top_self = rb_obj_alloc(rb_cObject); ruby_top_self = rb_obj_alloc(rb_cObject);
rb_global_variable(&ruby_top_self); rb_global_variable(&ruby_top_self);

18
parse.y
View file

@ -3938,6 +3938,10 @@ str_extend(list, term, paren)
case '-': case '-':
tokadd(c); tokadd(c);
c = nextc(); c = nextc();
if (!is_identchar(c)) {
pushback();
goto invalid_interporate;
}
tokadd(c); tokadd(c);
goto fetch_id; goto fetch_id;
@ -3956,11 +3960,16 @@ str_extend(list, term, paren)
goto refetch; goto refetch;
} }
if (!is_identchar(c)) { if (!is_identchar(c)) {
yyerror("bad global variable in string"); invalid_interporate:
{
VALUE s = rb_str_new2("#");
rb_str_cat(s, tok(), toklen());
list_append(list, NEW_STR(s));
newtok(); newtok();
return list; return list;
} }
} }
}
while (is_identchar(c)) { while (is_identchar(c)) {
tokadd(c); tokadd(c);
@ -3997,6 +4006,9 @@ str_extend(list, term, paren)
c = nextc(); c = nextc();
} }
pushback(c); pushback(c);
if (toklen() == 1) {
goto invalid_interporate;
}
break; break;
case '{': case '{':
@ -4264,7 +4276,9 @@ gettable(id)
return NEW_FALSE(); return NEW_FALSE();
} }
else if (id == k__FILE__) { else if (id == k__FILE__) {
return NEW_STR(rb_str_new2(ruby_sourcefile)); VALUE f = rb_str_new2(ruby_sourcefile);
OBJ_FREEZE(f);
return NEW_STR(f);
} }
else if (id == k__LINE__) { else if (id == k__LINE__) {
return NEW_LIT(INT2FIX(ruby_sourceline)); return NEW_LIT(INT2FIX(ruby_sourceline));

View file

@ -477,7 +477,7 @@ re_set_syntax(syntax)
} while(0) } while(0)
#define WC2MBC1ST(c) \ #define WC2MBC1ST(c) \
((c<0x100)?(c):((current_mbctype != MBCTYPE_UTF8)?(((c)>>8)&0xff):utf8_firstbyte(c))) ((current_mbctype != MBCTYPE_UTF8) ? ((c<0x100) ? (c) : (((c)>>8)&0xff)) : utf8_firstbyte(c))
static unsigned int static unsigned int
utf8_firstbyte(c) utf8_firstbyte(c)

17
ruby.h
View file

@ -247,6 +247,10 @@ VALUE rb_newobj _((void));
rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);\ rb_singleton_class_attached(RBASIC(clone)->klass, (VALUE)clone);\
if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)clone,(VALUE)obj);\ if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)clone,(VALUE)obj);\
} while (0) } while (0)
#define DUPSETUP(dup,obj) do {\
OBJSETUP(dup,rb_obj_class(obj),(RBASIC(obj)->flags)&(T_MASK|FL_EXIVAR|FL_TAINT));\
if (FL_TEST(obj, FL_EXIVAR)) rb_copy_generic_ivar((VALUE)dup,(VALUE)obj);\
} while (0)
struct RBasic { struct RBasic {
unsigned long flags; unsigned long flags;
@ -270,16 +274,25 @@ struct RFloat {
double value; double value;
}; };
#define ELTS_SHARED FL_USER2
struct RString { struct RString {
struct RBasic basic; struct RBasic basic;
long len; long len;
char *ptr; char *ptr;
VALUE orig; union {
int capa;
VALUE shared;
} aux;
}; };
struct RArray { struct RArray {
struct RBasic basic; struct RBasic basic;
long len, capa; long len;
union {
int capa;
VALUE shared;
} aux;
VALUE *ptr; VALUE *ptr;
}; };

View file

@ -470,6 +470,18 @@ test_ok(($x * 0).join(":") == '')
test_ok($x.size == 7) test_ok($x.size == 7)
test_ok($x == [1, 2, 3, 4, 5, 6, 7]) test_ok($x == [1, 2, 3, 4, 5, 6, 7])
$x = [1,2,3]
$x[1,0] = $x
test_ok($x == [1,1,2,3,2,3])
$x = [1,2,3]
$x[-1,0] = $x
test_ok($x == [1,2,1,2,3,3])
$x = [1,2,3]
$x.concat($x)
test_ok($x == [1,2,3,1,2,3])
test_check "hash" test_check "hash"
$x = {1=>2, 2=>4, 3=>6} $x = {1=>2, 2=>4, 3=>6}
$y = {1, 2, 2, 4, 3, 6} $y = {1, 2, 2, 4, 3, 6}
@ -505,17 +517,40 @@ $z = [1,2]
$y[$z] = 256 $y[$z] = 256
test_ok($y[$z] == 256) test_ok($y[$z] == 256)
$x = [1,2,3] $x = Hash.new(0)
$x[1,0] = $x $x[1] = 1
test_ok($x == [1,1,2,3,2,3]) test_ok($x[1] == 1)
test_ok($x[2] == 0)
$x = [1,2,3] $x = Hash.new([])
$x[-1,0] = $x test_ok($x[22] == [])
test_ok($x == [1,2,1,2,3,3]) test_ok($x[22].equal?($x[22]))
$x = [1,2,3] $x = Hash.new{[]}
$x.concat($x) test_ok($x[22] == [])
test_ok($x == [1,2,3,1,2,3]) test_ok(!$x[22].equal?($x[22]))
$x = Hash.new{|h,k| $z = k; h[k] = k*2}
$z = 0
test_ok($x[22] == 44)
test_ok($z == 22)
$z = 0
test_ok($x[22] == 44)
test_ok($z == 0)
$x.default = 5
test_ok($x[23] == 5)
$x = Hash.new
def $x.default(k)
$z = k
self[k] = k*2
end
$z = 0
test_ok($x[22] == 44)
test_ok($z == 22)
$z = 0
test_ok($x[22] == 44)
test_ok($z == 0)
test_check "iterator" test_check "iterator"

221
string.c
View file

@ -27,7 +27,6 @@
VALUE rb_cString; VALUE rb_cString;
#define STR_NO_ORIG FL_USER2
#define STR_ASSOC FL_USER3 #define STR_ASSOC FL_USER3
VALUE rb_fs; VALUE rb_fs;
@ -41,13 +40,13 @@ rb_str_s_alloc(klass)
str->ptr = 0; str->ptr = 0;
str->len = 0; str->len = 0;
str->orig = 0; str->aux.capa = 0;
return (VALUE)str; return (VALUE)str;
} }
VALUE static VALUE
rb_str_new0(klass, ptr, len) str_new(klass, ptr, len)
VALUE klass; VALUE klass;
const char *ptr; const char *ptr;
long len; long len;
@ -55,6 +54,7 @@ rb_str_new0(klass, ptr, len)
VALUE str = rb_obj_alloc(klass); VALUE str = rb_obj_alloc(klass);
RSTRING(str)->len = len; RSTRING(str)->len = len;
RSTRING(str)->aux.capa = len;
RSTRING(str)->ptr = ALLOC_N(char,len+1); RSTRING(str)->ptr = ALLOC_N(char,len+1);
if (ptr) { if (ptr) {
memcpy(RSTRING(str)->ptr, ptr, len); memcpy(RSTRING(str)->ptr, ptr, len);
@ -68,7 +68,7 @@ rb_str_new(ptr, len)
const char *ptr; const char *ptr;
long len; long len;
{ {
return rb_str_new0(rb_cString, ptr, len); return str_new(rb_cString, ptr, len);
} }
VALUE VALUE
@ -99,51 +99,52 @@ rb_tainted_str_new2(ptr)
return str; return str;
} }
VALUE static VALUE
rb_str_new3(str) str_new3(klass, str)
VALUE str; VALUE klass, str;
{ {
VALUE str2 = rb_obj_alloc(rb_obj_class(str)); VALUE str2 = rb_obj_alloc(klass);
RSTRING(str2)->len = RSTRING(str)->len; RSTRING(str2)->len = RSTRING(str)->len;
RSTRING(str2)->ptr = RSTRING(str)->ptr; RSTRING(str2)->ptr = RSTRING(str)->ptr;
RSTRING(str2)->orig = str; RSTRING(str2)->aux.shared = str;
FL_SET(str2, ELTS_SHARED);
OBJ_INFECT(str2, str); OBJ_INFECT(str2, str);
return str2; return str2;
} }
VALUE
rb_str_new3(str)
VALUE str;
{
return str_new3(rb_obj_class(str), str);
}
VALUE VALUE
rb_str_new4(orig) rb_str_new4(orig)
VALUE orig; VALUE orig;
{ {
VALUE klass; VALUE klass, str;
klass = rb_obj_class(orig); klass = rb_obj_class(orig);
if (RSTRING(orig)->orig) { if (FL_TEST(orig, ELTS_SHARED)) {
VALUE str; str = str_new3(klass, RSTRING(orig)->aux.shared);
}
if (FL_TEST(orig, STR_NO_ORIG)) { else if (FL_TEST(orig, STR_ASSOC)) {
str = rb_str_new0(klass, RSTRING(orig)->ptr, RSTRING(orig)->len); str = str_new(klass, RSTRING(orig)->ptr, RSTRING(orig)->len);
} }
else { else {
str = rb_str_new3(RSTRING(orig)->orig); str = rb_obj_alloc(klass);
RBASIC(str)->klass = klass;
}
OBJ_FREEZE(str);
return str;
}
else {
VALUE str = rb_obj_alloc(klass);
RSTRING(str)->len = RSTRING(orig)->len; RSTRING(str)->len = RSTRING(orig)->len;
RSTRING(str)->ptr = RSTRING(orig)->ptr; RSTRING(str)->ptr = RSTRING(orig)->ptr;
RSTRING(orig)->orig = str; RSTRING(orig)->aux.shared = str;
FL_SET(orig, ELTS_SHARED);
}
OBJ_INFECT(str, orig); OBJ_INFECT(str, orig);
OBJ_FREEZE(str); OBJ_FREEZE(str);
return str; return str;
}
} }
VALUE VALUE
@ -152,7 +153,7 @@ rb_str_new5(obj, ptr, len)
const char *ptr; const char *ptr;
long len; long len;
{ {
return rb_str_new0(rb_obj_class(obj), ptr, len); return str_new(rb_obj_class(obj), ptr, len);
} }
#define STR_BUF_MIN_SIZE 128 #define STR_BUF_MIN_SIZE 128
@ -163,12 +164,11 @@ rb_str_buf_new(capa)
{ {
VALUE str = rb_obj_alloc(rb_cString); VALUE str = rb_obj_alloc(rb_cString);
FL_SET(str, STR_NO_ORIG);
if (capa < STR_BUF_MIN_SIZE) if (capa < STR_BUF_MIN_SIZE)
capa = STR_BUF_MIN_SIZE; capa = STR_BUF_MIN_SIZE;
RSTRING(str)->ptr = 0; RSTRING(str)->ptr = 0;
RSTRING(str)->len = 0; RSTRING(str)->len = 0;
RSTRING(str)->orig = LONG2FIX(capa); RSTRING(str)->aux.capa = capa;
RSTRING(str)->ptr = ALLOC_N(char, capa+1); RSTRING(str)->ptr = ALLOC_N(char, capa+1);
RSTRING(str)->ptr[0] = '\0'; RSTRING(str)->ptr[0] = '\0';
@ -210,16 +210,23 @@ rb_str_become(str, str2)
if (NIL_P(str2)) { if (NIL_P(str2)) {
RSTRING(str)->ptr = 0; RSTRING(str)->ptr = 0;
RSTRING(str)->len = 0; RSTRING(str)->len = 0;
RSTRING(str)->orig = 0; RSTRING(str)->aux.capa = 0;
return; return;
} }
if ((!RSTRING(str)->orig||FL_TEST(str,STR_NO_ORIG))&&RSTRING(str)->ptr) if (FL_TEST(str, ELTS_SHARED)) free(RSTRING(str)->ptr);
free(RSTRING(str)->ptr);
RSTRING(str)->ptr = RSTRING(str2)->ptr; RSTRING(str)->ptr = RSTRING(str2)->ptr;
RSTRING(str)->len = RSTRING(str2)->len; RSTRING(str)->len = RSTRING(str2)->len;
RSTRING(str)->orig = RSTRING(str2)->orig; if (FL_TEST(str2, ELTS_SHARED|STR_ASSOC)) {
FL_SET(str, RBASIC(str2)->flags & (ELTS_SHARED|STR_ASSOC));
RSTRING(str)->aux.shared = RSTRING(str2)->aux.shared;
}
else {
RSTRING(str)->aux.capa = RSTRING(str2)->aux.capa;
}
RSTRING(str2)->ptr = 0; /* abandon str2 */ RSTRING(str2)->ptr = 0; /* abandon str2 */
RSTRING(str2)->len = 0; RSTRING(str2)->len = 0;
RSTRING(str2)->aux.capa = 0;
FL_UNSET(str, ELTS_SHARED|STR_ASSOC);
if (OBJ_TAINTED(str2)) OBJ_TAINT(str); if (OBJ_TAINTED(str2)) OBJ_TAINT(str);
} }
@ -227,22 +234,23 @@ void
rb_str_associate(str, add) rb_str_associate(str, add)
VALUE str, add; VALUE str, add;
{ {
if (FL_TEST(str, STR_NO_ORIG|STR_ASSOC) != (STR_NO_ORIG|STR_ASSOC)) { if (FL_TEST(str, STR_ASSOC)) {
if (FL_TEST(str, STR_NO_ORIG)) { /* already associated */
rb_ary_concat(RSTRING(str)->aux.shared, add);
}
else {
if (FL_TEST(str, ELTS_SHARED)) {
rb_str_modify(str);
}
else if (RSTRING(str)->aux.shared) {
/* str_buf */ /* str_buf */
if (FIX2LONG(RSTRING(str)->orig) != RSTRING(str)->len) { if (RSTRING(str)->aux.capa != RSTRING(str)->len) {
REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len + 1); REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len + 1);
} }
} }
else if (RSTRING(str)->orig) { RSTRING(str)->aux.shared = add;
rb_str_modify(str); FL_UNSET(str, ELTS_SHARED);
} FL_SET(str, STR_ASSOC);
RSTRING(str)->orig = add;
FL_SET(str, STR_NO_ORIG|STR_ASSOC);
}
else {
/* already associated */
rb_ary_concat(RSTRING(str)->orig, add);
} }
} }
@ -250,10 +258,10 @@ VALUE
rb_str_associated(str) rb_str_associated(str)
VALUE str; VALUE str;
{ {
if (FL_TEST(str, STR_NO_ORIG|STR_ASSOC) != (STR_NO_ORIG|STR_ASSOC)) { if (FL_TEST(str, STR_ASSOC)) {
return Qfalse; return RSTRING(str)->aux.shared;
} }
return RSTRING(str)->orig; return Qfalse;
} }
static ID id_to_s; static ID id_to_s;
@ -274,45 +282,53 @@ rb_obj_as_string(obj)
return str; return str;
} }
VALUE static VALUE
rb_str_dup(str) str_copy(str, clone)
VALUE str; VALUE str;
int clone;
{ {
VALUE str2; VALUE str2;
VALUE klass; VALUE klass;
int flags;
StringValue(str); StringValue(str);
klass = rb_obj_class(str);
if (OBJ_FROZEN(str)) str2 = rb_str_new3(str); if (FL_TEST(str, ELTS_SHARED)) {
else if (FL_TEST(str, STR_NO_ORIG)) { str2 = rb_str_new3(RSTRING(str)->aux.shared);
str2 = rb_str_new0(klass, RSTRING(str)->ptr, RSTRING(str)->len);
} }
else if (RSTRING(str)->orig) { else if (FL_TEST(str, STR_ASSOC)) {
str2 = rb_str_new3(RSTRING(str)->orig); str2 = str_new(RSTRING(str)->ptr, RSTRING(str)->len);
RBASIC(str2)->klass = klass; RSTRING(str2)->aux.shared = RSTRING(str)->aux.shared;
FL_UNSET(str2, FL_TAINT); }
OBJ_INFECT(str2, str); else if (OBJ_FROZEN(str)) {
str2 = rb_str_new3(str);
} }
else { else {
str2 = rb_str_new3(rb_str_new4(str)); str2 = rb_str_new3(rb_str_new4(str));
} }
if (FL_TEST(str, FL_EXIVAR)) flags = FL_TEST(str2, ELTS_SHARED|STR_ASSOC);
rb_copy_generic_ivar(str2, str); if (clone) {
OBJ_INFECT(str2, str); CLONESETUP(str2, str);
}
else {
DUPSETUP(str2, str);
}
if (flags) FL_SET(str2, flags);
return str2; return str2;
} }
VALUE
rb_str_dup(str)
VALUE str;
{
return str_copy(str, Qfalse);
}
static VALUE static VALUE
rb_str_clone(str) rb_str_clone(str)
VALUE str; VALUE str;
{ {
VALUE clone = rb_str_dup(str); return str_copy(str, Qtrue);
if (FL_TEST(str, STR_NO_ORIG))
RSTRING(clone)->orig = RSTRING(str)->orig;
CLONESETUP(clone, str);
return clone;
} }
static VALUE rb_str_replace _((VALUE, VALUE)); static VALUE rb_str_replace _((VALUE, VALUE));
@ -446,9 +462,7 @@ str_independent(str)
if (OBJ_FROZEN(str)) rb_error_frozen("string"); if (OBJ_FROZEN(str)) rb_error_frozen("string");
if (!OBJ_TAINTED(str) && rb_safe_level() >= 4) if (!OBJ_TAINTED(str) && rb_safe_level() >= 4)
rb_raise(rb_eSecurityError, "Insecure: can't modify string"); rb_raise(rb_eSecurityError, "Insecure: can't modify string");
if (!RSTRING(str)->orig || FL_TEST(str, STR_NO_ORIG)) return 1; if (!FL_TEST(str, ELTS_SHARED)) return 1;
if (RBASIC(str)->flags == 0) abort();
if (TYPE(RSTRING(str)->orig) != T_STRING) rb_bug("non string str->orig");
return 0; return 0;
} }
@ -465,7 +479,8 @@ rb_str_modify(str)
} }
ptr[RSTRING(str)->len] = 0; ptr[RSTRING(str)->len] = 0;
RSTRING(str)->ptr = ptr; RSTRING(str)->ptr = ptr;
RSTRING(str)->orig = 0; RSTRING(str)->aux.capa = RSTRING(str)->len;
FL_UNSET(str, ELTS_SHARED|STR_ASSOC);
} }
VALUE VALUE
@ -479,9 +494,9 @@ VALUE
rb_str_dup_frozen(str) rb_str_dup_frozen(str)
VALUE str; VALUE str;
{ {
if (RSTRING(str)->orig && !FL_TEST(str, STR_NO_ORIG)) { if (FL_TEST(str, ELTS_SHARED)) {
OBJ_FREEZE(RSTRING(str)->orig); OBJ_FREEZE(RSTRING(str)->aux.shared);
return RSTRING(str)->orig; return RSTRING(str)->aux.shared;
} }
if (OBJ_FROZEN(str)) return str; if (OBJ_FROZEN(str)) return str;
str = rb_str_dup(str); str = rb_str_dup(str);
@ -516,21 +531,17 @@ rb_str_buf_cat(str, ptr, len)
{ {
long i, capa, total; long i, capa, total;
if (RSTRING(str)->orig == 0) { if (FL_TEST(str, ELTS_SHARED)) {
capa = RSTRING(str)->len; rb_str_modify(str);
FL_SET(str, STR_NO_ORIG);
} }
else { capa = RSTRING(str)->aux.capa;
capa = FIX2LONG(RSTRING(str)->orig);
}
total = RSTRING(str)->len+len; total = RSTRING(str)->len+len;
if (capa <= total) { if (capa <= total) {
while (total > capa) { while (total > capa) {
capa = (capa + 1) * 2; capa = (capa + 1) * 2;
} }
REALLOC_N(RSTRING(str)->ptr, char, capa+1); REALLOC_N(RSTRING(str)->ptr, char, capa+1);
RSTRING(str)->orig = LONG2FIX(capa); RSTRING(str)->aux.capa = capa;
} }
memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len);
RSTRING(str)->len = total; RSTRING(str)->len = total;
@ -557,8 +568,7 @@ rb_str_cat(str, ptr, len)
rb_str_modify(str); rb_str_modify(str);
if (len > 0) { if (len > 0) {
if (RSTRING(str)->orig == 0 || if (!FL_TEST(str, ELTS_SHARED) && !FL_TEST(str, STR_ASSOC)) {
(FL_TEST(str, STR_NO_ORIG) && !FL_TEST(str, STR_ASSOC))) {
return rb_str_buf_cat(str, ptr, len); return rb_str_buf_cat(str, ptr, len);
} }
REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+len+1); REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+len+1);
@ -589,13 +599,10 @@ rb_str_buf_append(str, str2)
{ {
long i, capa, len; long i, capa, len;
if (RSTRING(str)->orig == 0) { if (FL_TEST(str, ELTS_SHARED)) {
capa = RSTRING(str)->len; rb_str_modify(str);
FL_SET(str, STR_NO_ORIG);
}
else {
capa = FIX2LONG(RSTRING(str)->orig);
} }
capa = RSTRING(str)->aux.capa;
len = RSTRING(str)->len+RSTRING(str2)->len; len = RSTRING(str)->len+RSTRING(str2)->len;
if (capa <= len) { if (capa <= len) {
@ -603,7 +610,7 @@ rb_str_buf_append(str, str2)
capa = (capa + 1) * 2; capa = (capa + 1) * 2;
} }
REALLOC_N(RSTRING(str)->ptr, char, capa+1); REALLOC_N(RSTRING(str)->ptr, char, capa+1);
RSTRING(str)->orig = LONG2FIX(capa); RSTRING(str)->aux.capa = capa;
} }
memcpy(RSTRING(str)->ptr + RSTRING(str)->len, memcpy(RSTRING(str)->ptr + RSTRING(str)->len,
RSTRING(str2)->ptr, RSTRING(str2)->len); RSTRING(str2)->ptr, RSTRING(str2)->len);
@ -623,11 +630,9 @@ rb_str_append(str, str2)
rb_str_modify(str); rb_str_modify(str);
if (RSTRING(str2)->len > 0) { if (RSTRING(str2)->len > 0) {
len = RSTRING(str)->len+RSTRING(str2)->len; len = RSTRING(str)->len+RSTRING(str2)->len;
if (RSTRING(str)->orig == 0 || if (!FL_TEST(str, ELTS_SHARED) && !FL_TEST(str, STR_ASSOC)) {
(FL_TEST(str, STR_NO_ORIG) && !FL_TEST(str, STR_ASSOC))) {
rb_str_buf_append(str, str2); rb_str_buf_append(str, str2);
OBJ_INFECT(str, str2); OBJ_INFECT(str, str2);
return str; return str;
} }
REALLOC_N(RSTRING(str)->ptr, char, len+1); REALLOC_N(RSTRING(str)->ptr, char, len+1);
@ -810,6 +815,13 @@ rb_str_match2(str)
return rb_reg_match2(rb_reg_regcomp(str)); return rb_reg_match2(rb_reg_regcomp(str));
} }
static VALUE
rb_str_match_m(str, re)
VALUE str, re;
{
return rb_funcall(re, rb_intern("match"), 1, str);
}
static long static long
rb_str_index(str, sub, offset) rb_str_index(str, sub, offset)
VALUE str, sub; VALUE str, sub;
@ -1529,20 +1541,18 @@ str_gsub(argc, argv, str, bang)
if (str_independent(str)) { if (str_independent(str)) {
free(RSTRING(str)->ptr); free(RSTRING(str)->ptr);
} }
else { FL_UNSET(str, ELTS_SHARED|STR_ASSOC);
RSTRING(str)->orig = 0;
}
} }
else { else {
VALUE dup = rb_obj_alloc(rb_obj_class(str)); VALUE dup = rb_obj_alloc(rb_obj_class(str));
OBJ_INFECT(dup, str); OBJ_INFECT(dup, str);
str = dup; str = dup;
RSTRING(dup)->orig = 0;
} }
RSTRING(str)->ptr = buf; RSTRING(str)->ptr = buf;
RSTRING(str)->len = len = bp - buf; RSTRING(str)->len = len = bp - buf;
RSTRING(str)->ptr[len] = '\0'; RSTRING(str)->ptr[len] = '\0';
RSTRING(str)->aux.capa = len;
if (tainted) OBJ_TAINT(str); if (tainted) OBJ_TAINT(str);
return str; return str;
@ -1573,13 +1583,19 @@ rb_str_replace(str, str2)
if (str == str2) return str; if (str == str2) return str;
StringValue(str2); StringValue(str2);
if (RSTRING(str2)->orig && !FL_TEST(str2, STR_NO_ORIG)) { if (FL_TEST(str2, ELTS_SHARED)) {
if (str_independent(str)) { if (str_independent(str)) {
free(RSTRING(str)->ptr); free(RSTRING(str)->ptr);
} }
RSTRING(str)->len = RSTRING(str2)->len; RSTRING(str)->len = RSTRING(str2)->len;
RSTRING(str)->ptr = RSTRING(str2)->ptr; RSTRING(str)->ptr = RSTRING(str2)->ptr;
RSTRING(str)->orig = RSTRING(str2)->orig; if (FL_TEST(str2, ELTS_SHARED|STR_ASSOC)) {
FL_SET(str, RBASIC(str2)->flags & (ELTS_SHARED|STR_ASSOC));
RSTRING(str)->aux.shared = RSTRING(str2)->aux.shared;
}
else {
RSTRING(str)->aux.capa = RSTRING(str2)->aux.capa;
}
} }
else { else {
rb_str_modify(str); rb_str_modify(str);
@ -3113,6 +3129,7 @@ Init_String()
rb_define_method(rb_cString, "empty?", rb_str_empty, 0); rb_define_method(rb_cString, "empty?", rb_str_empty, 0);
rb_define_method(rb_cString, "=~", rb_str_match, 1); rb_define_method(rb_cString, "=~", rb_str_match, 1);
rb_define_method(rb_cString, "~", rb_str_match2, 0); rb_define_method(rb_cString, "~", rb_str_match2, 0);
rb_define_method(rb_cString, "match", rb_str_match_m, 1);
rb_define_method(rb_cString, "succ", rb_str_succ, 0); rb_define_method(rb_cString, "succ", rb_str_succ, 0);
rb_define_method(rb_cString, "succ!", rb_str_succ_bang, 0); rb_define_method(rb_cString, "succ!", rb_str_succ_bang, 0);
rb_define_method(rb_cString, "next", rb_str_succ, 0); rb_define_method(rb_cString, "next", rb_str_succ, 0);

55
time.c
View file

@ -72,9 +72,9 @@ time_new_internal(klass, sec, usec)
sec += usec / 1000000; sec += usec / 1000000;
usec %= 1000000; usec %= 1000000;
} }
if (usec < 0) { /* usec underflow */ while (usec < 0) { /* usec underflow */
sec -= (-usec) / 1000000; sec--;
usec %= 1000000; usec += 1000000;
} }
#ifndef NEGATIVE_TIME_T #ifndef NEGATIVE_TIME_T
if (sec < 0 || (sec == 0 && usec < 0)) if (sec < 0 || (sec == 0 && usec < 0))
@ -643,7 +643,13 @@ time_cmp(time1, time2)
return INT2FIX(-1); return INT2FIX(-1);
} }
i = NUM2LONG(time2); i = NUM2LONG(time2);
if (tobj1->tv.tv_sec == i) return INT2FIX(0); if (tobj1->tv.tv_sec == i) {
if (tobj1->tv.tv_usec == 0)
return INT2FIX(0);
if (tobj1->tv.tv_usec > 0)
return INT2FIX(1);
return INT2FIX(-1);
}
if (tobj1->tv.tv_sec > i) return INT2FIX(1); if (tobj1->tv.tv_sec > i) return INT2FIX(1);
return INT2FIX(-1); return INT2FIX(-1);
} }
@ -759,6 +765,35 @@ time_gmtime(time)
return time; return time;
} }
static VALUE
time_dup(time)
VALUE time;
{
VALUE clone;
struct time_object *tobj, *tclone;
GetTimeval(time, tobj);
clone = Data_Make_Struct(0, struct time_object, 0, free, tclone);
DUPSETUP(clone, time);
MEMCPY(tclone, tobj, struct time_object, 1);
return clone;
}
static VALUE
time_getlocaltime(time)
VALUE time;
{
return time_localtime(time_dup(time));
}
static VALUE
time_getgmtime(time)
VALUE time;
{
return time_gmtime(time_dup(time));
}
static VALUE static VALUE
time_get_tm(time, gmt) time_get_tm(time, gmt)
VALUE time; VALUE time;
@ -1071,7 +1106,7 @@ rb_strftime(buf, format, time)
* if the buffer is 1024 times bigger than the length of the * if the buffer is 1024 times bigger than the length of the
* format string, it's not failing for lack of room. * format string, it's not failing for lack of room.
*/ */
if (len > 0 || len >= 1024 * flen) return len; if (len > 0 || size >= 1024 * flen) return len;
free(*buf); free(*buf);
} }
/* not reached */ /* not reached */
@ -1109,7 +1144,10 @@ time_strftime(time, format)
p += strlen(p) + 1; p += strlen(p) + 1;
if (p <= pe) if (p <= pe)
rb_str_cat(str, "\0", 1); rb_str_cat(str, "\0", 1);
if (len > SMALLBUF) free(buf); if (buf != buffer) {
free(buf);
buf = buffer;
}
} }
return str; return str;
} }
@ -1231,10 +1269,15 @@ Init_Time()
rb_define_method(rb_cTime, "eql?", time_eql, 1); rb_define_method(rb_cTime, "eql?", time_eql, 1);
rb_define_method(rb_cTime, "hash", time_hash, 0); rb_define_method(rb_cTime, "hash", time_hash, 0);
rb_define_method(rb_cTime, "clone", time_clone, 0); rb_define_method(rb_cTime, "clone", time_clone, 0);
rb_define_method(rb_cTime, "dup", time_dup, 0);
rb_define_method(rb_cTime, "localtime", time_localtime, 0); rb_define_method(rb_cTime, "localtime", time_localtime, 0);
rb_define_method(rb_cTime, "gmtime", time_gmtime, 0); rb_define_method(rb_cTime, "gmtime", time_gmtime, 0);
rb_define_method(rb_cTime, "utc", time_gmtime, 0); rb_define_method(rb_cTime, "utc", time_gmtime, 0);
rb_define_method(rb_cTime, "getlocal", time_getlocaltime, 0);
rb_define_method(rb_cTime, "getgm", time_getgmtime, 0);
rb_define_method(rb_cTime, "getutc", time_getgmtime, 0);
rb_define_method(rb_cTime, "ctime", time_asctime, 0); rb_define_method(rb_cTime, "ctime", time_asctime, 0);
rb_define_method(rb_cTime, "asctime", time_asctime, 0); rb_define_method(rb_cTime, "asctime", time_asctime, 0);
rb_define_method(rb_cTime, "to_s", time_to_s, 0); rb_define_method(rb_cTime, "to_s", time_to_s, 0);

53
util.c
View file

@ -384,31 +384,25 @@ __crt0_glob_function(char *path)
/* mm.c */ /* mm.c */
static int mmkind, mmsize, high, low;
#define A ((int*)a) #define A ((int*)a)
#define B ((int*)b) #define B ((int*)b)
#define C ((int*)c) #define C ((int*)c)
#define D ((int*)d) #define D ((int*)d)
static void mmprepare(base, size) void *base; int size; #define mmprepare(base, size) do {\
{ if (((long)base & (0x3)) == 0)\
#ifdef DEBUG if (size >= 16) mmkind = 1;\
if (sizeof(int) != 4) die("sizeof(int) != 4"); else mmkind = 0;\
if (size <= 0) die("mmsize <= 0"); else mmkind = -1;\
#endif high = (size & (~0xf));\
low = (size & 0x0c);\
} while (0)\
if (((long)base & (4-1)) == 0 && ((long)base & (4-1)) == 0) #define mmarg mmkind, size, high, low
if (size >= 16) mmkind = 1;
else mmkind = 0;
else mmkind = -1;
mmsize = size; static void mmswap_(a, b, mmarg)
high = (size & (-16)); register char *a, *b;
low = (size & 0x0c); int mmarg;
}
static void mmswap(a, b) register char *a, *b;
{ {
register int s; register int s;
if (a == b) return; if (a == b) return;
@ -427,12 +421,15 @@ static void mmswap(a, b) register char *a, *b;
if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = s;}}} if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = s;}}}
} }
else { else {
register char *t = a + mmsize; register char *t = a + size;
do {s = *a; *a++ = *b; *b++ = s;} while (a < t); do {s = *a; *a++ = *b; *b++ = s;} while (a < t);
} }
} }
#define mmswap(a,b) mmswap_((a),(b),mmarg)
static void mmrot3(a, b, c) register char *a, *b, *c; static void mmrot3_(a, b, c, mmarg)
register char *a, *b, *c;
int mmarg;
{ {
register int s; register int s;
if (mmkind >= 0) { if (mmkind >= 0) {
@ -450,10 +447,11 @@ static void mmrot3(a, b, c) register char *a, *b, *c;
if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s;}}} if (low == 12) {s = A[2]; A[2] = B[2]; B[2] = C[2]; C[2] = s;}}}
} }
else { else {
register char *t = a + mmsize; register char *t = a + size;
do {s = *a; *a++ = *b; *b++ = *c; *c++ = s;} while (a < t); do {s = *a; *a++ = *b; *b++ = *c; *c++ = s;} while (a < t);
} }
} }
#define mmrot3(a,b,c) mmrot3_((a),(b),(c),mmarg)
/* qs6.c */ /* qs6.c */
/*****************************************************/ /*****************************************************/
@ -472,7 +470,11 @@ typedef struct { char *LL, *RR; } stack_node; /* Stack structure for L,l,R,r */
((*cmp)(b,c)<0 ? b : ((*cmp)(a,c)<0 ? c : a)) : \ ((*cmp)(b,c)<0 ? b : ((*cmp)(a,c)<0 ? c : a)) : \
((*cmp)(b,c)>0 ? b : ((*cmp)(a,c)<0 ? a : c))) ((*cmp)(b,c)>0 ? b : ((*cmp)(a,c)<0 ? a : c)))
void ruby_qsort (base, nel, size, cmp) void* base; int nel; int size; int (*cmp)(); void ruby_qsort (base, nel, size, cmp)
void* base;
const int nel;
const int size;
int (*cmp)();
{ {
register char *l, *r, *m; /* l,r:left,right group m:median point */ register char *l, *r, *m; /* l,r:left,right group m:median point */
register int t, eq_l, eq_r; /* eq_l: all items in left group are equal to S */ register int t, eq_l, eq_r; /* eq_l: all items in left group are equal to S */
@ -480,6 +482,7 @@ void ruby_qsort (base, nel, size, cmp) void* base; int nel; int size; int (*cmp)
char *R = (char*)base + size*(nel-1); /* right end of current region */ char *R = (char*)base + size*(nel-1); /* right end of current region */
int chklim = 63; /* threshold of ordering element check */ int chklim = 63; /* threshold of ordering element check */
stack_node stack[32], *top = stack; /* 32 is enough for 32bit CPU */ stack_node stack[32], *top = stack; /* 32 is enough for 32bit CPU */
int mmkind, high, low;
if (nel <= 1) return; /* need not to sort */ if (nel <= 1) return; /* need not to sort */
mmprepare(base, size); mmprepare(base, size);
@ -491,7 +494,9 @@ void ruby_qsort (base, nel, size, cmp) void* base; int nel; int size; int (*cmp)
for (;;) { for (;;) {
start: start:
if (L + size == R) {if ((*cmp)(L,R) > 0) mmswap(L,R); goto nxt;}/* 2 elements */ if (L + size == R) { /* 2 elements */
if ((*cmp)(L,R) > 0) mmswap(L,R); goto nxt;
}
l = L; r = R; l = L; r = R;
t = (r - l + size) / size; /* number of elements */ t = (r - l + size) / size; /* number of elements */
@ -559,7 +564,7 @@ void ruby_qsort (base, nel, size, cmp) void* base; int nel; int size; int (*cmp)
if ((t = (*cmp)(m,r)) < 0) {goto loopA;} /*5-5-7*/ if ((t = (*cmp)(m,r)) < 0) {goto loopA;} /*5-5-7*/
if (t > 0) {mmswap(l,r); goto loopB;} /*5-5-3*/ if (t > 0) {mmswap(l,r); goto loopB;} /*5-5-3*/
/* deteming splitting type in case 5-5-5 */ /*5-5-5*/ /* determining splitting type in case 5-5-5 */ /*5-5-5*/
for (;;) { for (;;) {
if ((l += size) == r) goto nxt; /*5-5-5*/ if ((l += size) == r) goto nxt; /*5-5-5*/
if (l == m) continue; if (l == m) continue;

View file

@ -1,4 +1,4 @@
#define RUBY_VERSION "1.7.2" #define RUBY_VERSION "1.7.2"
#define RUBY_RELEASE_DATE "2001-12-09" #define RUBY_RELEASE_DATE "2001-12-10"
#define RUBY_VERSION_CODE 172 #define RUBY_VERSION_CODE 172
#define RUBY_RELEASE_CODE 20011209 #define RUBY_RELEASE_CODE 20011210