diff options
author | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2001-05-30 09:12:34 +0000 |
---|---|---|
committer | matz <matz@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2001-05-30 09:12:34 +0000 |
commit | abfaac7a6cbdbfad9e7c05bc5ebcb4df57906fcb (patch) | |
tree | 4d406191345ff9f25e3a3c9ce5f85a3a13e6f7d1 | |
parent | 4cd1cd7201757185e63a5a33181932a6670887ad (diff) | |
download | ruby-abfaac7a6cbdbfad9e7c05bc5ebcb4df57906fcb.tar.gz |
* ruby.c (proc_options): unexpected SecurityError happens when -T4.
* regex.c (re_compile_pattern): * \1 .. \9 should be
backreferences always.
* regex.c (re_match): backreferences corresponding to
unclosed/unmatched parentheses should fail always.
* string.c (rb_str_cat): use rb_str_buf_cat() if possible. [new]
* string.c (rb_str_append): ditto.
* string.c (rb_str_buf_cat): remove unnecessary check (type,
taint, modify) to gain performance.
* string.c (rb_str_buf_append): ditto.
* string.c (rb_str_buf_new): buffering string function. [new]
* string.c (rb_str_buf_append): ditto.
* string.c (rb_str_buf_cat): ditto.
* time.c (make_time_t): local time adjustment revised.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1476 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r-- | ChangeLog | 78 | ||||
-rw-r--r-- | array.c | 40 | ||||
-rw-r--r-- | class.c | 12 | ||||
-rw-r--r-- | dln.c | 15 | ||||
-rw-r--r-- | error.c | 10 | ||||
-rw-r--r-- | eval.c | 33 | ||||
-rw-r--r-- | file.c | 16 | ||||
-rw-r--r-- | hash.c | 26 | ||||
-rw-r--r-- | intern.h | 4 | ||||
-rw-r--r-- | io.c | 2 | ||||
-rw-r--r-- | marshal.c | 4 | ||||
-rw-r--r-- | object.c | 4 | ||||
-rw-r--r-- | pack.c | 110 | ||||
-rw-r--r-- | parse.y | 314 | ||||
-rw-r--r-- | range.c | 95 | ||||
-rw-r--r-- | re.c | 74 | ||||
-rw-r--r-- | regex.c | 47 | ||||
-rw-r--r-- | ruby.c | 10 | ||||
-rw-r--r-- | ruby.h | 1 | ||||
-rw-r--r-- | string.c | 186 | ||||
-rw-r--r-- | struct.c | 2 | ||||
-rw-r--r-- | time.c | 250 | ||||
-rw-r--r-- | variable.c | 1 | ||||
-rw-r--r-- | version.h | 8 |
24 files changed, 922 insertions, 420 deletions
@@ -1,3 +1,38 @@ +Tue May 29 17:24:23 2001 K.Kosako <kosako@sofnec.co.jp> + + * ruby.c (proc_options): unexpected SecurityError happens when -T4. + +Tue May 29 18:46:04 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * regex.c (re_compile_pattern): * \1 .. \9 should be + backreferences always. + + * regex.c (re_match): backreferences corresponding to + unclosed/unmatched parentheses should fail always. + +Tue May 29 16:35:49 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * string.c (rb_str_cat): use rb_str_buf_cat() if possible. [new] + + * string.c (rb_str_append): ditto. + + * string.c (rb_str_buf_cat): remove unnecessary check (type, + taint, modify) to gain performance. + + * string.c (rb_str_buf_append): ditto. + + * string.c (rb_str_buf_finish): removed. + +Tue May 29 02:05:55 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * string.c (rb_str_buf_new): buffering string function. [new] + + * string.c (rb_str_buf_append): ditto. + + * string.c (rb_str_buf_cat): ditto. + + * string.c (rb_str_buf_finish): ditto. + Mon May 28 23:20:43 2001 WATANABE Hirofumi <eban@ruby-lang.org> * configure.in: remove unnecessary AC_CANONICAL_BUILD @@ -21,6 +56,10 @@ Mon May 28 22:12:01 2001 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp> * ext/extconf.rb.in: make the priority of the make rule of .c higher than .C . +Mon May 28 13:22:19 2001 Tanaka Akira <akr@m17n.org> + + * time.c (make_time_t): local time adjustment revised. + Mon May 28 02:20:38 2001 Akinori MUSHA <knu@iDaemons.org> * dir.c (glob_helper): teach has_magic() to handle flags and get @@ -29,10 +68,38 @@ Mon May 28 02:20:38 2001 Akinori MUSHA <knu@iDaemons.org> * dir.c (fnmatch): fix a bug when FNM_PATHNAME and FNM_PERIOD are specified at the same time. +Sat May 26 09:55:26 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * parse.y: accomplish extended syntax described in [ruby-talk:14525] + using tSPC token. [new, experimental] + Sat May 26 07:05:45 2001 Usaku Nakamura <usa@osb.att.ne.jp> * MANIFEST: add win32/dir.h . +Fri May 25 20:03:51 2001 Pascal Rigaux <pixel@mandrakesoft.com> + + * dln.c (dln_find_1): should exclude directories in executable + file lookup. + +Fri May 25 18:00:26 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * class.c (rb_obj_singleton_methods): list methods in extended + modules if optional argument is true. [new] + +Fri May 25 14:19:25 2001 K.Kosako <kosako@sofnec.co.jp> + + * string.c (rb_str_replace): add taint status infection + (OBJ_INFECT()). + + * string.c (rb_str_crypt): ditto. + + * string.c (rb_str_ljust): ditto. + + * string.c (rb_str_rjust): ditto. + + * string.c (rb_str_center): ditto. + Fri May 25 05:39:03 2001 Akinori MUSHA <knu@iDaemons.org> * ext/sha1/sha1-ruby.c (sha1_hexdigest): fix buffer overflow. The @@ -54,6 +121,17 @@ Fri May 25 00:53:41 2001 Akinori MUSHA <knu@iDaemons.org> * ext/dbm/extconf.rb: fix support for *BSD and set $CFLAGS properly. +Thu May 24 16:10:33 2001 Yukihiro Matsumoto <matz@ruby-lang.org> + + * range.c (range_member): check based on "<=>" comparison. [new] + + * range.c (range_check): add "succ" check if first end is not a + numeric. + + * range.c (range_eqq): comparison should based on "<=>". + + * range.c (range_each): ditto. + Thu May 24 16:08:21 2001 WATANABE Hirofumi <eban@ruby-lang.org> * mkconfig.rb: autoconf 2.50 support. @@ -739,26 +739,11 @@ inspect_join(ary, arg) return rb_ary_join(arg[0], arg[1]); } -static long -str_cpy(str, idx, str2) - VALUE str; - long idx; - VALUE str2; -{ - long len = idx + RSTRING(str2)->len; - - if (RSTRING(str)->len < len) { - rb_str_resize(str, len); - } - memcpy(RSTRING(str)->ptr+idx, RSTRING(str2)->ptr, RSTRING(str2)->len); - return len; -} - VALUE rb_ary_join(ary, sep) VALUE ary, sep; { - long len, i, j; + long len, i; int taint = 0; VALUE result, tmp; @@ -778,9 +763,8 @@ rb_ary_join(ary, sep) if (!NIL_P(sep) && TYPE(sep) == T_STRING) { len += RSTRING(sep)->len * RARRAY(ary)->len - 1; } - result = rb_str_new(0, len); - - for (i=0, j=0; i<RARRAY(ary)->len; i++) { + result = rb_str_buf_new(len); + for (i=0; i<RARRAY(ary)->len; i++) { tmp = RARRAY(ary)->ptr[i]; switch (TYPE(tmp)) { case T_STRING: @@ -800,11 +784,11 @@ rb_ary_join(ary, sep) default: tmp = rb_obj_as_string(tmp); } - if (i > 0 && !NIL_P(sep)) j = str_cpy(result, j, sep); - j = str_cpy(result, j, tmp); + if (i > 0 && !NIL_P(sep)) + rb_str_buf_append(result, sep); + rb_str_buf_append(result, tmp); if (OBJ_TAINTED(tmp)) taint = 1; } - rb_str_resize(result, j); if (taint) OBJ_TAINT(result); return result; @@ -909,16 +893,14 @@ inspect_ary(ary) long i = 0; VALUE s, str; - str = rb_str_new2("["); - + str = rb_str_buf_new2("["); for (i=0; i<RARRAY(ary)->len; i++) { s = rb_inspect(RARRAY(ary)->ptr[i]); - tainted = OBJ_TAINTED(s); - if (i > 0) rb_str_cat2(str, ", "); - rb_str_append(str, s); + if (OBJ_TAINTED(s)) tainted = 1; + if (i > 0) rb_str_buf_cat2(str, ", "); + rb_str_buf_append(str, s); } - rb_str_cat(str, "]", 1); - + rb_str_buf_cat2(str, "]"); if (tainted) OBJ_TAINT(str); return str; } @@ -484,19 +484,29 @@ rb_class_private_instance_methods(argc, argv, mod) } VALUE -rb_obj_singleton_methods(obj) +rb_obj_singleton_methods(argc, argv, obj) + int argc; + VALUE *argv; VALUE obj; { + VALUE all; VALUE ary; VALUE klass; VALUE *p, *q, *pend; + rb_scan_args(argc, argv, "01", &all); ary = rb_ary_new(); klass = CLASS_OF(obj); while (klass && FL_TEST(klass, FL_SINGLETON)) { st_foreach(RCLASS(klass)->m_tbl, ins_methods_i, ary); klass = RCLASS(klass)->super; } + if (RTEST(all)) { + while (klass && TYPE(klass) == T_ICLASS) { + st_foreach(RCLASS(klass)->m_tbl, ins_methods_i, ary); + klass = RCLASS(klass)->super; + } + } p = q = RARRAY(ary)->ptr; pend = p + RARRAY(ary)->len; while (p < pend) { if (*p == Qnil) { @@ -50,6 +50,10 @@ void *xrealloc(); #include <sys/types.h> #include <sys/stat.h> +#ifndef S_ISDIR +# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR) +#endif + #ifdef HAVE_SYS_PARAM_H # include <sys/param.h> #else @@ -1582,9 +1586,8 @@ dln_find_1(fname, path, exe_flag) register char *dp; register char *ep; register char *bp; -#ifndef __MACOS__ struct stat st; -#else +#ifdef __MACOS__ const char* mac_fullpath; #endif @@ -1669,13 +1672,17 @@ dln_find_1(fname, path, exe_flag) if (stat(fbuf, &st) == 0) { if (exe_flag == 0) return fbuf; /* looking for executable */ - if (eaccess(fbuf, X_OK) == 0) return fbuf; + if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0) + return fbuf; } #else if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) { if (exe_flag == 0) return mac_fullpath; /* looking for executable */ - if (eaccess(mac_fullpath, X_OK) == 0) return mac_fullpath; + if (stat(mac_fullpath, &st) == 0) { + if (!S_ISDIR(st.st_mode) && eaccess(mac_fullpath, X_OK) == 0) + return mac_fullpath; + } } #endif #if defined(MSDOS) || defined(NT) || defined(__human68k__) || defined(__EMX__) @@ -359,12 +359,12 @@ exc_inspect(exc) return rb_str_dup(rb_class_path(klass)); } - str = rb_str_new2("#<"); + str = rb_str_buf_new2("#<"); klass = rb_class_path(klass); - rb_str_append(str, klass); - rb_str_cat(str, ": ", 2); - rb_str_append(str, exc); - rb_str_cat(str, ">", 1); + rb_str_buf_append(str, klass); + rb_str_buf_cat(str, ": ", 2); + rb_str_buf_append(str, exc); + rb_str_buf_cat(str, ">", 1); return str; } @@ -15,6 +15,7 @@ #include "ruby.h" #include "node.h" #include "env.h" +#include "util.h" #include "rubysig.h" #include <stdio.h> @@ -1213,14 +1214,14 @@ compile_error(at) VALUE str; ruby_nerrs = 0; - str = rb_str_new2("compile error"); + str = rb_str_buf_new2("compile error"); if (at) { - rb_str_cat2(str, " in "); - rb_str_cat2(str, at); + rb_str_buf_cat2(str, " in "); + rb_str_buf_cat2(str, at); } - rb_str_cat(str, "\n", 1); + rb_str_buf_cat(str, "\n", 1); if (!NIL_P(ruby_errinfo)) { - rb_str_concat(str, ruby_errinfo); + rb_str_append(str, ruby_errinfo); } rb_exc_raise(rb_exc_new3(rb_eSyntaxError, str)); } @@ -2351,9 +2352,7 @@ rb_eval(self, n) case NODE_YIELD: if (node->nd_stts) { result = rb_eval(self, node->nd_stts); - if (nd_type(node->nd_stts) == NODE_RESTARGS && - RARRAY(result)->len == 1) - { + if (nd_type(node->nd_stts) == NODE_RESTARGS && RARRAY(result)->len == 1) { result = RARRAY(result)->ptr[0]; } } @@ -6752,19 +6751,19 @@ method_inspect(method) const char *s; Data_Get_Struct(method, struct METHOD, data); - str = rb_str_new2("#<"); + str = rb_str_buf_new2("#<"); s = rb_class2name(CLASS_OF(method)); - rb_str_cat2(str, s); - rb_str_cat2(str, ": "); + rb_str_buf_cat2(str, s); + rb_str_buf_cat2(str, ": "); s = rb_class2name(data->oklass); - rb_str_cat2(str, s); - rb_str_cat2(str, "("); + rb_str_buf_cat2(str, s); + rb_str_buf_cat2(str, "("); s = rb_class2name(data->klass); - rb_str_cat2(str, s); - rb_str_cat2(str, ")#"); + rb_str_buf_cat2(str, s); + rb_str_buf_cat2(str, ")#"); s = rb_id2name(data->oid); - rb_str_cat2(str, s); - rb_str_cat2(str, ">"); + rb_str_buf_cat2(str, s); + rb_str_buf_cat2(str, ">"); return str; } @@ -281,22 +281,22 @@ rb_stat_inspect(self) {"ctime", rb_stat_ctime}, }; - str = rb_str_new2("#<"); - rb_str_cat2(str, rb_class2name(CLASS_OF(self))); - rb_str_cat2(str, " "); + str = rb_str_buf_new2("#<"); + rb_str_buf_cat2(str, rb_class2name(CLASS_OF(self))); + rb_str_buf_cat2(str, " "); for (i = 0; i < sizeof(member)/sizeof(member[0]); i++) { VALUE str2; if (i > 0) { - rb_str_cat2(str, ", "); + rb_str_buf_cat2(str, ", "); } - rb_str_cat2(str, member[i].name); - rb_str_cat2(str, "="); + rb_str_buf_cat2(str, member[i].name); + rb_str_buf_cat2(str, "="); str2 = rb_inspect((*member[i].func)(self)); rb_str_append(str, str2); } - rb_str_cat2(str, ">"); + rb_str_buf_cat2(str, ">"); OBJ_INFECT(str, self); return str; @@ -449,7 +449,7 @@ eaccess(path, mode) if (st.st_mode & mode) return 0; return -1; -#else /* !NT */ +#else return access(path, mode); #endif } @@ -634,11 +634,11 @@ inspect_i(key, value, str) rb_str_cat2(str, ", "); } str2 = rb_inspect(key); - rb_str_append(str, str2); + rb_str_buf_append(str, str2); OBJ_INFECT(str, str2); - rb_str_cat2(str, "=>"); + rb_str_buf_cat2(str, "=>"); str2 = rb_inspect(value); - rb_str_append(str, str2); + rb_str_buf_append(str, str2); OBJ_INFECT(str, str2); return ST_CONTINUE; @@ -650,11 +650,11 @@ inspect_hash(hash) { VALUE str; - str = rb_str_new2("{"); + str = rb_str_buf_new2("{"); st_foreach(RHASH(hash)->tbl, inspect_i, str); - rb_str_cat2(str, "}"); - + rb_str_buf_cat2(str, "}"); OBJ_INFECT(str, hash); + return str; } @@ -1266,7 +1266,7 @@ static VALUE env_inspect() { char **env; - VALUE str = rb_str_new2("{"); + VALUE str = rb_str_buf_new2("{"); VALUE i; env = environ; @@ -1274,18 +1274,18 @@ env_inspect() char *s = strchr(*env, '='); if (env != environ) { - rb_str_cat2(str, ", "); + rb_str_buf_cat2(str, ", "); } if (s) { - rb_str_cat2(str, "\""); - rb_str_cat(str, *env, s-*env); - rb_str_cat2(str, "\"=>"); + rb_str_buf_cat2(str, "\""); + rb_str_buf_cat(str, *env, s-*env); + rb_str_buf_cat2(str, "\"=>"); i = rb_inspect(rb_str_new2(s+1)); - rb_str_append(str, i); + rb_str_buf_append(str, i); } env++; } - rb_str_cat2(str, "}"); + rb_str_buf_cat2(str, "}"); OBJ_TAINT(str); return str; @@ -91,7 +91,7 @@ VALUE rb_mod_ancestors _((VALUE)); VALUE rb_class_instance_methods _((int, VALUE*, VALUE)); VALUE rb_class_protected_instance_methods _((int, VALUE*, VALUE)); VALUE rb_class_private_instance_methods _((int, VALUE*, VALUE)); -VALUE rb_obj_singleton_methods _((VALUE)); +VALUE rb_obj_singleton_methods _((int, VALUE*, VALUE)); void rb_define_method_id _((VALUE, ID, VALUE (*)(ANYARGS), int)); void rb_frozen_class_p _((VALUE)); void rb_undef _((VALUE, ID)); @@ -312,6 +312,8 @@ VALUE rb_str_new3 _((VALUE)); VALUE rb_str_new4 _((VALUE)); VALUE rb_tainted_str_new _((const char*, long)); VALUE rb_tainted_str_new2 _((const char*)); +VALUE rb_str_buf_new _((long)); +VALUE rb_str_buf_new2 _((const char*)); VALUE rb_obj_as_string _((VALUE)); VALUE rb_str_dup _((VALUE)); VALUE rb_str_plus _((VALUE, VALUE)); @@ -608,7 +608,7 @@ rb_io_gets_internal(argc, argv, io) VALUE rs; if (argc == 0) { - rs = rb_default_rs; + rs = rb_rs; } else { rb_scan_args(argc, argv, "1", &rs); @@ -106,7 +106,7 @@ w_byte(c, arg) struct dump_arg *arg; { if (arg->fp) putc(c, arg->fp); - else rb_str_cat(arg->str, &c, 1); + else rb_str_buf_cat(arg->str, &c, 1); } static void @@ -540,7 +540,7 @@ marshal_dump(argc, argv) } else { arg.fp = 0; - port = rb_str_new(0, 0); + port = rb_str_buf_new(0); arg.str = port; } @@ -809,8 +809,6 @@ rb_obj_methods(obj) return rb_class_instance_methods(1, argv, CLASS_OF(obj)); } -VALUE rb_obj_singleton_methods(); - static VALUE rb_obj_protected_methods(obj) VALUE obj; @@ -1179,7 +1177,7 @@ Init_Object() rb_define_method(rb_mKernel, "inspect", rb_obj_inspect, 0); rb_define_method(rb_mKernel, "methods", rb_obj_methods, 0); rb_define_method(rb_mKernel, "public_methods", rb_obj_methods, 0); - rb_define_method(rb_mKernel, "singleton_methods", rb_obj_singleton_methods, 0); + rb_define_method(rb_mKernel, "singleton_methods", rb_obj_singleton_methods, -1); rb_define_method(rb_mKernel, "protected_methods", rb_obj_protected_methods, 0); rb_define_method(rb_mKernel, "private_methods", rb_obj_private_methods, 0); rb_define_method(rb_mKernel, "instance_variables", rb_obj_instance_variables, 0); @@ -331,7 +331,7 @@ pack_pack(ary, fmt) static char *nul10 = "\0\0\0\0\0\0\0\0\0\0"; static char *spc10 = " "; char *p, *pend; - VALUE res, from; + VALUE res, from, associates = 0; char type; int items, len, idx; char *ptr; @@ -343,7 +343,7 @@ pack_pack(ary, fmt) StringValue(fmt); p = RSTRING(fmt)->ptr; pend = p + RSTRING(fmt)->len; - res = rb_str_new(0, 0); + res = rb_str_buf_new(0); items = RARRAY(ary)->len; idx = 0; @@ -405,15 +405,15 @@ pack_pack(ary, fmt) case 'A': case 'Z': if (plen >= len) - rb_str_cat(res, ptr, len); + rb_str_buf_cat(res, ptr, len); else { - rb_str_cat(res, ptr, plen); + rb_str_buf_cat(res, ptr, plen); len -= plen; while (len >= 10) { - rb_str_cat(res, (type == 'A')?spc10:nul10, 10); + rb_str_buf_cat(res, (type == 'A')?spc10:nul10, 10); len -= 10; } - rb_str_cat(res, (type == 'A')?spc10:nul10, len); + rb_str_buf_cat(res, (type == 'A')?spc10:nul10, len); } break; @@ -433,7 +433,7 @@ pack_pack(ary, fmt) byte >>= 1; else { char c = byte & 0xff; - rb_str_cat(res, &c, 1); + rb_str_buf_cat(res, &c, 1); byte = 0; } } @@ -441,11 +441,9 @@ pack_pack(ary, fmt) char c; byte >>= 7 - (len & 7); c = byte & 0xff; - rb_str_cat(res, &c, 1); + rb_str_buf_cat(res, &c, 1); } - len = RSTRING(res)->len; - rb_str_resize(res, len+j); - MEMZERO(RSTRING(res)->ptr+len, char, j); + rb_str_buf_cat(res, 0, j); } break; @@ -464,7 +462,7 @@ pack_pack(ary, fmt) byte <<= 1; else { char c = byte & 0xff; - rb_str_cat(res, &c, 1); + rb_str_buf_cat(res, &c, 1); byte = 0; } } @@ -472,11 +470,9 @@ pack_pack(ary, fmt) char c; byte <<= 7 - (len & 7); c = byte & 0xff; - rb_str_cat(res, &c, 1); + rb_str_buf_cat(res, &c, 1); } - len = RSTRING(res)->len; - rb_str_resize(res, len+j); - MEMZERO(RSTRING(res)->ptr+len, char, j); + rb_str_buf_cat(res, 0, j); } break; @@ -498,17 +494,15 @@ pack_pack(ary, fmt) byte >>= 4; else { char c = byte & 0xff; - rb_str_cat(res, &c, 1); + rb_str_buf_cat(res, &c, 1); byte = 0; } } if (len & 1) { char c = byte & 0xff; - rb_str_cat(res, &c, 1); + rb_str_buf_cat(res, &c, 1); } - len = RSTRING(res)->len; - rb_str_resize(res, len+j); - MEMZERO(RSTRING(res)->ptr+len, char, j); + rb_str_buf_cat(res, 0, j); } break; @@ -530,17 +524,15 @@ pack_pack(ary, fmt) byte <<= 4; else { char c = byte & 0xff; - rb_str_cat(res, &c, 1); + rb_str_buf_cat(res, &c, 1); byte = 0; } } if (len & 1) { char c = byte & 0xff; - rb_str_cat(res, &c, 1); + rb_str_buf_cat(res, &c, 1); } - len = RSTRING(res)->len; - rb_str_resize(res, len+j); - MEMZERO(RSTRING(res)->ptr+len, char, j); + rb_str_buf_cat(res, 0, j); } break; } @@ -556,7 +548,7 @@ pack_pack(ary, fmt) else { c = NUM2INT(from); } - rb_str_cat(res, &c, sizeof(char)); + rb_str_buf_cat(res, &c, sizeof(char)); } break; @@ -570,7 +562,7 @@ pack_pack(ary, fmt) else { s = NUM2INT(from); } - rb_str_cat(res, OFF16(&s), NATINT_LEN(short,2)); + rb_str_buf_cat(res, OFF16(&s), NATINT_LEN(short,2)); } break; @@ -584,7 +576,7 @@ pack_pack(ary, fmt) else { i = NUM2UINT(from); } - rb_str_cat(res, (char*)&i, sizeof(int)); + rb_str_buf_cat(res, (char*)&i, sizeof(int)); } break; @@ -598,7 +590,7 @@ pack_pack(ary, fmt) else { l = NATINT_U32(from); } - rb_str_cat(res, OFF32(&l), NATINT_LEN(long,4)); + rb_str_buf_cat(res, OFF32(&l), NATINT_LEN(long,4)); } break; @@ -612,7 +604,7 @@ pack_pack(ary, fmt) s = NUM2INT(from); } s = htons(s); - rb_str_cat(res, OFF16B(&s), NATINT_LEN(short,2)); + rb_str_buf_cat(res, OFF16B(&s), NATINT_LEN(short,2)); } break; @@ -626,7 +618,7 @@ pack_pack(ary, fmt) l = NATINT_U32(from); } l = htonl(l); - rb_str_cat(res, OFF32B(&l), NATINT_LEN(long,4)); + rb_str_buf_cat(res, OFF32B(&l), NATINT_LEN(long,4)); } break; @@ -640,7 +632,7 @@ pack_pack(ary, fmt) s = NUM2INT(from); } s = htovs(s); - rb_str_cat(res, OFF16(&s), NATINT_LEN(short,2)); + rb_str_buf_cat(res, OFF16(&s), NATINT_LEN(short,2)); } break; @@ -654,7 +646,7 @@ pack_pack(ary, fmt) l = NATINT_U32(from); } l = htovl(l); - rb_str_cat(res, OFF32(&l), NATINT_LEN(long,4)); + rb_str_buf_cat(res, OFF32(&l), NATINT_LEN(long,4)); } break; @@ -674,7 +666,7 @@ pack_pack(ary, fmt) f = (float)NUM2INT(from); break; } - rb_str_cat(res, (char*)&f, sizeof(float)); + rb_str_buf_cat(res, (char*)&f, sizeof(float)); } break; @@ -695,7 +687,7 @@ pack_pack(ary, fmt) break; } f = HTOVF(f,ftmp); - rb_str_cat(res, (char*)&f, sizeof(float)); + rb_str_buf_cat(res, (char*)&f, sizeof(float)); } break; @@ -716,7 +708,7 @@ pack_pack(ary, fmt) break; } d = HTOVD(d,dtmp); - rb_str_cat(res, (char*)&d, sizeof(double)); + rb_str_buf_cat(res, (char*)&d, sizeof(double)); } break; @@ -736,7 +728,7 @@ pack_pack(ary, fmt) d = (double)NUM2INT(from); break; } - rb_str_cat(res, (char*)&d, sizeof(double)); + rb_str_buf_cat(res, (char*)&d, sizeof(double)); } break; @@ -757,7 +749,7 @@ pack_pack(ary, fmt) break; } f = HTONF(f,ftmp); - rb_str_cat(res, (char*)&f, sizeof(float)); + rb_str_buf_cat(res, (char*)&f, sizeof(float)); } break; @@ -778,25 +770,26 @@ pack_pack(ary, fmt) break; } d = HTOND(d,dtmp); - rb_str_cat(res, (char*)&d, sizeof(double)); + rb_str_buf_cat(res, (char*)&d, sizeof(double)); } break; case 'x': grow: while (len >= 10) { - rb_str_cat(res, nul10, 10); + rb_str_buf_cat(res, nul10, 10); len -= 10; } - rb_str_cat(res, nul10, len); + rb_str_buf_cat(res, nul10, len); break; case 'X': shrink: - if (RSTRING(res)->len < len) + plen = RSTRING(res)->len; + if (plen < len) rb_raise(rb_eArgError, "X outside of string"); - RSTRING(res)->len -= len; - RSTRING(res)->ptr[RSTRING(res)->len] = '\0'; + RSTRING(res)->len = plen - len; + RSTRING(res)->ptr[plen - len] = '\0'; break; case '@': @@ -822,7 +815,7 @@ pack_pack(ary, fmt) l = NUM2ULONG(from); } le = uv_to_utf8(buf, l); - rb_str_cat(res, (char*)buf, le); + rb_str_buf_cat(res, (char*)buf, le); } break; @@ -879,8 +872,11 @@ pack_pack(ary, fmt) StringValue(from); t = RSTRING(from)->ptr; } - rb_str_associate(res, from); - rb_str_cat(res, (char*)&t, sizeof(char*)); + if (!associates) { + associates = rb_ary_new(); + } + rb_ary_push(associates, from); + rb_str_buf_cat(res, (char*)&t, sizeof(char*)); } break; @@ -891,13 +887,12 @@ pack_pack(ary, fmt) char c, *bufs, *bufe; from = NEXTFROM; - if (TYPE(from) == T_BIGNUM) { VALUE big128 = rb_uint2big(128); while (TYPE(from) == T_BIGNUM) { from = rb_big_divmod(from, big128); c = NUM2INT(RARRAY(from)->ptr[1]) | 0x80; /* mod */ - rb_str_cat(buf, &c, sizeof(char)); + rb_str_buf_cat(buf, &c, sizeof(char)); from = RARRAY(from)->ptr[0]; /* div */ } } @@ -909,7 +904,7 @@ pack_pack(ary, fmt) while (ul) { c = ((ul & 0x7f) | 0x80); - rb_str_cat(buf, &c, sizeof(char)); + rb_str_buf_cat(buf, &c, sizeof(char)); ul >>= 7; } @@ -922,11 +917,11 @@ pack_pack(ary, fmt) *bufs++ = *bufe; *bufe-- = c; } - rb_str_cat(res, RSTRING(buf)->ptr, RSTRING(buf)->len); + rb_str_buf_cat(res, RSTRING(buf)->ptr, RSTRING(buf)->len); } else { c = 0; - rb_str_cat(res, &c, sizeof(char)); + rb_str_buf_cat(res, &c, sizeof(char)); } } break; @@ -936,6 +931,9 @@ pack_pack(ary, fmt) } } + if (associates) { + rb_str_associate(res, associates); + } return res; } @@ -984,7 +982,7 @@ encodes(str, s, len, type) buff[i++] = padding; } buff[i++] = '\n'; - rb_str_cat(str, buff, i); + rb_str_buf_cat(str, buff, i); } static char hex_table[] = "0123456789ABCDEF"; @@ -1030,7 +1028,7 @@ qpencode(str, from, len) prev = '\n'; } if (i > 1024 - 5) { - rb_str_cat(str, buff, i); + rb_str_buf_cat(str, buff, i); i = 0; } s++; @@ -1040,7 +1038,7 @@ qpencode(str, from, len) buff[i++] = '\n'; } if (i > 0) { - rb_str_cat(str, buff, i); + rb_str_buf_cat(str, buff, i); } } @@ -51,6 +51,7 @@ static enum lex_state { EXPR_BEG, /* ignore newline, +/- is a sign. */ EXPR_END, /* newline significant, +/- is a operator. */ EXPR_ARG, /* newline significant, +/- is a operator. */ + EXPR_CMDARG, /* newline significant, +/- is a operator. */ EXPR_MID, /* newline significant, +/- is a operator. */ EXPR_FNAME, /* ignore newline, no reserved words. */ EXPR_DOT, /* right after `.' or `::', no reserved words. */ @@ -63,32 +64,40 @@ typedef unsigned LONG_LONG stack_type; typedef unsigned long stack_type; #endif -static int cond_nest = 0; static stack_type cond_stack = 0; -#define COND_PUSH do {\ - cond_nest++;\ - cond_stack = (cond_stack<<1)|1;\ +#define COND_PUSH(n) do {\ + cond_stack = (cond_stack<<1)|((n)&1);\ } while(0) -#define COND_POP do {\ - cond_nest--;\ +#define COND_POP() do {\ cond_stack >>= 1;\ } while (0) -#define COND_P() (cond_nest > 0 && (cond_stack&1)) +#define COND_LEXPOP() do {\ + int last = COND_P();\ + cond_stack >>= 1;\ + if (last) cond_stack |= 1;\ +} while (0) +#define COND_P() (cond_stack&1) static stack_type cmdarg_stack = 0; -#define CMDARG_PUSH do {\ - cmdarg_stack = (cmdarg_stack<<1)|1;\ +#define CMDARG_PUSH(n) do {\ + cmdarg_stack = (cmdarg_stack<<1)|((n)&1);\ } while(0) -#define CMDARG_POP do {\ +#define CMDARG_POP() do {\ + cmdarg_stack >>= 1;\ +} while (0) +#define CMDARG_LEXPOP() do {\ + int last = CMDARG_P();\ cmdarg_stack >>= 1;\ + if (last) cmdarg_stack |= 1;\ } while (0) -#define CMDARG_P() (cmdarg_stack && (cmdarg_stack&1)) +#define CMDARG_P() (cmdarg_stack&1) static int class_nest = 0; static int in_single = 0; static int in_def = 0; static int compile_for_eval = 0; static ID cur_mid = 0; +static ID last_id = 0; static NODE *cond(); static NODE *logop(); @@ -104,9 +113,11 @@ static NODE *block_append(); static NODE *list_append(); static NODE *list_concat(); static NODE *arg_concat(); +static NODE *arg_prepend(); static NODE *call_op(); static int in_defined = 0; +static NODE *ret_args(); static NODE *arg_blk_pass(); static NODE *new_call(); static NODE *new_fcall(); @@ -133,6 +144,7 @@ static int dyna_in_block(); static void top_local_init(); static void top_local_setup(); + %} %union { @@ -199,7 +211,7 @@ static void top_local_setup(); %type <val> literal numeric %type <node> compstmt stmts stmt expr arg primary command command_call method_call %type <node> if_tail opt_else case_body cases rescue exc_list exc_var ensure -%type <node> args ret_args when_args call_args paren_args opt_paren_args +%type <node> args when_args call_args call_args2 open_args paren_args opt_paren_args %type <node> command_args aref_args opt_block_arg block_arg var_ref %type <node> mrhs mrhs_basic superclass block_call block_command %type <node> f_arglist f_args f_optarg f_opt f_block_arg opt_f_block_arg @@ -228,9 +240,11 @@ static void top_local_setup(); %token <id> tOP_ASGN /* +=, -= etc. */ %token tASSOC /* => */ %token tLPAREN /* ( */ +%token tLPAREN_ARG /* ( */ %token tRPAREN /* ) */ %token tLBRACK /* [ */ %token tLBRACE /* { */ +%token tLBRACE_ARG /* { */ %token tSTAR /* * */ %token tAMPER /* & */ %token tSYMBEG @@ -420,19 +434,19 @@ stmt : kALIAS fitem {lex_state = EXPR_FNAME;} fitem } | expr -expr : kRETURN ret_args +expr : kRETURN call_args { if (!compile_for_eval && !in_def && !in_single) yyerror("return appeared outside of method"); - $$ = NEW_RETURN($2); + $$ = NEW_RETURN(ret_args($2)); } - | kBREAK ret_args + | kBREAK call_args { - $$ = NEW_BREAK($2); + $$ = NEW_BREAK(ret_args($2)); } - | kNEXT ret_args + | kNEXT call_args { - $$ = NEW_NEXT($2); + $$ = NEW_NEXT(ret_args($2)); } | command_call | expr kAND expr @@ -469,7 +483,7 @@ block_command : block_call $$ = new_call($1, $3, $4); } -command : operation command_args +command : operation command_args { $$ = new_fcall($1, $2); fixpos($$, $2); @@ -493,9 +507,9 @@ command : operation command_args $$ = new_super($2); fixpos($$, $2); } - | kYIELD ret_args + | kYIELD call_args { - $$ = NEW_YIELD($2); + $$ = NEW_YIELD(ret_args($2)); fixpos($$, $2); } @@ -1001,9 +1015,90 @@ call_args : command } | block_arg -command_args : {CMDARG_PUSH;} call_args +call_args2 : arg ',' args opt_block_arg + { + $$ = arg_blk_pass(list_append(NEW_LIST($1),$3), $4); + } + | arg ',' tSTAR arg opt_block_arg + { + value_expr($1); + value_expr($4); + $$ = arg_concat(NEW_LIST($1), $4); + $$ = arg_blk_pass($$, $5); + } + | arg ',' args ',' tSTAR arg opt_block_arg + { + value_expr($1); + value_expr($6); + $$ = arg_concat(list_append($1,$3), $6); + $$ = arg_blk_pass($$, $7); + } + | assocs opt_block_arg + { + $$ = NEW_LIST(NEW_HASH($1)); + $$ = arg_blk_pass($$, $2); + } + | assocs ',' tSTAR arg opt_block_arg + { + value_expr($4); + $$ = arg_concat(NEW_LIST(NEW_HASH($1)), $4); + $$ = arg_blk_pass($$, $5); + } + | arg ',' assocs opt_block_arg + { + $$ = list_append(NEW_LIST($1), NEW_HASH($3)); + $$ = arg_blk_pass($$, $4); + } + | arg ',' args ',' assocs opt_block_arg + { + value_expr($1); + value_expr($6); + $$ = list_append(list_append($1,$3), NEW_HASH($5)); + $$ = arg_blk_pass($$, $6); + } + | arg ',' assocs ',' tSTAR arg opt_block_arg + { + value_expr($1); + value_expr($6); + $$ = arg_concat(list_append(NEW_LIST($1), NEW_HASH($3)), $6); + $$ = arg_blk_pass($$, $7); + } + | arg ',' args ',' assocs ',' tSTAR arg opt_block_arg + { + value_expr($1); + value_expr($8); + $$ = arg_concat(list_append(list_append(NEW_LIST($1), $3), NEW_HASH($5)), $8); + $$ = arg_blk_pass($$, $9); + } + | tSTAR arg opt_block_arg + { + value_expr($2); + $$ = arg_blk_pass(NEW_RESTARGS($2), $3); + } + | block_arg + +command_args : { + $<num>$ = cmdarg_stack; + CMDARG_PUSH(1); + } + open_args + { + /* CMDARG_POP() */ + cmdarg_stack = $<num>1; + $$ = $2; + } + +open_args : call_args + | tLPAREN_ARG ')' + { + rb_warning("%s (...) interpreted as method call", + rb_id2name(last_id)); + $$ = 0; + } + | tLPAREN_ARG call_args2 ')' { - CMDARG_POP; + rb_warning("%s (...) interpreted as method call", + rb_id2name(last_id)); $$ = $2; } @@ -1053,20 +1148,6 @@ mrhs_basic : args ',' arg $$ = $2; } -ret_args : call_args - { - $$ = $1; - if ($1) { - if (nd_type($1) == NODE_ARRAY && - $1->nd_next == 0) { - $$ = $1->nd_head; - } - else if (nd_type($1) == NODE_BLOCK_PASS) { - rb_compile_error("block argument should not be given"); - } - } - } - primary : literal { $$ = NEW_LIT($1); @@ -1104,6 +1185,11 @@ primary : literal } fixpos($$, $2); } + | tLPAREN_ARG expr ')' + { + rb_warning("%s (...) interpreted as command call", rb_id2name(last_id)); + $$ = $2; + } | tLPAREN compstmt ')' { $$ = $2; @@ -1140,10 +1226,10 @@ primary : literal yyerror("return appeared outside of method"); $$ = NEW_RETURN(0); } - | kYIELD '(' ret_args ')' + | kYIELD '(' call_args ')' { value_expr($3); - $$ = NEW_YIELD($3); + $$ = NEW_YIELD(ret_args($3)); } | kYIELD '(' ')' { @@ -1191,7 +1277,7 @@ primary : literal $$ = NEW_UNLESS(cond($2), $4, $5); fixpos($$, $2); } - | kWHILE {COND_PUSH;} expr do {COND_POP;} + | kWHILE {COND_PUSH(1);} expr do {COND_POP();} compstmt kEND { @@ -1199,7 +1285,7 @@ primary : literal $$ = NEW_WHILE(cond($3), $6, 1); fixpos($$, $3); } - | kUNTIL {COND_PUSH;} expr do {COND_POP;} + | kUNTIL {COND_PUSH(1);} expr do {COND_POP();} compstmt kEND { @@ -1219,7 +1305,7 @@ primary : literal { $$ = $3; } - | kFOR block_var kIN {COND_PUSH;} expr do {COND_POP;} + | kFOR block_var kIN {COND_PUSH(1);} expr do {COND_POP();} compstmt kEND { @@ -1407,6 +1493,16 @@ do_block : kDO_BLOCK fixpos($$, $3?$3:$4); dyna_pop($<vars>2); } + | tLBRACE_ARG {$<vars>$ = dyna_push();} + opt_block_var + compstmt + '}' + { + $$ = NEW_ITER($3, 0, $4); + fixpos($$, $3?$3:$4); + dyna_pop($<vars>2); + } + block_call : command do_block { @@ -1913,6 +2009,7 @@ yyerror(msg) } static int heredoc_end; +static int command_start = Qtrue; int ruby_in_compile = 0; int ruby__end__seen; @@ -1958,9 +2055,9 @@ yycompile(f, line) ruby_debug_lines = 0; compile_for_eval = 0; ruby_in_compile = 0; - cond_nest = 0; cond_stack = 0; cmdarg_stack = 0; + command_start = 1; class_nest = 0; in_single = 0; in_def = 0; @@ -2711,13 +2808,6 @@ here_document(term, indent) lex_pbeg = lex_p = RSTRING(line)->ptr; lex_pend = lex_p + RSTRING(line)->len; -#if 0 - if (indent) { - while (*lex_p && *lex_p == '\t') { - lex_p++; - } - } -#endif retry: switch (parse_string(term, '\n', '\n')) { case tSTRING: @@ -2791,13 +2881,18 @@ arg_ambiguous() double strtod (); #endif +#define IS_ARG() (lex_state == EXPR_ARG || lex_state == EXPR_CMDARG) + static int yylex() { register int c; int space_seen = 0; + int cmd_state; struct kwtable *kw; + cmd_state = command_start; + command_start = Qfalse; retry: switch (c = nextc()) { case '\0': /* NUL */ @@ -2827,6 +2922,7 @@ yylex() default: break; } + command_start = Qtrue; lex_state = EXPR_BEG; return '\n'; @@ -2846,7 +2942,7 @@ yylex() return tOP_ASGN; } pushback(c); - if (lex_state == EXPR_ARG && space_seen && !ISSPACE(c)){ + if (IS_ARG() && space_seen && !ISSPACE(c)){ rb_warning("`*' interpreted as argument prefix"); c = tSTAR; } @@ -2913,7 +3009,7 @@ yylex() c = nextc(); if (c == '<' && lex_state != EXPR_END && lex_state != EXPR_CLASS && - (lex_state != EXPR_ARG || space_seen)) { + (!IS_ARG() || space_seen)) { int c2 = nextc(); int indent = 0; if (c2 == '-') { @@ -2980,7 +3076,7 @@ yylex() rb_compile_error("incomplete character syntax"); return 0; } - if (lex_state == EXPR_ARG && ISSPACE(c)){ + if (IS_ARG() && ISSPACE(c)){ pushback(c); lex_state = EXPR_BEG; return '?'; @@ -3009,8 +3105,8 @@ yylex() return tOP_ASGN; } pushback(c); - if (lex_state == EXPR_ARG && space_seen && !ISSPACE(c)){ - rb_warning("`&' interpreted as argument prefix"); + if (IS_ARG() && space_seen && !ISSPACE(c)){ + rb_warning("`&' interpeted as argument prefix"); c = tAMPER; } else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { @@ -3054,8 +3150,8 @@ yylex() return tOP_ASGN; } if (lex_state == EXPR_BEG || lex_state == EXPR_MID || - (lex_state == EXPR_ARG && space_seen && !ISSPACE(c))) { - if (lex_state == EXPR_ARG) arg_ambiguous(); + (IS_ARG() && space_seen && !ISSPACE(c))) { + if (IS_ARG()) arg_ambiguous(); lex_state = EXPR_BEG; pushback(c); if (ISDIGIT(c)) { @@ -3083,8 +3179,8 @@ yylex() return tOP_ASGN; } if (lex_state == EXPR_BEG || lex_state == EXPR_MID || - (lex_state == EXPR_ARG && space_seen && !ISSPACE(c))) { - if (lex_state == EXPR_ARG) arg_ambiguous(); + (IS_ARG() && space_seen && !ISSPACE(c))) { + if (IS_ARG()) arg_ambiguous(); lex_state = EXPR_BEG; pushback(c); if (ISDIGIT(c)) { @@ -3276,13 +3372,9 @@ yylex() case ']': case '}': - lex_state = EXPR_END; - return c; - case ')': - if (cond_nest > 0) { - cond_stack >>= 1; - } + COND_LEXPOP(); + CMDARG_LEXPOP(); lex_state = EXPR_END; return c; @@ -3290,7 +3382,7 @@ yylex() c = nextc(); if (c == ':') { if (lex_state == EXPR_BEG || lex_state == EXPR_MID || - (lex_state == EXPR_ARG && space_seen)) { + (IS_ARG() && space_seen)) { lex_state = EXPR_BEG; return tCOLON3; } @@ -3315,7 +3407,7 @@ yylex() return tOP_ASGN; } pushback(c); - if (lex_state == EXPR_ARG && space_seen) { + if (IS_ARG() && space_seen) { if (!ISSPACE(c)) { arg_ambiguous(); return parse_regx('/', '/'); @@ -3333,8 +3425,9 @@ yylex() pushback(c); return '^'; - case ',': case ';': + command_start = Qtrue; + case ',': lex_state = EXPR_BEG; return c; @@ -3348,15 +3441,21 @@ yylex() return '~'; case '(': - if (cond_nest > 0) { - cond_stack = (cond_stack<<1)|0; - } + command_start = Qtrue; if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { c = tLPAREN; } - else if (lex_state == EXPR_ARG && space_seen) { - rb_warning("%s (...) interpreted as method call", tok()); + else if (space_seen) { + if (lex_state == EXPR_CMDARG) { + c = tLPAREN_ARG; + } + else if (lex_state == EXPR_ARG) { + rb_warning("%s (...) interpreted as method call", tok()); + c = tLPAREN_ARG; + } } + COND_PUSH(0); + CMDARG_PUSH(0); lex_state = EXPR_BEG; return c; @@ -3375,15 +3474,23 @@ yylex() else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { c = tLBRACK; } - else if (lex_state == EXPR_ARG && space_seen) { + else if (IS_ARG() && space_seen) { c = tLBRACK; } lex_state = EXPR_BEG; + COND_PUSH(0); + CMDARG_PUSH(0); return c; case '{': - if (lex_state != EXPR_END && lex_state != EXPR_ARG) - c = tLBRACE; + if (!IS_ARG()) { + if (lex_state != EXPR_END) + c = tLBRACE; + if (space_seen && CMDARG_P()) + c = tLBRACE_ARG; + } + COND_PUSH(0); + CMDARG_PUSH(0); lex_state = EXPR_BEG; return c; @@ -3446,7 +3553,7 @@ yylex() yylval.id = '%'; return tOP_ASGN; } - if (lex_state == EXPR_ARG && space_seen && !ISSPACE(c)) { + if (IS_ARG() && space_seen && !ISSPACE(c)) { goto quotation; } lex_state = EXPR_BEG; @@ -3608,7 +3715,8 @@ yylex() } if (kw->id[0] == kDO) { if (COND_P()) return kDO_COND; - if (CMDARG_P()) return kDO_BLOCK; + if (CMDARG_P() && state != EXPR_CMDARG && state != EXPR_ARG) + return kDO_BLOCK; return kDO; } if (state == EXPR_BEG) @@ -3626,12 +3734,8 @@ yylex() } else { if (lex_state == EXPR_FNAME) { -#if 0 - if ((c = nextc()) == '=' && !peek('=') && !peek('~') && !peek('>')) { -#else if ((c = nextc()) == '=' && !peek('~') && !peek('>') && (!peek('=') || lex_p + 1 < lex_pend && lex_p[1] == '>')) { -#endif result = tIDENTIFIER; tokadd(c); } @@ -3648,15 +3752,19 @@ yylex() } if (lex_state == EXPR_BEG || lex_state == EXPR_DOT || - lex_state == EXPR_ARG) { - lex_state = EXPR_ARG; + lex_state == EXPR_ARG || + lex_state == EXPR_CMDARG) { + if (cmd_state) + lex_state = EXPR_CMDARG; + else + lex_state = EXPR_ARG; } else { lex_state = EXPR_END; } } tokfix(); - yylval.id = rb_intern(tok()); + last_id = yylval.id = rb_intern(tok()); return result; } } @@ -4549,6 +4657,21 @@ logop(type, left, right) } static NODE * +ret_args(node) + NODE *node; +{ + if (node) { + if (nd_type(node) == NODE_ARRAY && node->nd_next == 0) { + node = node->nd_head; + } + else if (nd_type(node) == NODE_BLOCK_PASS) { + rb_compile_error("block argument should not be given"); + } + } + return node; +} + +static NODE * arg_blk_pass(node1, node2) NODE *node1; NODE *node2; @@ -4561,6 +4684,27 @@ arg_blk_pass(node1, node2) } static NODE* +arg_prepend(node1, node2) + NODE *node1, *node2; +{ + switch (nodetype(node2)) { + case NODE_ARRAY: + return list_concat(NEW_LIST(node1), node2); + + case NODE_RESTARGS: + return arg_concat(node1, node2->nd_head); + + case NODE_BLOCK_PASS: + node2->nd_body = arg_prepend(node1, node2->nd_body); + return node2; + + default: + rb_bug("unknown nodetype(%d) for arg_prepend"); + } + return 0; /* not reached */ +} + +static NODE* new_call(r,m,a) NODE *r; ID m; @@ -13,7 +13,7 @@ #include "ruby.h" VALUE rb_cRange; -static ID id_cmp, id_beg, id_end, id_excl; +static ID id_cmp, id_succ, id_beg, id_end, id_excl; #define EXCL(r) RTEST(rb_ivar_get((r), id_excl)) #define SET_EXCL(r,v) rb_ivar_set((r), id_excl, (v)?Qtrue:Qfalse) @@ -23,6 +23,9 @@ range_check(args) VALUE *args; { rb_funcall(args[0], id_cmp, 1, args[1]); + if (!FIXNUM_P(args[0]) && !rb_obj_is_kind_of(args[0], rb_cNumeric)) { + rb_funcall(args[0], id_succ, 0, 0); + } return Qnil; } @@ -103,6 +106,49 @@ range_eq(range, obj) return Qtrue; } +static int +r_eq(a,b) + VALUE a, b; +{ + VALUE r; + + if (a == b) return Qtrue; + + if (rb_funcall(a, id_cmp, 1, b) == INT2FIX(0)) + return Qtrue; + return Qfalse; +} + +static int +r_lt(a,b) + VALUE a, b; +{ + VALUE r = rb_funcall(a, id_cmp, 1, b); + + if (NUM2LONG(r) < 0) return Qtrue; + return Qfalse; +} + +static int +r_le(a,b) + VALUE a, b; +{ + VALUE r = rb_funcall(a, id_cmp, 1, b); + + if (NUM2LONG(r) <= 0) return Qtrue; + return Qfalse; +} + +static int +r_gt(a,b) + VALUE a, b; +{ + VALUE r = rb_funcall(a, id_cmp, 1, b); + + if (NUM2LONG(r) > 0) return Qtrue; + return Qfalse; +} + static VALUE range_eqq(range, obj) VALUE range, obj; @@ -123,14 +169,12 @@ range_eqq(range, obj) } return Qfalse; } - else if (RTEST(rb_funcall(beg, rb_intern("<="), 1, obj))) { + else if (r_le(beg, obj)) { if (EXCL(range)) { - if (RTEST(rb_funcall(end, rb_intern(">"), 1, obj))) - return Qtrue; + if (r_lt(obj, end)) return Qtrue; } else { - if (RTEST(rb_funcall(end, rb_intern(">="), 1, obj))) - return Qtrue; + if (r_le(obj, end)) return Qtrue; } } return Qfalse; @@ -169,22 +213,19 @@ range_each(range) } else { /* generic each */ VALUE v = b; - ID succ = rb_intern("succ"); if (EXCL(range)) { - while (RTEST(rb_funcall(v, '<', 1, e))) { - if (rb_equal(v, e)) break; + while (r_lt(v, e)) { + if (r_eq(v, e)) break; rb_yield(v); - v = rb_funcall(v, succ, 0, 0); + v = rb_funcall(v, id_succ, 0, 0); } } else { - ID le = rb_intern("<="); - - while (RTEST(rb_funcall(v, le, 1, e))) { + while (r_le(v, e)) { rb_yield(v); - if (rb_equal(v, e)) break; - v = rb_funcall(v, succ, 0, 0); + if (r_eq(v, e)) break; + v = rb_funcall(v, id_succ, 0, 0); } } } @@ -324,7 +365,7 @@ range_length(range) beg = rb_ivar_get(range, id_beg); end = rb_ivar_get(range, id_end); - if (RTEST(rb_funcall(beg, '>', 1, end))) { + if (r_gt(beg, end)) { return INT2FIX(0); } if (FIXNUM_P(beg) && FIXNUM_P(end)) { @@ -349,6 +390,25 @@ range_length(range) return size; } +static VALUE +range_member(range, val) + VALUE range, val; +{ + VALUE beg, end; + + beg = rb_ivar_get(range, id_beg); + end = rb_ivar_get(range, id_end); + + if (r_lt(beg, val)) return Qtrue; + if (EXCL(range)) { + if (r_lt(val, end)) return Qtrue; + } + else { + if (r_le(val, end)) return Qtrue; + } + return Qfalse; +} + void Init_Range() { @@ -369,8 +429,11 @@ Init_Range() rb_define_method(rb_cRange, "length", range_length, 0); rb_define_method(rb_cRange, "size", range_length, 0); + rb_define_method(rb_cRange, "member?", range_member, 1); + rb_define_method(rb_cRange, "include?", range_member, 1); id_cmp = rb_intern("<=>"); + id_succ = rb_intern("succ"); id_beg = rb_intern("begin"); id_end = rb_intern("end"); id_excl = rb_intern("excl"); @@ -224,51 +224,51 @@ rb_reg_expr_str(str, s, len) p++; } if (!need_escape) { - rb_str_cat(str, s, len); + rb_str_buf_cat(str, s, len); } else { p = s; while (p<pend) { if (*p == '/') { char c = '\\'; - rb_str_cat(str, &c, 1); - rb_str_cat(str, p, 1); + rb_str_buf_cat(str, &c, 1); + rb_str_buf_cat(str, p, 1); } else if (ismbchar(*p)) { - rb_str_cat(str, p, mbclen(*p)); + rb_str_buf_cat(str, p, mbclen(*p)); p += mbclen(*p); continue; } else if (ISPRINT(*p)) { - rb_str_cat(str, p, 1); + rb_str_buf_cat(str, p, 1); } else { char b[8]; switch (*p) { case '\r': - rb_str_cat(str, "\\r", 2); + rb_str_buf_cat(str, "\\r", 2); break; case '\n': - rb_str_cat(str, "\\n", 2); + rb_str_buf_cat(str, "\\n", 2); break; case '\t': - rb_str_cat(str, "\\t", 2); + rb_str_buf_cat(str, "\\t", 2); break; case '\f': - rb_str_cat(str, "\\f", 2); + rb_str_buf_cat(str, "\\f", 2); break; case 007: - rb_str_cat(str, "\\a", 2); + rb_str_buf_cat(str, "\\a", 2); break; case 013: - rb_str_cat(str, "\\v", 2); + rb_str_buf_cat(str, "\\v", 2); break; case 033: - rb_str_cat(str, "\\e", 2); + rb_str_buf_cat(str, "\\e", 2); break; default: sprintf(b, "\\%03o", *p & 0377); - rb_str_cat(str, b, 4); + rb_str_buf_cat(str, b, 4); break; } } @@ -283,35 +283,35 @@ rb_reg_desc(s, len, re) int len; VALUE re; { - VALUE str = rb_str_new2("/"); + VALUE str = rb_str_buf_new2("/"); rb_reg_expr_str(str, s, len); - rb_str_cat2(str, "/"); + rb_str_buf_cat2(str, "/"); if (re) { rb_reg_check(re); /* /p is obsolete; to be removed */ if ((RREGEXP(re)->ptr->options & RE_OPTION_POSIXLINE) == RE_OPTION_POSIXLINE) - rb_str_cat2(str, "p"); + rb_str_buf_cat2(str, "p"); else if (RREGEXP(re)->ptr->options & RE_OPTION_MULTILINE) - rb_str_cat2(str, "m"); + rb_str_buf_cat2(str, "m"); if (RREGEXP(re)->ptr->options & RE_OPTION_IGNORECASE) - rb_str_cat2(str, "i"); + rb_str_buf_cat2(str, "i"); if (RREGEXP(re)->ptr->options & RE_OPTION_EXTENDED) - rb_str_cat2(str, "x"); + rb_str_buf_cat2(str, "x"); if (FL_TEST(re, KCODE_FIXED)) { switch ((RBASIC(re)->flags & KCODE_MASK)) { case KCODE_NONE: - rb_str_cat2(str, "n"); + rb_str_buf_cat2(str, "n"); break; case KCODE_EUC: - rb_str_cat2(str, "e"); + rb_str_buf_cat2(str, "e"); break; case KCODE_SJIS: - rb_str_cat2(str, "s"); + rb_str_buf_cat2(str, "s"); break; case KCODE_UTF8: - rb_str_cat2(str, "u"); + rb_str_buf_cat2(str, "u"); break; } } @@ -1171,8 +1171,13 @@ rb_reg_regsub(str, src, regs) } if (c != '\\' || s == e) continue; - if (!val) val = rb_str_new(p, ss-p); - else rb_str_cat(val, p, ss-p); + if (!val) { + val = rb_str_buf_new(ss-p); + rb_str_buf_cat(val, p, ss-p); + } + else { + rb_str_buf_cat(val, p, ss-p); + } c = *s++; p = s; @@ -1186,11 +1191,11 @@ rb_reg_regsub(str, src, regs) break; case '`': - rb_str_cat(val, RSTRING(src)->ptr, BEG(0)); + rb_str_buf_cat(val, RSTRING(src)->ptr, BEG(0)); continue; case '\'': - rb_str_cat(val, RSTRING(src)->ptr+END(0), RSTRING(src)->len-END(0)); + rb_str_buf_cat(val, RSTRING(src)->ptr+END(0), RSTRING(src)->len-END(0)); continue; case '+': @@ -1200,24 +1205,29 @@ rb_reg_regsub(str, src, regs) break; case '\\': - rb_str_cat(val, s-1, 1); + rb_str_buf_cat(val, s-1, 1); continue; default: - rb_str_cat(val, s-2, 2); + rb_str_buf_cat(val, s-2, 2); continue; } if (no >= 0) { if (no >= regs->num_regs) continue; if (BEG(no) == -1) continue; - rb_str_cat(val, RSTRING(src)->ptr+BEG(no), END(no)-BEG(no)); + rb_str_buf_cat(val, RSTRING(src)->ptr+BEG(no), END(no)-BEG(no)); } } if (p < e) { - if (!val) val = rb_str_new(p, e-p); - else rb_str_cat(val, p, e-p); + if (!val) { + val = rb_str_buf_new(e-p); + rb_str_buf_cat(val, p, e-p); + } + else { + rb_str_buf_cat(val, p, e-p); + } } if (!val) return str; @@ -370,6 +370,7 @@ enum regexpcode duplicate, /* Match a duplicate of something remembered. Followed by one byte containing the index of the memory register. */ + fail, /* always fails. */ wordchar, /* Matches any word-constituent character. */ notwordchar, /* Matches any char that is not a word-constituent. */ wordbeg, /* Succeeds if at word beginning. */ @@ -2246,32 +2247,23 @@ re_compile_pattern(pattern, size, bufp) case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - { - const char *p_save; - - PATUNFETCH; - p_save = p; + PATUNFETCH; + p0 = p; - had_mbchar = 0; + had_mbchar = 0; + c1 = 0; + GET_UNSIGNED_NUMBER(c1); + if (!ISDIGIT(c)) PATUNFETCH; + + if (9 < c1 && c1 >= regnum) { + /* need to get octal */ + c = scan_oct(p0, 3, &numlen) & 0xff; + p = p0 + numlen; c1 = 0; - GET_UNSIGNED_NUMBER(c1); - if (!ISDIGIT(c)) PATUNFETCH; - - if (c1 >= regnum) { - /* need to get octal */ - p = p_save; - c = scan_oct(p_save, 3, &numlen) & 0xff; - p = p_save + numlen; - c1 = 0; - had_num_literal = 1; - goto numeric_char; - } + had_num_literal = 1; + goto numeric_char; } - /* Can't back reference to a subexpression if inside of it. */ - for (stackt = stackp - 2; stackt > stackb; stackt -= 5) - if (*stackt == c1) - goto normal_char; laststart = b; BUFPUSH(duplicate); BUFPUSH(c1); @@ -3736,11 +3728,16 @@ re_match(bufp, string_arg, size, pos, regs) int regno = *p++; /* Get which register to match against */ register unsigned char *d2, *dend2; - if (IS_ACTIVE(reg_info[regno])) break; +#if 0 + /* Check if corresponding group is still open */ + if (IS_ACTIVE(reg_info[regno])) goto fail; /* Where in input to try to start matching. */ d2 = regstart[regno]; - if (REG_UNSET(d2)) break; +#else + d2 = IS_ACTIVE(reg_info[regno])?old_regstart[regno]:regstart[regno]; +#endif + if (REG_UNSET(d2)) goto fail; /* Where to stop matching; if both the place to start and the place to stop matching are in the same string, then @@ -3748,7 +3745,7 @@ re_match(bufp, string_arg, size, pos, regs) the end of the first string. */ dend2 = regend[regno]; - if (REG_UNSET(dend2)) break; + if (REG_UNSET(dend2)) goto fail; for (;;) { /* At end of register contents => success */ if (d2 == dend2) break; @@ -681,6 +681,11 @@ proc_options(argc, argv) ruby_show_copyright(); } + if (rb_safe_level() >= 4) { + OBJ_TAINT(rb_argv); + OBJ_TAINT(rb_load_path); + } + if (!e_script && argc == 0) { /* no more args */ if (verbose) exit(0); script = "-"; @@ -726,6 +731,11 @@ proc_options(argc, argv) process_sflag(); xflag = 0; + + if (rb_safe_level() >= 4) { + FL_UNSET(rb_argv, FL_TAINT); + FL_UNSET(rb_load_path, FL_TAINT); + } } extern int ruby__end__seen; @@ -111,6 +111,7 @@ typedef unsigned long ID; #define FIXNUM_FLAG 0x01 #define INT2FIX(i) ((VALUE)(((long)(i))<<1 | FIXNUM_FLAG)) +#define LONG2FIX(i) INT2FIX(i) #define rb_fix_new(v) INT2FIX(v) VALUE rb_int2inum _((long)); #define INT2NUM(v) rb_int2inum(v) @@ -28,6 +28,7 @@ VALUE rb_cString; #define STR_NO_ORIG FL_USER2 +#define STR_ASSOC FL_USER3 VALUE rb_fs; @@ -132,6 +133,40 @@ rb_str_new4(orig) } } +#define STR_BUF_MIN_SIZE 128 + +VALUE +rb_str_buf_new(capa) + long capa; +{ + NEWOBJ(str, struct RString); + OBJSETUP(str, rb_cString, T_STRING); + + FL_SET(str, STR_NO_ORIG); + if (capa < STR_BUF_MIN_SIZE) + capa = STR_BUF_MIN_SIZE; + str->ptr = 0; + str->len = 0; + str->orig = LONG2FIX(capa); + str->ptr = ALLOC_N(char, capa+1); + str->ptr[0] = '\0'; + + return (VALUE)str; +} + +VALUE +rb_str_buf_new2(ptr) + const char *ptr; +{ + VALUE str; + long len = strlen(ptr); + + str = rb_str_buf_new(len + STR_BUF_MIN_SIZE); + rb_str_cat(str, ptr, len); + + return str; +} + VALUE rb_str_to_str(str) VALUE str; @@ -176,7 +211,7 @@ rb_str_associate(str, add) rb_str_modify(str); } RSTRING(str)->orig = rb_ary_new(); - FL_SET(str, STR_NO_ORIG); + FL_SET(str, STR_NO_ORIG|STR_ASSOC); } rb_ary_push(RSTRING(str)->orig, add); } @@ -185,7 +220,7 @@ VALUE rb_str_associated(str) VALUE str; { - if (!FL_TEST(str, STR_NO_ORIG)) { + if (!FL_TEST(str, STR_NO_ORIG|STR_ASSOC)) { return Qfalse; } return RSTRING(str)->orig; @@ -443,27 +478,69 @@ rb_str_resize(str, len) } VALUE +rb_str_buf_cat(str, ptr, len) + VALUE str; + const char *ptr; + long len; +{ + long i, capa, total; + + if (RSTRING(str)->orig == 0) { + capa = RSTRING(str)->len; + FL_SET(str, STR_NO_ORIG); + } + else { + capa = FIX2LONG(RSTRING(str)->orig); + } + + total = RSTRING(str)->len+len; + if (capa <= total) { + while (total > capa) { + capa = (capa + 1) * 2; + } + REALLOC_N(RSTRING(str)->ptr, char, capa+1); + RSTRING(str)->orig = LONG2FIX(capa); + } + memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); + RSTRING(str)->len = total; + RSTRING(str)->ptr[total] = '\0'; /* sentinel */ + + return str; +} + +VALUE +rb_str_buf_cat2(str, ptr) + VALUE str; + const char *ptr; +{ + return rb_str_buf_cat(str, ptr, strlen(ptr)); +} + +VALUE rb_str_cat(str, ptr, len) VALUE str; const char *ptr; long len; { - if (len > 0) { - int poffset = -1; + long i, capa; - rb_str_modify(str); - if (RSTRING(str)->ptr <= ptr && - ptr < RSTRING(str)->ptr + RSTRING(str)->len) { - poffset = ptr - RSTRING(str)->ptr; + rb_str_modify(str); + if (len > 0) { + if (RSTRING(str)->orig == 0 || + (FL_TEST(str, STR_NO_ORIG) && !FL_TEST(str, STR_ASSOC))) { + 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+1); if (ptr) { - if (poffset >= 0) ptr = RSTRING(str)->ptr + poffset; memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); } + else { + MEMZERO(RSTRING(str)->ptr + RSTRING(str)->len, char, len); + } RSTRING(str)->len += len; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */ } + return str; } @@ -476,14 +553,61 @@ rb_str_cat2(str, ptr) } VALUE -rb_str_append(str1, str2) - VALUE str1, str2; +rb_str_buf_append(str, str2) + VALUE str, str2; { + long i, capa, len; + + if (RSTRING(str)->orig == 0) { + capa = RSTRING(str)->len; + FL_SET(str, STR_NO_ORIG); + } + else { + capa = FIX2LONG(RSTRING(str)->orig); + } + + len = RSTRING(str)->len+RSTRING(str2)->len; + if (capa <= len) { + while (len > capa) { + capa = (capa + 1) * 2; + } + REALLOC_N(RSTRING(str)->ptr, char, capa+1); + RSTRING(str)->orig = LONG2FIX(capa); + } + memcpy(RSTRING(str)->ptr + RSTRING(str)->len, + RSTRING(str2)->ptr, RSTRING(str2)->len); + RSTRING(str)->len += RSTRING(str2)->len; + RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */ + + return str; +} + +VALUE +rb_str_append(str, str2) + VALUE str, str2; +{ + long i, capa, len; + StringValue(str2); - str1 = rb_str_cat(str1, RSTRING(str2)->ptr, RSTRING(str2)->len); - OBJ_INFECT(str1, str2); + rb_str_modify(str); + len = RSTRING(str)->len+RSTRING(str2)->len; + if (len > 0) { + if (RSTRING(str)->orig == 0 || + (FL_TEST(str, STR_NO_ORIG) && !FL_TEST(str, STR_ASSOC))) { + rb_str_buf_append(str, str2); + OBJ_INFECT(str, str2); + + return str; + } + REALLOC_N(RSTRING(str)->ptr, char, len+1); + memcpy(RSTRING(str)->ptr + RSTRING(str)->len, + RSTRING(str2)->ptr, RSTRING(str2)->len); + RSTRING(str)->len += RSTRING(str2)->len; + RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */ + } + OBJ_INFECT(str, str2); - return str1; + return str; } VALUE @@ -998,6 +1122,7 @@ rb_str_update(str, beg, len, val) } RSTRING(str)->len += RSTRING(val)->len - len; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; + OBJ_INFECT(str, val); } static VALUE rb_str_sub_bang _((int, VALUE*, VALUE)); @@ -1518,7 +1643,7 @@ rb_str_inspect(str) VALUE str; { char *p, *pend; - VALUE result = rb_str_new2("\""); + VALUE result = rb_str_buf_new2("\""); char s[5]; p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len; @@ -1526,51 +1651,51 @@ rb_str_inspect(str) char c = *p++; if (ismbchar(c) && p < pend) { int len = mbclen(c); - rb_str_cat(result, p - 1, len); + rb_str_buf_cat(result, p - 1, len); p += len - 1; } else if (c == '"'|| c == '\\') { s[0] = '\\'; s[1] = c; - rb_str_cat(result, s, 2); + rb_str_buf_cat(result, s, 2); } else if (ISPRINT(c)) { s[0] = c; - rb_str_cat(result, s, 1); + rb_str_buf_cat(result, s, 1); } else if (c == '\n') { s[0] = '\\'; s[1] = 'n'; - rb_str_cat(result, s, 2); + rb_str_buf_cat(result, s, 2); } else if (c == '\r') { s[0] = '\\'; s[1] = 'r'; - rb_str_cat(result, s, 2); + rb_str_buf_cat(result, s, 2); } else if (c == '\t') { s[0] = '\\'; s[1] = 't'; - rb_str_cat(result, s, 2); + rb_str_buf_cat(result, s, 2); } else if (c == '\f') { s[0] = '\\'; s[1] = 'f'; - rb_str_cat(result, s, 2); + rb_str_buf_cat(result, s, 2); } else if (c == '\013') { s[0] = '\\'; s[1] = 'v'; - rb_str_cat(result, s, 2); + rb_str_buf_cat(result, s, 2); } else if (c == '\007') { s[0] = '\\'; s[1] = 'a'; - rb_str_cat(result, s, 2); + rb_str_buf_cat(result, s, 2); } else if (c == 033) { s[0] = '\\'; s[1] = 'e'; - rb_str_cat(result, s, 2); + rb_str_buf_cat(result, s, 2); } else { sprintf(s, "\\%03o", c & 0377); - rb_str_cat2(result, s); + rb_str_buf_cat2(result, s); } } - rb_str_cat2(result, "\""); + rb_str_buf_cat2(result, "\""); OBJ_INFECT(result, str); return result; @@ -2661,7 +2786,7 @@ rb_str_crypt(str, salt) StringValue(salt); if (RSTRING(salt)->len < 2) rb_raise(rb_eArgError, "salt too short(need >=2 bytes)"); - return rb_str_new2(crypt(RSTRING(str)->ptr, RSTRING(salt)->ptr)); + return rb_tainted_str_new2(crypt(RSTRING(str)->ptr, RSTRING(salt)->ptr)); } static VALUE @@ -2738,6 +2863,7 @@ rb_str_ljust(str, w) while (p < pend) { *p++ = ' '; } + OBJ_INFECT(res, str); return res; } @@ -2757,6 +2883,7 @@ rb_str_rjust(str, w) *p++ = ' '; } memcpy(pend, RSTRING(str)->ptr, RSTRING(str)->len); + OBJ_INFECT(res, str); return res; } @@ -2782,6 +2909,7 @@ rb_str_center(str, w) while (p < pend) { *p++ = ' '; } + OBJ_INFECT(res, str); return res; } @@ -358,7 +358,7 @@ inspect_struct(s) rb_bug("non-initialized struct"); } - str = rb_str_new2("#<"); + str = rb_str_buf_new2("#<"); rb_str_cat2(str, cname); rb_str_cat2(str, " "); for (i=0; i<RSTRUCT(s)->len; i++) { @@ -314,7 +314,10 @@ make_time_t(tptr, utc_p) { time_t guess, guess_lo, guess_hi; struct tm *tm, tm_lo, tm_hi; - int d; + int d, have_guess; + int find_dst; + + find_dst = 1; #ifdef NEGATIVE_TIME_T guess_lo = 1 << (8 * sizeof(time_t) - 1); @@ -322,7 +325,7 @@ make_time_t(tptr, utc_p) guess_lo = 0; #endif guess_hi = ((time_t)-1) < ((time_t)0) ? - (1U << (8 * sizeof(time_t) - 1)) - 1 : + (1UL << (8 * sizeof(time_t) - 1)) - 1 : ~(time_t)0; tm = (utc_p ? gmtime : localtime)(&guess_lo); @@ -339,62 +342,87 @@ make_time_t(tptr, utc_p) if (d == 0) return guess_hi; tm_hi = *tm; - while (guess_lo + 1 < guess_hi) { /* there is a gap between lo and hi. */ - unsigned long range; - int a, b; - /* - Try precious guess by a linear interpolation at first. - `a' and `b' is a coefficient of guess_lo and guess_hi. - `range' is approximation of maximum error by the interpolation. - (a + b)**2 should be less than 2**31 to avoid overflow. - When these parameter is wrong, binary search is used. - */ - a = (tm_hi.tm_year - tptr->tm_year); - b = (tptr->tm_year - tm_lo.tm_year); - range = 366 * 24 * 3600; - if (a + b < 46000 / 366) { - /* 46000 is selected as `some big number less than sqrt(2**31)'. */ - /* The distinction between leap/non-leap year is not important here. */ - static int days[] = { - 0, - 0 + 31, - 0 + 31 + 29, - 0 + 31 + 29 + 31, - 0 + 31 + 29 + 31 + 30, - 0 + 31 + 29 + 31 + 30 + 31, - 0 + 31 + 29 + 31 + 30 + 31 + 30, - 0 + 31 + 29 + 31 + 30 + 31 + 30 + 31, - 0 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, - 0 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, - 0 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, - 0 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 - /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov */ - }; - a *= 366; - b *= 366; - d = days[tptr->tm_mon] + tptr->tm_mday; - a += days[tm_hi.tm_mon] + tm_hi.tm_mday - d; - b += d - (days[tm_lo.tm_mon] + tm_lo.tm_mday); - range = 2 * 24 * 3600; - } - if (a + b <= 1) { - range = 2; - a *= 24 * 3600; - b *= 24 * 3600; - d = tptr->tm_hour * 3600 + tptr->tm_min * 60 + tptr->tm_sec; - a += tm_hi.tm_hour * 3600 + tm_hi.tm_min * 60 + tm_hi.tm_sec - d; - b += d - (tm_lo.tm_hour * 3600 + tm_lo.tm_min * 60 + tm_lo.tm_sec); + have_guess = 0; + + while (guess_lo + 1 < guess_hi) { + /* there is a gap between guess_lo and guess_hi. */ + unsigned long range = 0; + if (!have_guess) { + int a, b; + /* + Try precious guess by a linear interpolation at first. + `a' and `b' is a coefficient of guess_lo and guess_hi as: + + guess = (guess_lo * a + guess_hi * b) / (a + b) + + However this causes overflow in most cases, following assignment + is used instead: + + guess = guess_lo / d * a + (guess_lo % d) * a / d + + guess_hi / d * b + (guess_hi % d) * b / d + where d = a + b + + To avoid overflow in this assignment, `d' is restricted to less than + sqrt(2**31). By this restriction and other reasons, the guess is + not accurate and some error is expected. `range' approximates + the maximum error. + + When these parameters are not suitable, i.e. guess is not within + guess_lo and guess_hi, simple guess by binary search is used. + */ + range = 366 * 24 * 60 * 60; + a = (tm_hi.tm_year - tptr->tm_year); + b = (tptr->tm_year - tm_lo.tm_year); + /* 46000 is selected as `some big number less than sqrt(2**31)'. */ + if (a + b <= 46000 / 12) { + range = 31 * 24 * 60 * 60; + a *= 12; + b *= 12; + a += tm_hi.tm_mon - tptr->tm_mon; + b += tptr->tm_mon - tm_lo.tm_mon; + if (a + b <= 46000 / 31) { + range = 24 * 60 * 60; + a *= 31; + b *= 31; + a += tm_hi.tm_mday - tptr->tm_mday; + b += tptr->tm_mday - tm_lo.tm_mday; + if (a + b <= 46000 / 24) { + range = 60 * 60; + a *= 24; + b *= 24; + a += tm_hi.tm_hour - tptr->tm_hour; + b += tptr->tm_hour - tm_lo.tm_hour; + if (a + b <= 46000 / 60) { + range = 60; + a *= 60; + b *= 60; + a += tm_hi.tm_min - tptr->tm_min; + b += tptr->tm_min - tm_lo.tm_min; + if (a + b <= 46000 / 60) { + range = 1; + a *= 60; + b *= 60; + a += tm_hi.tm_sec - tptr->tm_sec; + b += tptr->tm_sec - tm_lo.tm_sec; + } + } + } + } + } + if (a <= 0) a = 1; + if (b <= 0) b = 1; + d = a + b; + /* + Although `/' and `%' may produce unexpected result with negative + argument, it doesn't cause serious problem because there is a + fail safe. + */ + guess = guess_lo / d * a + (guess_lo % d) * a / d + + guess_hi / d * b + (guess_hi % d) * b / d; + have_guess = 1; } - if (a <= 0) a = 1; - if (b <= 0) b = 1; - d = a + b; - guess = guess_lo / d * a + guess_hi / d * b; - /* Although `%' may not work with negative value, - it doesn't cause serious problem because there is a fail safe. */ - guess += ((guess_lo % d) * a + (guess_hi % d) * b) / d; - - fixguess: - if (guess <= guess_lo || guess >= guess_hi) { + + if (guess <= guess_lo || guess_hi <= guess) { /* Precious guess is invalid. try binary search. */ guess = guess_lo / 2 + guess_hi / 2; if (guess <= guess_lo) @@ -406,53 +434,99 @@ make_time_t(tptr, utc_p) tm = (utc_p ? gmtime : localtime)(&guess); if (!tm) goto error; + have_guess = 0; d = tmcmp(tptr, tm); - if (d == 0) { - if (!utc_p && !tm->tm_isdst) { - /* When leaving DST, there may be two time corresponding to given - argument. make_time_t returns DST in such cases. */ - /* xxx this assumes a difference in time as 3600 seconds. */ - time_t guess2 = guess - 3600; - tm = localtime(&guess2); - if (!tm) return guess; - if (tmcmp(tptr, tm) == 0) - return guess2; - } - return guess; - } - else if (d < 0) { + if (d < 0) { guess_hi = guess; tm_hi = *tm; - if (range && range < (unsigned long)(guess_hi - guess_lo)) { + if (range) { guess = guess - range; range = 0; - goto fixguess; + if (guess_lo < guess && guess < guess_hi) + have_guess = 1; } } - else { + else if (d > 0) { guess_lo = guess; tm_lo = *tm; - if (range && range < (unsigned long)(guess_hi - guess_lo)) { + if (range) { guess = guess + range; range = 0; - goto fixguess; + if (guess_lo < guess && guess < guess_hi) + have_guess = 1; } } + else { + if (!utc_p) { + /* If localtime is nonmonotonic, another result may exist. */ + time_t guess2; + if (find_dst) { + guess2 = guess - 2 * 60 * 60; + tm = localtime(&guess2); + if (tm) { + if (tptr->tm_hour != (tm->tm_hour + 2) % 24 || + tptr->tm_min != tm->tm_min || + tptr->tm_sec != tm->tm_sec) { + guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 + + (tm->tm_min - tptr->tm_min) * 60 + + (tm->tm_sec - tptr->tm_sec); + if (tptr->tm_mday != tm->tm_mday) + guess2 += 24 * 60 * 60; + if (guess != guess2) { + tm = localtime(&guess2); + if (tmcmp(tptr, tm) == 0) { + if (guess < guess2) + return guess; + else + return guess2; + } + } + } + } + } + else { + guess2 = guess + 2 * 60 * 60; + tm = localtime(&guess2); + if (tm) { + if ((tptr->tm_hour + 2) % 24 != tm->tm_hour || + tptr->tm_min != tm->tm_min || + tptr->tm_sec != tm->tm_sec) { + guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 + + (tm->tm_min - tptr->tm_min) * 60 + + (tm->tm_sec - tptr->tm_sec); + if (tptr->tm_mday != tm->tm_mday) + guess2 -= 24 * 60 * 60; + if (guess != guess2) { + tm = localtime(&guess2); + if (tmcmp(tptr, tm) == 0) { + if (guess < guess2) + return guess2; + else + return guess; + } + } + } + } + } + } + return guess; + } } - /* given time is not found. */ - if (guess_lo + 1 == guess_hi) { - /* given argument is invalid: 04/29 at non-leap year for example. */ - return guess_hi; + /* Given argument has no corresponding time_t. Let's outerpolation. */ + if (tm_lo.tm_year == tptr->tm_year && tm_lo.tm_mon == tptr->tm_mon) { + return guess_lo + + (tptr->tm_mday - tm_lo.tm_mday) * 24 * 60 * 60 + + (tptr->tm_hour - tm_lo.tm_hour) * 60 * 60 + + (tptr->tm_min - tm_lo.tm_min) * 60 + + (tptr->tm_sec - tm_lo.tm_sec); } - else { - /* given argument is in a gap. When it enters DST, for example. */ - d = tptr->tm_sec - tm_lo.tm_sec; - d += (tptr->tm_min - tm_lo.tm_min) * 60; - d += (tptr->tm_hour - tm_lo.tm_hour) * 3600; - if (d < 0) - d += 24 * 3600; - return guess_hi + d - 1; + else if (tm_hi.tm_year == tptr->tm_year && tm_hi.tm_mon == tptr->tm_mon) { + return guess_hi + + (tptr->tm_mday - tm_hi.tm_mday) * 24 * 60 * 60 + + (tptr->tm_hour - tm_hi.tm_hour) * 60 * 60 + + (tptr->tm_min - tm_hi.tm_min) * 60 + + (tptr->tm_sec - tm_hi.tm_sec); } out_of_range: diff --git a/variable.c b/variable.c index 4286f56086..fe0272d21e 100644 --- a/variable.c +++ b/variable.c @@ -16,6 +16,7 @@ #include "env.h" #include "node.h" #include "st.h" +#include "util.h" static st_table *rb_global_tbl; st_table *rb_class_tbl; @@ -1,4 +1,4 @@ -#define RUBY_VERSION "1.7.0" -#define RUBY_RELEASE_DATE "2001-05-28" -#define RUBY_VERSION_CODE 170 -#define RUBY_RELEASE_CODE 20010528 +#define RUBY_VERSION "1.7.1" +#define RUBY_RELEASE_DATE "2001-05-30" +#define RUBY_VERSION_CODE 171 +#define RUBY_RELEASE_CODE 20010530 |