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

* 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
This commit is contained in:
matz 2001-05-30 09:12:34 +00:00
parent 4cd1cd7201
commit abfaac7a6c
24 changed files with 925 additions and 423 deletions

View file

@ -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> Mon May 28 23:20:43 2001 WATANABE Hirofumi <eban@ruby-lang.org>
* configure.in: remove unnecessary AC_CANONICAL_BUILD * 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 * ext/extconf.rb.in: make the priority of the make rule of .c
higher than .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> Mon May 28 02:20:38 2001 Akinori MUSHA <knu@iDaemons.org>
* dir.c (glob_helper): teach has_magic() to handle flags and get * 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 * dir.c (fnmatch): fix a bug when FNM_PATHNAME and FNM_PERIOD are
specified at the same time. 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> Sat May 26 07:05:45 2001 Usaku Nakamura <usa@osb.att.ne.jp>
* MANIFEST: add win32/dir.h . * 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> Fri May 25 05:39:03 2001 Akinori MUSHA <knu@iDaemons.org>
* ext/sha1/sha1-ruby.c (sha1_hexdigest): fix buffer overflow. The * 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 * ext/dbm/extconf.rb: fix support for *BSD and set $CFLAGS
properly. 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> Thu May 24 16:08:21 2001 WATANABE Hirofumi <eban@ruby-lang.org>
* mkconfig.rb: autoconf 2.50 support. * mkconfig.rb: autoconf 2.50 support.

40
array.c
View file

@ -739,26 +739,11 @@ inspect_join(ary, arg)
return rb_ary_join(arg[0], arg[1]); 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 VALUE
rb_ary_join(ary, sep) rb_ary_join(ary, sep)
VALUE ary, sep; VALUE ary, sep;
{ {
long len, i, j; long len, i;
int taint = 0; int taint = 0;
VALUE result, tmp; VALUE result, tmp;
@ -778,9 +763,8 @@ rb_ary_join(ary, sep)
if (!NIL_P(sep) && TYPE(sep) == T_STRING) { if (!NIL_P(sep) && TYPE(sep) == T_STRING) {
len += RSTRING(sep)->len * RARRAY(ary)->len - 1; len += RSTRING(sep)->len * RARRAY(ary)->len - 1;
} }
result = rb_str_new(0, len); result = rb_str_buf_new(len);
for (i=0; i<RARRAY(ary)->len; i++) {
for (i=0, j=0; i<RARRAY(ary)->len; i++) {
tmp = RARRAY(ary)->ptr[i]; tmp = RARRAY(ary)->ptr[i];
switch (TYPE(tmp)) { switch (TYPE(tmp)) {
case T_STRING: case T_STRING:
@ -800,11 +784,11 @@ rb_ary_join(ary, sep)
default: default:
tmp = rb_obj_as_string(tmp); tmp = rb_obj_as_string(tmp);
} }
if (i > 0 && !NIL_P(sep)) j = str_cpy(result, j, sep); if (i > 0 && !NIL_P(sep))
j = str_cpy(result, j, tmp); rb_str_buf_append(result, sep);
rb_str_buf_append(result, tmp);
if (OBJ_TAINTED(tmp)) taint = 1; if (OBJ_TAINTED(tmp)) taint = 1;
} }
rb_str_resize(result, j);
if (taint) OBJ_TAINT(result); if (taint) OBJ_TAINT(result);
return result; return result;
@ -909,16 +893,14 @@ inspect_ary(ary)
long i = 0; long i = 0;
VALUE s, str; VALUE s, str;
str = rb_str_new2("["); str = rb_str_buf_new2("[");
for (i=0; i<RARRAY(ary)->len; i++) { for (i=0; i<RARRAY(ary)->len; i++) {
s = rb_inspect(RARRAY(ary)->ptr[i]); s = rb_inspect(RARRAY(ary)->ptr[i]);
tainted = OBJ_TAINTED(s); if (OBJ_TAINTED(s)) tainted = 1;
if (i > 0) rb_str_cat2(str, ", "); if (i > 0) rb_str_buf_cat2(str, ", ");
rb_str_append(str, s); rb_str_buf_append(str, s);
} }
rb_str_cat(str, "]", 1); rb_str_buf_cat2(str, "]");
if (tainted) OBJ_TAINT(str); if (tainted) OBJ_TAINT(str);
return str; return str;
} }

12
class.c
View file

@ -484,19 +484,29 @@ rb_class_private_instance_methods(argc, argv, mod)
} }
VALUE VALUE
rb_obj_singleton_methods(obj) rb_obj_singleton_methods(argc, argv, obj)
int argc;
VALUE *argv;
VALUE obj; VALUE obj;
{ {
VALUE all;
VALUE ary; VALUE ary;
VALUE klass; VALUE klass;
VALUE *p, *q, *pend; VALUE *p, *q, *pend;
rb_scan_args(argc, argv, "01", &all);
ary = rb_ary_new(); ary = rb_ary_new();
klass = CLASS_OF(obj); klass = CLASS_OF(obj);
while (klass && FL_TEST(klass, FL_SINGLETON)) { while (klass && FL_TEST(klass, FL_SINGLETON)) {
st_foreach(RCLASS(klass)->m_tbl, ins_methods_i, ary); st_foreach(RCLASS(klass)->m_tbl, ins_methods_i, ary);
klass = RCLASS(klass)->super; 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; p = q = RARRAY(ary)->ptr; pend = p + RARRAY(ary)->len;
while (p < pend) { while (p < pend) {
if (*p == Qnil) { if (*p == Qnil) {

15
dln.c
View file

@ -50,6 +50,10 @@ void *xrealloc();
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
#ifndef S_ISDIR
# define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
#endif
#ifdef HAVE_SYS_PARAM_H #ifdef HAVE_SYS_PARAM_H
# include <sys/param.h> # include <sys/param.h>
#else #else
@ -1582,9 +1586,8 @@ dln_find_1(fname, path, exe_flag)
register char *dp; register char *dp;
register char *ep; register char *ep;
register char *bp; register char *bp;
#ifndef __MACOS__
struct stat st; struct stat st;
#else #ifdef __MACOS__
const char* mac_fullpath; const char* mac_fullpath;
#endif #endif
@ -1669,13 +1672,17 @@ dln_find_1(fname, path, exe_flag)
if (stat(fbuf, &st) == 0) { if (stat(fbuf, &st) == 0) {
if (exe_flag == 0) return fbuf; if (exe_flag == 0) return fbuf;
/* looking for executable */ /* 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 #else
if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) { if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) {
if (exe_flag == 0) return mac_fullpath; if (exe_flag == 0) return mac_fullpath;
/* looking for executable */ /* 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 #endif
#if defined(MSDOS) || defined(NT) || defined(__human68k__) || defined(__EMX__) #if defined(MSDOS) || defined(NT) || defined(__human68k__) || defined(__EMX__)

10
error.c
View file

@ -359,12 +359,12 @@ exc_inspect(exc)
return rb_str_dup(rb_class_path(klass)); return rb_str_dup(rb_class_path(klass));
} }
str = rb_str_new2("#<"); str = rb_str_buf_new2("#<");
klass = rb_class_path(klass); klass = rb_class_path(klass);
rb_str_append(str, klass); rb_str_buf_append(str, klass);
rb_str_cat(str, ": ", 2); rb_str_buf_cat(str, ": ", 2);
rb_str_append(str, exc); rb_str_buf_append(str, exc);
rb_str_cat(str, ">", 1); rb_str_buf_cat(str, ">", 1);
return str; return str;
} }

33
eval.c
View file

@ -15,6 +15,7 @@
#include "ruby.h" #include "ruby.h"
#include "node.h" #include "node.h"
#include "env.h" #include "env.h"
#include "util.h"
#include "rubysig.h" #include "rubysig.h"
#include <stdio.h> #include <stdio.h>
@ -1213,14 +1214,14 @@ compile_error(at)
VALUE str; VALUE str;
ruby_nerrs = 0; ruby_nerrs = 0;
str = rb_str_new2("compile error"); str = rb_str_buf_new2("compile error");
if (at) { if (at) {
rb_str_cat2(str, " in "); rb_str_buf_cat2(str, " in ");
rb_str_cat2(str, at); rb_str_buf_cat2(str, at);
} }
rb_str_cat(str, "\n", 1); rb_str_buf_cat(str, "\n", 1);
if (!NIL_P(ruby_errinfo)) { 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)); rb_exc_raise(rb_exc_new3(rb_eSyntaxError, str));
} }
@ -2351,9 +2352,7 @@ rb_eval(self, n)
case NODE_YIELD: case NODE_YIELD:
if (node->nd_stts) { if (node->nd_stts) {
result = rb_eval(self, node->nd_stts); result = rb_eval(self, node->nd_stts);
if (nd_type(node->nd_stts) == NODE_RESTARGS && if (nd_type(node->nd_stts) == NODE_RESTARGS && RARRAY(result)->len == 1) {
RARRAY(result)->len == 1)
{
result = RARRAY(result)->ptr[0]; result = RARRAY(result)->ptr[0];
} }
} }
@ -6752,19 +6751,19 @@ method_inspect(method)
const char *s; const char *s;
Data_Get_Struct(method, struct METHOD, data); Data_Get_Struct(method, struct METHOD, data);
str = rb_str_new2("#<"); str = rb_str_buf_new2("#<");
s = rb_class2name(CLASS_OF(method)); s = rb_class2name(CLASS_OF(method));
rb_str_cat2(str, s); rb_str_buf_cat2(str, s);
rb_str_cat2(str, ": "); rb_str_buf_cat2(str, ": ");
s = rb_class2name(data->oklass); s = rb_class2name(data->oklass);
rb_str_cat2(str, s); rb_str_buf_cat2(str, s);
rb_str_cat2(str, "("); rb_str_buf_cat2(str, "(");
s = rb_class2name(data->klass); s = rb_class2name(data->klass);
rb_str_cat2(str, s); rb_str_buf_cat2(str, s);
rb_str_cat2(str, ")#"); rb_str_buf_cat2(str, ")#");
s = rb_id2name(data->oid); s = rb_id2name(data->oid);
rb_str_cat2(str, s); rb_str_buf_cat2(str, s);
rb_str_cat2(str, ">"); rb_str_buf_cat2(str, ">");
return str; return str;
} }

16
file.c
View file

@ -281,22 +281,22 @@ rb_stat_inspect(self)
{"ctime", rb_stat_ctime}, {"ctime", rb_stat_ctime},
}; };
str = rb_str_new2("#<"); str = rb_str_buf_new2("#<");
rb_str_cat2(str, rb_class2name(CLASS_OF(self))); rb_str_buf_cat2(str, rb_class2name(CLASS_OF(self)));
rb_str_cat2(str, " "); rb_str_buf_cat2(str, " ");
for (i = 0; i < sizeof(member)/sizeof(member[0]); i++) { for (i = 0; i < sizeof(member)/sizeof(member[0]); i++) {
VALUE str2; VALUE str2;
if (i > 0) { if (i > 0) {
rb_str_cat2(str, ", "); rb_str_buf_cat2(str, ", ");
} }
rb_str_cat2(str, member[i].name); rb_str_buf_cat2(str, member[i].name);
rb_str_cat2(str, "="); rb_str_buf_cat2(str, "=");
str2 = rb_inspect((*member[i].func)(self)); str2 = rb_inspect((*member[i].func)(self));
rb_str_append(str, str2); rb_str_append(str, str2);
} }
rb_str_cat2(str, ">"); rb_str_buf_cat2(str, ">");
OBJ_INFECT(str, self); OBJ_INFECT(str, self);
return str; return str;
@ -449,7 +449,7 @@ eaccess(path, mode)
if (st.st_mode & mode) return 0; if (st.st_mode & mode) return 0;
return -1; return -1;
#else /* !NT */ #else
return access(path, mode); return access(path, mode);
#endif #endif
} }

26
hash.c
View file

@ -634,11 +634,11 @@ inspect_i(key, value, str)
rb_str_cat2(str, ", "); rb_str_cat2(str, ", ");
} }
str2 = rb_inspect(key); str2 = rb_inspect(key);
rb_str_append(str, str2); rb_str_buf_append(str, str2);
OBJ_INFECT(str, str2); OBJ_INFECT(str, str2);
rb_str_cat2(str, "=>"); rb_str_buf_cat2(str, "=>");
str2 = rb_inspect(value); str2 = rb_inspect(value);
rb_str_append(str, str2); rb_str_buf_append(str, str2);
OBJ_INFECT(str, str2); OBJ_INFECT(str, str2);
return ST_CONTINUE; return ST_CONTINUE;
@ -650,11 +650,11 @@ inspect_hash(hash)
{ {
VALUE str; VALUE str;
str = rb_str_new2("{"); str = rb_str_buf_new2("{");
st_foreach(RHASH(hash)->tbl, inspect_i, str); st_foreach(RHASH(hash)->tbl, inspect_i, str);
rb_str_cat2(str, "}"); rb_str_buf_cat2(str, "}");
OBJ_INFECT(str, hash); OBJ_INFECT(str, hash);
return str; return str;
} }
@ -1266,7 +1266,7 @@ static VALUE
env_inspect() env_inspect()
{ {
char **env; char **env;
VALUE str = rb_str_new2("{"); VALUE str = rb_str_buf_new2("{");
VALUE i; VALUE i;
env = environ; env = environ;
@ -1274,18 +1274,18 @@ env_inspect()
char *s = strchr(*env, '='); char *s = strchr(*env, '=');
if (env != environ) { if (env != environ) {
rb_str_cat2(str, ", "); rb_str_buf_cat2(str, ", ");
} }
if (s) { if (s) {
rb_str_cat2(str, "\""); rb_str_buf_cat2(str, "\"");
rb_str_cat(str, *env, s-*env); rb_str_buf_cat(str, *env, s-*env);
rb_str_cat2(str, "\"=>"); rb_str_buf_cat2(str, "\"=>");
i = rb_inspect(rb_str_new2(s+1)); i = rb_inspect(rb_str_new2(s+1));
rb_str_append(str, i); rb_str_buf_append(str, i);
} }
env++; env++;
} }
rb_str_cat2(str, "}"); rb_str_buf_cat2(str, "}");
OBJ_TAINT(str); OBJ_TAINT(str);
return str; return str;

View file

@ -91,7 +91,7 @@ VALUE rb_mod_ancestors _((VALUE));
VALUE rb_class_instance_methods _((int, VALUE*, VALUE)); VALUE rb_class_instance_methods _((int, VALUE*, VALUE));
VALUE rb_class_protected_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_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_define_method_id _((VALUE, ID, VALUE (*)(ANYARGS), int));
void rb_frozen_class_p _((VALUE)); void rb_frozen_class_p _((VALUE));
void rb_undef _((VALUE, ID)); void rb_undef _((VALUE, ID));
@ -312,6 +312,8 @@ VALUE rb_str_new3 _((VALUE));
VALUE rb_str_new4 _((VALUE)); VALUE rb_str_new4 _((VALUE));
VALUE rb_tainted_str_new _((const char*, long)); VALUE rb_tainted_str_new _((const char*, long));
VALUE rb_tainted_str_new2 _((const char*)); 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_obj_as_string _((VALUE));
VALUE rb_str_dup _((VALUE)); VALUE rb_str_dup _((VALUE));
VALUE rb_str_plus _((VALUE, VALUE)); VALUE rb_str_plus _((VALUE, VALUE));

2
io.c
View file

@ -608,7 +608,7 @@ rb_io_gets_internal(argc, argv, io)
VALUE rs; VALUE rs;
if (argc == 0) { if (argc == 0) {
rs = rb_default_rs; rs = rb_rs;
} }
else { else {
rb_scan_args(argc, argv, "1", &rs); rb_scan_args(argc, argv, "1", &rs);

View file

@ -106,7 +106,7 @@ w_byte(c, arg)
struct dump_arg *arg; struct dump_arg *arg;
{ {
if (arg->fp) putc(c, arg->fp); 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 static void
@ -540,7 +540,7 @@ marshal_dump(argc, argv)
} }
else { else {
arg.fp = 0; arg.fp = 0;
port = rb_str_new(0, 0); port = rb_str_buf_new(0);
arg.str = port; arg.str = port;
} }

View file

@ -809,8 +809,6 @@ rb_obj_methods(obj)
return rb_class_instance_methods(1, argv, CLASS_OF(obj)); return rb_class_instance_methods(1, argv, CLASS_OF(obj));
} }
VALUE rb_obj_singleton_methods();
static VALUE static VALUE
rb_obj_protected_methods(obj) rb_obj_protected_methods(obj)
VALUE obj; VALUE obj;
@ -1179,7 +1177,7 @@ Init_Object()
rb_define_method(rb_mKernel, "inspect", rb_obj_inspect, 0); 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, "methods", rb_obj_methods, 0);
rb_define_method(rb_mKernel, "public_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, "protected_methods", rb_obj_protected_methods, 0);
rb_define_method(rb_mKernel, "private_methods", rb_obj_private_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); rb_define_method(rb_mKernel, "instance_variables", rb_obj_instance_variables, 0);

110
pack.c
View file

@ -331,7 +331,7 @@ pack_pack(ary, fmt)
static char *nul10 = "\0\0\0\0\0\0\0\0\0\0"; static char *nul10 = "\0\0\0\0\0\0\0\0\0\0";
static char *spc10 = " "; static char *spc10 = " ";
char *p, *pend; char *p, *pend;
VALUE res, from; VALUE res, from, associates = 0;
char type; char type;
int items, len, idx; int items, len, idx;
char *ptr; char *ptr;
@ -343,7 +343,7 @@ pack_pack(ary, fmt)
StringValue(fmt); StringValue(fmt);
p = RSTRING(fmt)->ptr; p = RSTRING(fmt)->ptr;
pend = p + RSTRING(fmt)->len; pend = p + RSTRING(fmt)->len;
res = rb_str_new(0, 0); res = rb_str_buf_new(0);
items = RARRAY(ary)->len; items = RARRAY(ary)->len;
idx = 0; idx = 0;
@ -405,15 +405,15 @@ pack_pack(ary, fmt)
case 'A': case 'A':
case 'Z': case 'Z':
if (plen >= len) if (plen >= len)
rb_str_cat(res, ptr, len); rb_str_buf_cat(res, ptr, len);
else { else {
rb_str_cat(res, ptr, plen); rb_str_buf_cat(res, ptr, plen);
len -= plen; len -= plen;
while (len >= 10) { while (len >= 10) {
rb_str_cat(res, (type == 'A')?spc10:nul10, 10); rb_str_buf_cat(res, (type == 'A')?spc10:nul10, 10);
len -= 10; len -= 10;
} }
rb_str_cat(res, (type == 'A')?spc10:nul10, len); rb_str_buf_cat(res, (type == 'A')?spc10:nul10, len);
} }
break; break;
@ -433,7 +433,7 @@ pack_pack(ary, fmt)
byte >>= 1; byte >>= 1;
else { else {
char c = byte & 0xff; char c = byte & 0xff;
rb_str_cat(res, &c, 1); rb_str_buf_cat(res, &c, 1);
byte = 0; byte = 0;
} }
} }
@ -441,11 +441,9 @@ pack_pack(ary, fmt)
char c; char c;
byte >>= 7 - (len & 7); byte >>= 7 - (len & 7);
c = byte & 0xff; c = byte & 0xff;
rb_str_cat(res, &c, 1); rb_str_buf_cat(res, &c, 1);
} }
len = RSTRING(res)->len; rb_str_buf_cat(res, 0, j);
rb_str_resize(res, len+j);
MEMZERO(RSTRING(res)->ptr+len, char, j);
} }
break; break;
@ -464,7 +462,7 @@ pack_pack(ary, fmt)
byte <<= 1; byte <<= 1;
else { else {
char c = byte & 0xff; char c = byte & 0xff;
rb_str_cat(res, &c, 1); rb_str_buf_cat(res, &c, 1);
byte = 0; byte = 0;
} }
} }
@ -472,11 +470,9 @@ pack_pack(ary, fmt)
char c; char c;
byte <<= 7 - (len & 7); byte <<= 7 - (len & 7);
c = byte & 0xff; c = byte & 0xff;
rb_str_cat(res, &c, 1); rb_str_buf_cat(res, &c, 1);
} }
len = RSTRING(res)->len; rb_str_buf_cat(res, 0, j);
rb_str_resize(res, len+j);
MEMZERO(RSTRING(res)->ptr+len, char, j);
} }
break; break;
@ -498,17 +494,15 @@ pack_pack(ary, fmt)
byte >>= 4; byte >>= 4;
else { else {
char c = byte & 0xff; char c = byte & 0xff;
rb_str_cat(res, &c, 1); rb_str_buf_cat(res, &c, 1);
byte = 0; byte = 0;
} }
} }
if (len & 1) { if (len & 1) {
char c = byte & 0xff; char c = byte & 0xff;
rb_str_cat(res, &c, 1); rb_str_buf_cat(res, &c, 1);
} }
len = RSTRING(res)->len; rb_str_buf_cat(res, 0, j);
rb_str_resize(res, len+j);
MEMZERO(RSTRING(res)->ptr+len, char, j);
} }
break; break;
@ -530,17 +524,15 @@ pack_pack(ary, fmt)
byte <<= 4; byte <<= 4;
else { else {
char c = byte & 0xff; char c = byte & 0xff;
rb_str_cat(res, &c, 1); rb_str_buf_cat(res, &c, 1);
byte = 0; byte = 0;
} }
} }
if (len & 1) { if (len & 1) {
char c = byte & 0xff; char c = byte & 0xff;
rb_str_cat(res, &c, 1); rb_str_buf_cat(res, &c, 1);
} }
len = RSTRING(res)->len; rb_str_buf_cat(res, 0, j);
rb_str_resize(res, len+j);
MEMZERO(RSTRING(res)->ptr+len, char, j);
} }
break; break;
} }
@ -556,7 +548,7 @@ pack_pack(ary, fmt)
else { else {
c = NUM2INT(from); c = NUM2INT(from);
} }
rb_str_cat(res, &c, sizeof(char)); rb_str_buf_cat(res, &c, sizeof(char));
} }
break; break;
@ -570,7 +562,7 @@ pack_pack(ary, fmt)
else { else {
s = NUM2INT(from); 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; break;
@ -584,7 +576,7 @@ pack_pack(ary, fmt)
else { else {
i = NUM2UINT(from); i = NUM2UINT(from);
} }
rb_str_cat(res, (char*)&i, sizeof(int)); rb_str_buf_cat(res, (char*)&i, sizeof(int));
} }
break; break;
@ -598,7 +590,7 @@ pack_pack(ary, fmt)
else { else {
l = NATINT_U32(from); 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; break;
@ -612,7 +604,7 @@ pack_pack(ary, fmt)
s = NUM2INT(from); s = NUM2INT(from);
} }
s = htons(s); 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; break;
@ -626,7 +618,7 @@ pack_pack(ary, fmt)
l = NATINT_U32(from); l = NATINT_U32(from);
} }
l = htonl(l); 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; break;
@ -640,7 +632,7 @@ pack_pack(ary, fmt)
s = NUM2INT(from); s = NUM2INT(from);
} }
s = htovs(s); 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; break;
@ -654,7 +646,7 @@ pack_pack(ary, fmt)
l = NATINT_U32(from); l = NATINT_U32(from);
} }
l = htovl(l); 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; break;
@ -674,7 +666,7 @@ pack_pack(ary, fmt)
f = (float)NUM2INT(from); f = (float)NUM2INT(from);
break; break;
} }
rb_str_cat(res, (char*)&f, sizeof(float)); rb_str_buf_cat(res, (char*)&f, sizeof(float));
} }
break; break;
@ -695,7 +687,7 @@ pack_pack(ary, fmt)
break; break;
} }
f = HTOVF(f,ftmp); f = HTOVF(f,ftmp);
rb_str_cat(res, (char*)&f, sizeof(float)); rb_str_buf_cat(res, (char*)&f, sizeof(float));
} }
break; break;
@ -716,7 +708,7 @@ pack_pack(ary, fmt)
break; break;
} }
d = HTOVD(d,dtmp); d = HTOVD(d,dtmp);
rb_str_cat(res, (char*)&d, sizeof(double)); rb_str_buf_cat(res, (char*)&d, sizeof(double));
} }
break; break;
@ -736,7 +728,7 @@ pack_pack(ary, fmt)
d = (double)NUM2INT(from); d = (double)NUM2INT(from);
break; break;
} }
rb_str_cat(res, (char*)&d, sizeof(double)); rb_str_buf_cat(res, (char*)&d, sizeof(double));
} }
break; break;
@ -757,7 +749,7 @@ pack_pack(ary, fmt)
break; break;
} }
f = HTONF(f,ftmp); f = HTONF(f,ftmp);
rb_str_cat(res, (char*)&f, sizeof(float)); rb_str_buf_cat(res, (char*)&f, sizeof(float));
} }
break; break;
@ -778,25 +770,26 @@ pack_pack(ary, fmt)
break; break;
} }
d = HTOND(d,dtmp); d = HTOND(d,dtmp);
rb_str_cat(res, (char*)&d, sizeof(double)); rb_str_buf_cat(res, (char*)&d, sizeof(double));
} }
break; break;
case 'x': case 'x':
grow: grow:
while (len >= 10) { while (len >= 10) {
rb_str_cat(res, nul10, 10); rb_str_buf_cat(res, nul10, 10);
len -= 10; len -= 10;
} }
rb_str_cat(res, nul10, len); rb_str_buf_cat(res, nul10, len);
break; break;
case 'X': case 'X':
shrink: shrink:
if (RSTRING(res)->len < len) plen = RSTRING(res)->len;
if (plen < len)
rb_raise(rb_eArgError, "X outside of string"); rb_raise(rb_eArgError, "X outside of string");
RSTRING(res)->len -= len; RSTRING(res)->len = plen - len;
RSTRING(res)->ptr[RSTRING(res)->len] = '\0'; RSTRING(res)->ptr[plen - len] = '\0';
break; break;
case '@': case '@':
@ -822,7 +815,7 @@ pack_pack(ary, fmt)
l = NUM2ULONG(from); l = NUM2ULONG(from);
} }
le = uv_to_utf8(buf, l); le = uv_to_utf8(buf, l);
rb_str_cat(res, (char*)buf, le); rb_str_buf_cat(res, (char*)buf, le);
} }
break; break;
@ -879,8 +872,11 @@ pack_pack(ary, fmt)
StringValue(from); StringValue(from);
t = RSTRING(from)->ptr; t = RSTRING(from)->ptr;
} }
rb_str_associate(res, from); if (!associates) {
rb_str_cat(res, (char*)&t, sizeof(char*)); associates = rb_ary_new();
}
rb_ary_push(associates, from);
rb_str_buf_cat(res, (char*)&t, sizeof(char*));
} }
break; break;
@ -891,13 +887,12 @@ pack_pack(ary, fmt)
char c, *bufs, *bufe; char c, *bufs, *bufe;
from = NEXTFROM; from = NEXTFROM;
if (TYPE(from) == T_BIGNUM) { if (TYPE(from) == T_BIGNUM) {
VALUE big128 = rb_uint2big(128); VALUE big128 = rb_uint2big(128);
while (TYPE(from) == T_BIGNUM) { while (TYPE(from) == T_BIGNUM) {
from = rb_big_divmod(from, big128); from = rb_big_divmod(from, big128);
c = NUM2INT(RARRAY(from)->ptr[1]) | 0x80; /* mod */ 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 */ from = RARRAY(from)->ptr[0]; /* div */
} }
} }
@ -909,7 +904,7 @@ pack_pack(ary, fmt)
while (ul) { while (ul) {
c = ((ul & 0x7f) | 0x80); c = ((ul & 0x7f) | 0x80);
rb_str_cat(buf, &c, sizeof(char)); rb_str_buf_cat(buf, &c, sizeof(char));
ul >>= 7; ul >>= 7;
} }
@ -922,11 +917,11 @@ pack_pack(ary, fmt)
*bufs++ = *bufe; *bufs++ = *bufe;
*bufe-- = c; *bufe-- = c;
} }
rb_str_cat(res, RSTRING(buf)->ptr, RSTRING(buf)->len); rb_str_buf_cat(res, RSTRING(buf)->ptr, RSTRING(buf)->len);
} }
else { else {
c = 0; c = 0;
rb_str_cat(res, &c, sizeof(char)); rb_str_buf_cat(res, &c, sizeof(char));
} }
} }
break; break;
@ -936,6 +931,9 @@ pack_pack(ary, fmt)
} }
} }
if (associates) {
rb_str_associate(res, associates);
}
return res; return res;
} }
@ -984,7 +982,7 @@ encodes(str, s, len, type)
buff[i++] = padding; buff[i++] = padding;
} }
buff[i++] = '\n'; buff[i++] = '\n';
rb_str_cat(str, buff, i); rb_str_buf_cat(str, buff, i);
} }
static char hex_table[] = "0123456789ABCDEF"; static char hex_table[] = "0123456789ABCDEF";
@ -1030,7 +1028,7 @@ qpencode(str, from, len)
prev = '\n'; prev = '\n';
} }
if (i > 1024 - 5) { if (i > 1024 - 5) {
rb_str_cat(str, buff, i); rb_str_buf_cat(str, buff, i);
i = 0; i = 0;
} }
s++; s++;
@ -1040,7 +1038,7 @@ qpencode(str, from, len)
buff[i++] = '\n'; buff[i++] = '\n';
} }
if (i > 0) { if (i > 0) {
rb_str_cat(str, buff, i); rb_str_buf_cat(str, buff, i);
} }
} }

308
parse.y
View file

@ -51,6 +51,7 @@ static enum lex_state {
EXPR_BEG, /* ignore newline, +/- is a sign. */ EXPR_BEG, /* ignore newline, +/- is a sign. */
EXPR_END, /* newline significant, +/- is a operator. */ EXPR_END, /* newline significant, +/- is a operator. */
EXPR_ARG, /* 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_MID, /* newline significant, +/- is a operator. */
EXPR_FNAME, /* ignore newline, no reserved words. */ EXPR_FNAME, /* ignore newline, no reserved words. */
EXPR_DOT, /* right after `.' or `::', 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; typedef unsigned long stack_type;
#endif #endif
static int cond_nest = 0;
static stack_type cond_stack = 0; static stack_type cond_stack = 0;
#define COND_PUSH do {\ #define COND_PUSH(n) do {\
cond_nest++;\ cond_stack = (cond_stack<<1)|((n)&1);\
cond_stack = (cond_stack<<1)|1;\
} while(0) } while(0)
#define COND_POP do {\ #define COND_POP() do {\
cond_nest--;\
cond_stack >>= 1;\ cond_stack >>= 1;\
} while (0) } 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; static stack_type cmdarg_stack = 0;
#define CMDARG_PUSH do {\ #define CMDARG_PUSH(n) do {\
cmdarg_stack = (cmdarg_stack<<1)|1;\ cmdarg_stack = (cmdarg_stack<<1)|((n)&1);\
} while(0) } while(0)
#define CMDARG_POP do {\ #define CMDARG_POP() do {\
cmdarg_stack >>= 1;\ cmdarg_stack >>= 1;\
} while (0) } while (0)
#define CMDARG_P() (cmdarg_stack && (cmdarg_stack&1)) #define CMDARG_LEXPOP() do {\
int last = CMDARG_P();\
cmdarg_stack >>= 1;\
if (last) cmdarg_stack |= 1;\
} while (0)
#define CMDARG_P() (cmdarg_stack&1)
static int class_nest = 0; static int class_nest = 0;
static int in_single = 0; static int in_single = 0;
static int in_def = 0; static int in_def = 0;
static int compile_for_eval = 0; static int compile_for_eval = 0;
static ID cur_mid = 0; static ID cur_mid = 0;
static ID last_id = 0;
static NODE *cond(); static NODE *cond();
static NODE *logop(); static NODE *logop();
@ -104,9 +113,11 @@ static NODE *block_append();
static NODE *list_append(); static NODE *list_append();
static NODE *list_concat(); static NODE *list_concat();
static NODE *arg_concat(); static NODE *arg_concat();
static NODE *arg_prepend();
static NODE *call_op(); static NODE *call_op();
static int in_defined = 0; static int in_defined = 0;
static NODE *ret_args();
static NODE *arg_blk_pass(); static NODE *arg_blk_pass();
static NODE *new_call(); static NODE *new_call();
static NODE *new_fcall(); static NODE *new_fcall();
@ -133,6 +144,7 @@ static int dyna_in_block();
static void top_local_init(); static void top_local_init();
static void top_local_setup(); static void top_local_setup();
%} %}
%union { %union {
@ -199,7 +211,7 @@ static void top_local_setup();
%type <val> literal numeric %type <val> literal numeric
%type <node> compstmt stmts stmt expr arg primary command command_call method_call %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> 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> command_args aref_args opt_block_arg block_arg var_ref
%type <node> mrhs mrhs_basic superclass block_call block_command %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 %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 <id> tOP_ASGN /* +=, -= etc. */
%token tASSOC /* => */ %token tASSOC /* => */
%token tLPAREN /* ( */ %token tLPAREN /* ( */
%token tLPAREN_ARG /* ( */
%token tRPAREN /* ) */ %token tRPAREN /* ) */
%token tLBRACK /* [ */ %token tLBRACK /* [ */
%token tLBRACE /* { */ %token tLBRACE /* { */
%token tLBRACE_ARG /* { */
%token tSTAR /* * */ %token tSTAR /* * */
%token tAMPER /* & */ %token tAMPER /* & */
%token tSYMBEG %token tSYMBEG
@ -420,19 +434,19 @@ stmt : kALIAS fitem {lex_state = EXPR_FNAME;} fitem
} }
| expr | expr
expr : kRETURN ret_args expr : kRETURN call_args
{ {
if (!compile_for_eval && !in_def && !in_single) if (!compile_for_eval && !in_def && !in_single)
yyerror("return appeared outside of method"); 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 | command_call
| expr kAND expr | expr kAND expr
@ -493,9 +507,9 @@ command : operation command_args
$$ = new_super($2); $$ = new_super($2);
fixpos($$, $2); fixpos($$, $2);
} }
| kYIELD ret_args | kYIELD call_args
{ {
$$ = NEW_YIELD($2); $$ = NEW_YIELD(ret_args($2));
fixpos($$, $2); fixpos($$, $2);
} }
@ -1001,9 +1015,90 @@ call_args : command
} }
| block_arg | block_arg
command_args : {CMDARG_PUSH;} call_args call_args2 : arg ',' args opt_block_arg
{ {
CMDARG_POP; $$ = 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 ')'
{
rb_warning("%s (...) interpreted as method call",
rb_id2name(last_id));
$$ = $2; $$ = $2;
} }
@ -1053,20 +1148,6 @@ mrhs_basic : args ',' arg
$$ = $2; $$ = $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 primary : literal
{ {
$$ = NEW_LIT($1); $$ = NEW_LIT($1);
@ -1104,6 +1185,11 @@ primary : literal
} }
fixpos($$, $2); fixpos($$, $2);
} }
| tLPAREN_ARG expr ')'
{
rb_warning("%s (...) interpreted as command call", rb_id2name(last_id));
$$ = $2;
}
| tLPAREN compstmt ')' | tLPAREN compstmt ')'
{ {
$$ = $2; $$ = $2;
@ -1140,10 +1226,10 @@ primary : literal
yyerror("return appeared outside of method"); yyerror("return appeared outside of method");
$$ = NEW_RETURN(0); $$ = NEW_RETURN(0);
} }
| kYIELD '(' ret_args ')' | kYIELD '(' call_args ')'
{ {
value_expr($3); value_expr($3);
$$ = NEW_YIELD($3); $$ = NEW_YIELD(ret_args($3));
} }
| kYIELD '(' ')' | kYIELD '(' ')'
{ {
@ -1191,7 +1277,7 @@ primary : literal
$$ = NEW_UNLESS(cond($2), $4, $5); $$ = NEW_UNLESS(cond($2), $4, $5);
fixpos($$, $2); fixpos($$, $2);
} }
| kWHILE {COND_PUSH;} expr do {COND_POP;} | kWHILE {COND_PUSH(1);} expr do {COND_POP();}
compstmt compstmt
kEND kEND
{ {
@ -1199,7 +1285,7 @@ primary : literal
$$ = NEW_WHILE(cond($3), $6, 1); $$ = NEW_WHILE(cond($3), $6, 1);
fixpos($$, $3); fixpos($$, $3);
} }
| kUNTIL {COND_PUSH;} expr do {COND_POP;} | kUNTIL {COND_PUSH(1);} expr do {COND_POP();}
compstmt compstmt
kEND kEND
{ {
@ -1219,7 +1305,7 @@ primary : literal
{ {
$$ = $3; $$ = $3;
} }
| kFOR block_var kIN {COND_PUSH;} expr do {COND_POP;} | kFOR block_var kIN {COND_PUSH(1);} expr do {COND_POP();}
compstmt compstmt
kEND kEND
{ {
@ -1407,6 +1493,16 @@ do_block : kDO_BLOCK
fixpos($$, $3?$3:$4); fixpos($$, $3?$3:$4);
dyna_pop($<vars>2); 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 block_call : command do_block
{ {
@ -1913,6 +2009,7 @@ yyerror(msg)
} }
static int heredoc_end; static int heredoc_end;
static int command_start = Qtrue;
int ruby_in_compile = 0; int ruby_in_compile = 0;
int ruby__end__seen; int ruby__end__seen;
@ -1958,9 +2055,9 @@ yycompile(f, line)
ruby_debug_lines = 0; ruby_debug_lines = 0;
compile_for_eval = 0; compile_for_eval = 0;
ruby_in_compile = 0; ruby_in_compile = 0;
cond_nest = 0;
cond_stack = 0; cond_stack = 0;
cmdarg_stack = 0; cmdarg_stack = 0;
command_start = 1;
class_nest = 0; class_nest = 0;
in_single = 0; in_single = 0;
in_def = 0; in_def = 0;
@ -2711,13 +2808,6 @@ here_document(term, indent)
lex_pbeg = lex_p = RSTRING(line)->ptr; lex_pbeg = lex_p = RSTRING(line)->ptr;
lex_pend = lex_p + RSTRING(line)->len; lex_pend = lex_p + RSTRING(line)->len;
#if 0
if (indent) {
while (*lex_p && *lex_p == '\t') {
lex_p++;
}
}
#endif
retry: retry:
switch (parse_string(term, '\n', '\n')) { switch (parse_string(term, '\n', '\n')) {
case tSTRING: case tSTRING:
@ -2791,13 +2881,18 @@ arg_ambiguous()
double strtod (); double strtod ();
#endif #endif
#define IS_ARG() (lex_state == EXPR_ARG || lex_state == EXPR_CMDARG)
static int static int
yylex() yylex()
{ {
register int c; register int c;
int space_seen = 0; int space_seen = 0;
int cmd_state;
struct kwtable *kw; struct kwtable *kw;
cmd_state = command_start;
command_start = Qfalse;
retry: retry:
switch (c = nextc()) { switch (c = nextc()) {
case '\0': /* NUL */ case '\0': /* NUL */
@ -2827,6 +2922,7 @@ yylex()
default: default:
break; break;
} }
command_start = Qtrue;
lex_state = EXPR_BEG; lex_state = EXPR_BEG;
return '\n'; return '\n';
@ -2846,7 +2942,7 @@ yylex()
return tOP_ASGN; return tOP_ASGN;
} }
pushback(c); pushback(c);
if (lex_state == EXPR_ARG && space_seen && !ISSPACE(c)){ if (IS_ARG() && space_seen && !ISSPACE(c)){
rb_warning("`*' interpreted as argument prefix"); rb_warning("`*' interpreted as argument prefix");
c = tSTAR; c = tSTAR;
} }
@ -2913,7 +3009,7 @@ yylex()
c = nextc(); c = nextc();
if (c == '<' && if (c == '<' &&
lex_state != EXPR_END && lex_state != EXPR_CLASS && lex_state != EXPR_END && lex_state != EXPR_CLASS &&
(lex_state != EXPR_ARG || space_seen)) { (!IS_ARG() || space_seen)) {
int c2 = nextc(); int c2 = nextc();
int indent = 0; int indent = 0;
if (c2 == '-') { if (c2 == '-') {
@ -2980,7 +3076,7 @@ yylex()
rb_compile_error("incomplete character syntax"); rb_compile_error("incomplete character syntax");
return 0; return 0;
} }
if (lex_state == EXPR_ARG && ISSPACE(c)){ if (IS_ARG() && ISSPACE(c)){
pushback(c); pushback(c);
lex_state = EXPR_BEG; lex_state = EXPR_BEG;
return '?'; return '?';
@ -3009,8 +3105,8 @@ yylex()
return tOP_ASGN; return tOP_ASGN;
} }
pushback(c); pushback(c);
if (lex_state == EXPR_ARG && space_seen && !ISSPACE(c)){ if (IS_ARG() && space_seen && !ISSPACE(c)){
rb_warning("`&' interpreted as argument prefix"); rb_warning("`&' interpeted as argument prefix");
c = tAMPER; c = tAMPER;
} }
else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
@ -3054,8 +3150,8 @@ yylex()
return tOP_ASGN; return tOP_ASGN;
} }
if (lex_state == EXPR_BEG || lex_state == EXPR_MID || if (lex_state == EXPR_BEG || lex_state == EXPR_MID ||
(lex_state == EXPR_ARG && space_seen && !ISSPACE(c))) { (IS_ARG() && space_seen && !ISSPACE(c))) {
if (lex_state == EXPR_ARG) arg_ambiguous(); if (IS_ARG()) arg_ambiguous();
lex_state = EXPR_BEG; lex_state = EXPR_BEG;
pushback(c); pushback(c);
if (ISDIGIT(c)) { if (ISDIGIT(c)) {
@ -3083,8 +3179,8 @@ yylex()
return tOP_ASGN; return tOP_ASGN;
} }
if (lex_state == EXPR_BEG || lex_state == EXPR_MID || if (lex_state == EXPR_BEG || lex_state == EXPR_MID ||
(lex_state == EXPR_ARG && space_seen && !ISSPACE(c))) { (IS_ARG() && space_seen && !ISSPACE(c))) {
if (lex_state == EXPR_ARG) arg_ambiguous(); if (IS_ARG()) arg_ambiguous();
lex_state = EXPR_BEG; lex_state = EXPR_BEG;
pushback(c); pushback(c);
if (ISDIGIT(c)) { if (ISDIGIT(c)) {
@ -3276,13 +3372,9 @@ yylex()
case ']': case ']':
case '}': case '}':
lex_state = EXPR_END;
return c;
case ')': case ')':
if (cond_nest > 0) { COND_LEXPOP();
cond_stack >>= 1; CMDARG_LEXPOP();
}
lex_state = EXPR_END; lex_state = EXPR_END;
return c; return c;
@ -3290,7 +3382,7 @@ yylex()
c = nextc(); c = nextc();
if (c == ':') { if (c == ':') {
if (lex_state == EXPR_BEG || lex_state == EXPR_MID || if (lex_state == EXPR_BEG || lex_state == EXPR_MID ||
(lex_state == EXPR_ARG && space_seen)) { (IS_ARG() && space_seen)) {
lex_state = EXPR_BEG; lex_state = EXPR_BEG;
return tCOLON3; return tCOLON3;
} }
@ -3315,7 +3407,7 @@ yylex()
return tOP_ASGN; return tOP_ASGN;
} }
pushback(c); pushback(c);
if (lex_state == EXPR_ARG && space_seen) { if (IS_ARG() && space_seen) {
if (!ISSPACE(c)) { if (!ISSPACE(c)) {
arg_ambiguous(); arg_ambiguous();
return parse_regx('/', '/'); return parse_regx('/', '/');
@ -3333,8 +3425,9 @@ yylex()
pushback(c); pushback(c);
return '^'; return '^';
case ',':
case ';': case ';':
command_start = Qtrue;
case ',':
lex_state = EXPR_BEG; lex_state = EXPR_BEG;
return c; return c;
@ -3348,15 +3441,21 @@ yylex()
return '~'; return '~';
case '(': case '(':
if (cond_nest > 0) { command_start = Qtrue;
cond_stack = (cond_stack<<1)|0;
}
if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
c = tLPAREN; c = tLPAREN;
} }
else if (lex_state == EXPR_ARG && space_seen) { else if (space_seen) {
rb_warning("%s (...) interpreted as method call", tok()); 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; lex_state = EXPR_BEG;
return c; return c;
@ -3375,15 +3474,23 @@ yylex()
else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) { else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
c = tLBRACK; c = tLBRACK;
} }
else if (lex_state == EXPR_ARG && space_seen) { else if (IS_ARG() && space_seen) {
c = tLBRACK; c = tLBRACK;
} }
lex_state = EXPR_BEG; lex_state = EXPR_BEG;
COND_PUSH(0);
CMDARG_PUSH(0);
return c; return c;
case '{': case '{':
if (lex_state != EXPR_END && lex_state != EXPR_ARG) if (!IS_ARG()) {
if (lex_state != EXPR_END)
c = tLBRACE; c = tLBRACE;
if (space_seen && CMDARG_P())
c = tLBRACE_ARG;
}
COND_PUSH(0);
CMDARG_PUSH(0);
lex_state = EXPR_BEG; lex_state = EXPR_BEG;
return c; return c;
@ -3446,7 +3553,7 @@ yylex()
yylval.id = '%'; yylval.id = '%';
return tOP_ASGN; return tOP_ASGN;
} }
if (lex_state == EXPR_ARG && space_seen && !ISSPACE(c)) { if (IS_ARG() && space_seen && !ISSPACE(c)) {
goto quotation; goto quotation;
} }
lex_state = EXPR_BEG; lex_state = EXPR_BEG;
@ -3608,7 +3715,8 @@ yylex()
} }
if (kw->id[0] == kDO) { if (kw->id[0] == kDO) {
if (COND_P()) return kDO_COND; 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; return kDO;
} }
if (state == EXPR_BEG) if (state == EXPR_BEG)
@ -3626,12 +3734,8 @@ yylex()
} }
else { else {
if (lex_state == EXPR_FNAME) { if (lex_state == EXPR_FNAME) {
#if 0
if ((c = nextc()) == '=' && !peek('=') && !peek('~') && !peek('>')) {
#else
if ((c = nextc()) == '=' && !peek('~') && !peek('>') && if ((c = nextc()) == '=' && !peek('~') && !peek('>') &&
(!peek('=') || lex_p + 1 < lex_pend && lex_p[1] == '>')) { (!peek('=') || lex_p + 1 < lex_pend && lex_p[1] == '>')) {
#endif
result = tIDENTIFIER; result = tIDENTIFIER;
tokadd(c); tokadd(c);
} }
@ -3648,7 +3752,11 @@ yylex()
} }
if (lex_state == EXPR_BEG || if (lex_state == EXPR_BEG ||
lex_state == EXPR_DOT || lex_state == EXPR_DOT ||
lex_state == EXPR_ARG) { lex_state == EXPR_ARG ||
lex_state == EXPR_CMDARG) {
if (cmd_state)
lex_state = EXPR_CMDARG;
else
lex_state = EXPR_ARG; lex_state = EXPR_ARG;
} }
else { else {
@ -3656,7 +3764,7 @@ yylex()
} }
} }
tokfix(); tokfix();
yylval.id = rb_intern(tok()); last_id = yylval.id = rb_intern(tok());
return result; return result;
} }
} }
@ -4548,6 +4656,21 @@ logop(type, left, right)
return rb_node_newnode(type, cond1(left, 1), cond1(right, 1), 0); return rb_node_newnode(type, cond1(left, 1), cond1(right, 1), 0);
} }
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 * static NODE *
arg_blk_pass(node1, node2) arg_blk_pass(node1, node2)
NODE *node1; NODE *node1;
@ -4560,6 +4683,27 @@ arg_blk_pass(node1, node2)
return node1; return node1;
} }
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* static NODE*
new_call(r,m,a) new_call(r,m,a)
NODE *r; NODE *r;

95
range.c
View file

@ -13,7 +13,7 @@
#include "ruby.h" #include "ruby.h"
VALUE rb_cRange; 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 EXCL(r) RTEST(rb_ivar_get((r), id_excl))
#define SET_EXCL(r,v) rb_ivar_set((r), id_excl, (v)?Qtrue:Qfalse) #define SET_EXCL(r,v) rb_ivar_set((r), id_excl, (v)?Qtrue:Qfalse)
@ -23,6 +23,9 @@ range_check(args)
VALUE *args; VALUE *args;
{ {
rb_funcall(args[0], id_cmp, 1, args[1]); 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; return Qnil;
} }
@ -103,6 +106,49 @@ range_eq(range, obj)
return Qtrue; 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 static VALUE
range_eqq(range, obj) range_eqq(range, obj)
VALUE range, obj; VALUE range, obj;
@ -123,14 +169,12 @@ range_eqq(range, obj)
} }
return Qfalse; return Qfalse;
} }
else if (RTEST(rb_funcall(beg, rb_intern("<="), 1, obj))) { else if (r_le(beg, obj)) {
if (EXCL(range)) { if (EXCL(range)) {
if (RTEST(rb_funcall(end, rb_intern(">"), 1, obj))) if (r_lt(obj, end)) return Qtrue;
return Qtrue;
} }
else { else {
if (RTEST(rb_funcall(end, rb_intern(">="), 1, obj))) if (r_le(obj, end)) return Qtrue;
return Qtrue;
} }
} }
return Qfalse; return Qfalse;
@ -169,22 +213,19 @@ range_each(range)
} }
else { /* generic each */ else { /* generic each */
VALUE v = b; VALUE v = b;
ID succ = rb_intern("succ");
if (EXCL(range)) { if (EXCL(range)) {
while (RTEST(rb_funcall(v, '<', 1, e))) { while (r_lt(v, e)) {
if (rb_equal(v, e)) break; if (r_eq(v, e)) break;
rb_yield(v); rb_yield(v);
v = rb_funcall(v, succ, 0, 0); v = rb_funcall(v, id_succ, 0, 0);
} }
} }
else { else {
ID le = rb_intern("<="); while (r_le(v, e)) {
while (RTEST(rb_funcall(v, le, 1, e))) {
rb_yield(v); rb_yield(v);
if (rb_equal(v, e)) break; if (r_eq(v, e)) break;
v = rb_funcall(v, succ, 0, 0); v = rb_funcall(v, id_succ, 0, 0);
} }
} }
} }
@ -324,7 +365,7 @@ range_length(range)
beg = rb_ivar_get(range, id_beg); beg = rb_ivar_get(range, id_beg);
end = rb_ivar_get(range, id_end); end = rb_ivar_get(range, id_end);
if (RTEST(rb_funcall(beg, '>', 1, end))) { if (r_gt(beg, end)) {
return INT2FIX(0); return INT2FIX(0);
} }
if (FIXNUM_P(beg) && FIXNUM_P(end)) { if (FIXNUM_P(beg) && FIXNUM_P(end)) {
@ -349,6 +390,25 @@ range_length(range)
return size; 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 void
Init_Range() Init_Range()
{ {
@ -369,8 +429,11 @@ Init_Range()
rb_define_method(rb_cRange, "length", range_length, 0); rb_define_method(rb_cRange, "length", range_length, 0);
rb_define_method(rb_cRange, "size", 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_cmp = rb_intern("<=>");
id_succ = rb_intern("succ");
id_beg = rb_intern("begin"); id_beg = rb_intern("begin");
id_end = rb_intern("end"); id_end = rb_intern("end");
id_excl = rb_intern("excl"); id_excl = rb_intern("excl");

74
re.c
View file

@ -224,51 +224,51 @@ rb_reg_expr_str(str, s, len)
p++; p++;
} }
if (!need_escape) { if (!need_escape) {
rb_str_cat(str, s, len); rb_str_buf_cat(str, s, len);
} }
else { else {
p = s; p = s;
while (p<pend) { while (p<pend) {
if (*p == '/') { if (*p == '/') {
char c = '\\'; char c = '\\';
rb_str_cat(str, &c, 1); rb_str_buf_cat(str, &c, 1);
rb_str_cat(str, p, 1); rb_str_buf_cat(str, p, 1);
} }
else if (ismbchar(*p)) { else if (ismbchar(*p)) {
rb_str_cat(str, p, mbclen(*p)); rb_str_buf_cat(str, p, mbclen(*p));
p += mbclen(*p); p += mbclen(*p);
continue; continue;
} }
else if (ISPRINT(*p)) { else if (ISPRINT(*p)) {
rb_str_cat(str, p, 1); rb_str_buf_cat(str, p, 1);
} }
else { else {
char b[8]; char b[8];
switch (*p) { switch (*p) {
case '\r': case '\r':
rb_str_cat(str, "\\r", 2); rb_str_buf_cat(str, "\\r", 2);
break; break;
case '\n': case '\n':
rb_str_cat(str, "\\n", 2); rb_str_buf_cat(str, "\\n", 2);
break; break;
case '\t': case '\t':
rb_str_cat(str, "\\t", 2); rb_str_buf_cat(str, "\\t", 2);
break; break;
case '\f': case '\f':
rb_str_cat(str, "\\f", 2); rb_str_buf_cat(str, "\\f", 2);
break; break;
case 007: case 007:
rb_str_cat(str, "\\a", 2); rb_str_buf_cat(str, "\\a", 2);
break; break;
case 013: case 013:
rb_str_cat(str, "\\v", 2); rb_str_buf_cat(str, "\\v", 2);
break; break;
case 033: case 033:
rb_str_cat(str, "\\e", 2); rb_str_buf_cat(str, "\\e", 2);
break; break;
default: default:
sprintf(b, "\\%03o", *p & 0377); sprintf(b, "\\%03o", *p & 0377);
rb_str_cat(str, b, 4); rb_str_buf_cat(str, b, 4);
break; break;
} }
} }
@ -283,35 +283,35 @@ rb_reg_desc(s, len, re)
int len; int len;
VALUE re; VALUE re;
{ {
VALUE str = rb_str_new2("/"); VALUE str = rb_str_buf_new2("/");
rb_reg_expr_str(str, s, len); rb_reg_expr_str(str, s, len);
rb_str_cat2(str, "/"); rb_str_buf_cat2(str, "/");
if (re) { if (re) {
rb_reg_check(re); rb_reg_check(re);
/* /p is obsolete; to be removed */ /* /p is obsolete; to be removed */
if ((RREGEXP(re)->ptr->options & RE_OPTION_POSIXLINE) == RE_OPTION_POSIXLINE) 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) 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) 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) 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)) { if (FL_TEST(re, KCODE_FIXED)) {
switch ((RBASIC(re)->flags & KCODE_MASK)) { switch ((RBASIC(re)->flags & KCODE_MASK)) {
case KCODE_NONE: case KCODE_NONE:
rb_str_cat2(str, "n"); rb_str_buf_cat2(str, "n");
break; break;
case KCODE_EUC: case KCODE_EUC:
rb_str_cat2(str, "e"); rb_str_buf_cat2(str, "e");
break; break;
case KCODE_SJIS: case KCODE_SJIS:
rb_str_cat2(str, "s"); rb_str_buf_cat2(str, "s");
break; break;
case KCODE_UTF8: case KCODE_UTF8:
rb_str_cat2(str, "u"); rb_str_buf_cat2(str, "u");
break; break;
} }
} }
@ -1171,8 +1171,13 @@ rb_reg_regsub(str, src, regs)
} }
if (c != '\\' || s == e) continue; if (c != '\\' || s == e) continue;
if (!val) val = rb_str_new(p, ss-p); if (!val) {
else rb_str_cat(val, p, ss-p); 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++; c = *s++;
p = s; p = s;
@ -1186,11 +1191,11 @@ rb_reg_regsub(str, src, regs)
break; break;
case '`': case '`':
rb_str_cat(val, RSTRING(src)->ptr, BEG(0)); rb_str_buf_cat(val, RSTRING(src)->ptr, BEG(0));
continue; continue;
case '\'': 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; continue;
case '+': case '+':
@ -1200,24 +1205,29 @@ rb_reg_regsub(str, src, regs)
break; break;
case '\\': case '\\':
rb_str_cat(val, s-1, 1); rb_str_buf_cat(val, s-1, 1);
continue; continue;
default: default:
rb_str_cat(val, s-2, 2); rb_str_buf_cat(val, s-2, 2);
continue; continue;
} }
if (no >= 0) { if (no >= 0) {
if (no >= regs->num_regs) continue; if (no >= regs->num_regs) continue;
if (BEG(no) == -1) 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 (p < e) {
if (!val) val = rb_str_new(p, e-p); if (!val) {
else rb_str_cat(val, p, e-p); 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; if (!val) return str;

29
regex.c
View file

@ -370,6 +370,7 @@ enum regexpcode
duplicate, /* Match a duplicate of something remembered. duplicate, /* Match a duplicate of something remembered.
Followed by one byte containing the index of the memory Followed by one byte containing the index of the memory
register. */ register. */
fail, /* always fails. */
wordchar, /* Matches any word-constituent character. */ wordchar, /* Matches any word-constituent character. */
notwordchar, /* Matches any char that is not a word-constituent. */ notwordchar, /* Matches any char that is not a word-constituent. */
wordbeg, /* Succeeds if at word beginning. */ wordbeg, /* Succeeds if at word beginning. */
@ -2246,32 +2247,23 @@ re_compile_pattern(pattern, size, bufp)
case '1': case '2': case '3': case '1': case '2': case '3':
case '4': case '5': case '6': case '4': case '5': case '6':
case '7': case '8': case '9': case '7': case '8': case '9':
{
const char *p_save;
PATUNFETCH; PATUNFETCH;
p_save = p; p0 = p;
had_mbchar = 0; had_mbchar = 0;
c1 = 0; c1 = 0;
GET_UNSIGNED_NUMBER(c1); GET_UNSIGNED_NUMBER(c1);
if (!ISDIGIT(c)) PATUNFETCH; if (!ISDIGIT(c)) PATUNFETCH;
if (c1 >= regnum) { if (9 < c1 && c1 >= regnum) {
/* need to get octal */ /* need to get octal */
p = p_save; c = scan_oct(p0, 3, &numlen) & 0xff;
c = scan_oct(p_save, 3, &numlen) & 0xff; p = p0 + numlen;
p = p_save + numlen;
c1 = 0; c1 = 0;
had_num_literal = 1; had_num_literal = 1;
goto numeric_char; 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; laststart = b;
BUFPUSH(duplicate); BUFPUSH(duplicate);
BUFPUSH(c1); BUFPUSH(c1);
@ -3736,11 +3728,16 @@ re_match(bufp, string_arg, size, pos, regs)
int regno = *p++; /* Get which register to match against */ int regno = *p++; /* Get which register to match against */
register unsigned char *d2, *dend2; 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. */ /* Where in input to try to start matching. */
d2 = regstart[regno]; 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 /* Where to stop matching; if both the place to start and
the place to stop matching are in the same string, then 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. */ the end of the first string. */
dend2 = regend[regno]; dend2 = regend[regno];
if (REG_UNSET(dend2)) break; if (REG_UNSET(dend2)) goto fail;
for (;;) { for (;;) {
/* At end of register contents => success */ /* At end of register contents => success */
if (d2 == dend2) break; if (d2 == dend2) break;

10
ruby.c
View file

@ -681,6 +681,11 @@ proc_options(argc, argv)
ruby_show_copyright(); 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 (!e_script && argc == 0) { /* no more args */
if (verbose) exit(0); if (verbose) exit(0);
script = "-"; script = "-";
@ -726,6 +731,11 @@ proc_options(argc, argv)
process_sflag(); process_sflag();
xflag = 0; 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; extern int ruby__end__seen;

1
ruby.h
View file

@ -111,6 +111,7 @@ typedef unsigned long ID;
#define FIXNUM_FLAG 0x01 #define FIXNUM_FLAG 0x01
#define INT2FIX(i) ((VALUE)(((long)(i))<<1 | FIXNUM_FLAG)) #define INT2FIX(i) ((VALUE)(((long)(i))<<1 | FIXNUM_FLAG))
#define LONG2FIX(i) INT2FIX(i)
#define rb_fix_new(v) INT2FIX(v) #define rb_fix_new(v) INT2FIX(v)
VALUE rb_int2inum _((long)); VALUE rb_int2inum _((long));
#define INT2NUM(v) rb_int2inum(v) #define INT2NUM(v) rb_int2inum(v)

186
string.c
View file

@ -28,6 +28,7 @@
VALUE rb_cString; VALUE rb_cString;
#define STR_NO_ORIG FL_USER2 #define STR_NO_ORIG FL_USER2
#define STR_ASSOC FL_USER3
VALUE rb_fs; 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 VALUE
rb_str_to_str(str) rb_str_to_str(str)
VALUE str; VALUE str;
@ -176,7 +211,7 @@ rb_str_associate(str, add)
rb_str_modify(str); rb_str_modify(str);
} }
RSTRING(str)->orig = rb_ary_new(); 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); rb_ary_push(RSTRING(str)->orig, add);
} }
@ -185,7 +220,7 @@ VALUE
rb_str_associated(str) rb_str_associated(str)
VALUE str; VALUE str;
{ {
if (!FL_TEST(str, STR_NO_ORIG)) { if (!FL_TEST(str, STR_NO_ORIG|STR_ASSOC)) {
return Qfalse; return Qfalse;
} }
return RSTRING(str)->orig; return RSTRING(str)->orig;
@ -442,28 +477,70 @@ rb_str_resize(str, len)
return str; return str;
} }
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 VALUE
rb_str_cat(str, ptr, len) rb_str_cat(str, ptr, len)
VALUE str; VALUE str;
const char *ptr; const char *ptr;
long len; long len;
{ {
if (len > 0) { long i, capa;
int poffset = -1;
rb_str_modify(str); rb_str_modify(str);
if (RSTRING(str)->ptr <= ptr && if (len > 0) {
ptr < RSTRING(str)->ptr + RSTRING(str)->len) { if (RSTRING(str)->orig == 0 ||
poffset = ptr - RSTRING(str)->ptr; (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 (ptr) {
if (poffset >= 0) ptr = RSTRING(str)->ptr + poffset;
memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len); 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)->len += len;
RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */ RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */
} }
return str; return str;
} }
@ -476,14 +553,61 @@ rb_str_cat2(str, ptr)
} }
VALUE VALUE
rb_str_append(str1, str2) rb_str_buf_append(str, str2)
VALUE str1, str2; VALUE str, str2;
{ {
StringValue(str2); long i, capa, len;
str1 = rb_str_cat(str1, RSTRING(str2)->ptr, RSTRING(str2)->len);
OBJ_INFECT(str1, str2);
return str1; 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);
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 str;
} }
VALUE VALUE
@ -998,6 +1122,7 @@ rb_str_update(str, beg, len, val)
} }
RSTRING(str)->len += RSTRING(val)->len - len; RSTRING(str)->len += RSTRING(val)->len - len;
RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; RSTRING(str)->ptr[RSTRING(str)->len] = '\0';
OBJ_INFECT(str, val);
} }
static VALUE rb_str_sub_bang _((int, VALUE*, VALUE)); static VALUE rb_str_sub_bang _((int, VALUE*, VALUE));
@ -1518,7 +1643,7 @@ rb_str_inspect(str)
VALUE str; VALUE str;
{ {
char *p, *pend; char *p, *pend;
VALUE result = rb_str_new2("\""); VALUE result = rb_str_buf_new2("\"");
char s[5]; char s[5];
p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len; p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len;
@ -1526,51 +1651,51 @@ rb_str_inspect(str)
char c = *p++; char c = *p++;
if (ismbchar(c) && p < pend) { if (ismbchar(c) && p < pend) {
int len = mbclen(c); int len = mbclen(c);
rb_str_cat(result, p - 1, len); rb_str_buf_cat(result, p - 1, len);
p += len - 1; p += len - 1;
} }
else if (c == '"'|| c == '\\') { else if (c == '"'|| c == '\\') {
s[0] = '\\'; s[1] = c; s[0] = '\\'; s[1] = c;
rb_str_cat(result, s, 2); rb_str_buf_cat(result, s, 2);
} }
else if (ISPRINT(c)) { else if (ISPRINT(c)) {
s[0] = c; s[0] = c;
rb_str_cat(result, s, 1); rb_str_buf_cat(result, s, 1);
} }
else if (c == '\n') { else if (c == '\n') {
s[0] = '\\'; s[1] = 'n'; s[0] = '\\'; s[1] = 'n';
rb_str_cat(result, s, 2); rb_str_buf_cat(result, s, 2);
} }
else if (c == '\r') { else if (c == '\r') {
s[0] = '\\'; s[1] = 'r'; s[0] = '\\'; s[1] = 'r';
rb_str_cat(result, s, 2); rb_str_buf_cat(result, s, 2);
} }
else if (c == '\t') { else if (c == '\t') {
s[0] = '\\'; s[1] = 't'; s[0] = '\\'; s[1] = 't';
rb_str_cat(result, s, 2); rb_str_buf_cat(result, s, 2);
} }
else if (c == '\f') { else if (c == '\f') {
s[0] = '\\'; s[1] = 'f'; s[0] = '\\'; s[1] = 'f';
rb_str_cat(result, s, 2); rb_str_buf_cat(result, s, 2);
} }
else if (c == '\013') { else if (c == '\013') {
s[0] = '\\'; s[1] = 'v'; s[0] = '\\'; s[1] = 'v';
rb_str_cat(result, s, 2); rb_str_buf_cat(result, s, 2);
} }
else if (c == '\007') { else if (c == '\007') {
s[0] = '\\'; s[1] = 'a'; s[0] = '\\'; s[1] = 'a';
rb_str_cat(result, s, 2); rb_str_buf_cat(result, s, 2);
} }
else if (c == 033) { else if (c == 033) {
s[0] = '\\'; s[1] = 'e'; s[0] = '\\'; s[1] = 'e';
rb_str_cat(result, s, 2); rb_str_buf_cat(result, s, 2);
} }
else { else {
sprintf(s, "\\%03o", c & 0377); 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); OBJ_INFECT(result, str);
return result; return result;
@ -2661,7 +2786,7 @@ rb_str_crypt(str, salt)
StringValue(salt); StringValue(salt);
if (RSTRING(salt)->len < 2) if (RSTRING(salt)->len < 2)
rb_raise(rb_eArgError, "salt too short(need >=2 bytes)"); 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 static VALUE
@ -2738,6 +2863,7 @@ rb_str_ljust(str, w)
while (p < pend) { while (p < pend) {
*p++ = ' '; *p++ = ' ';
} }
OBJ_INFECT(res, str);
return res; return res;
} }
@ -2757,6 +2883,7 @@ rb_str_rjust(str, w)
*p++ = ' '; *p++ = ' ';
} }
memcpy(pend, RSTRING(str)->ptr, RSTRING(str)->len); memcpy(pend, RSTRING(str)->ptr, RSTRING(str)->len);
OBJ_INFECT(res, str);
return res; return res;
} }
@ -2782,6 +2909,7 @@ rb_str_center(str, w)
while (p < pend) { while (p < pend) {
*p++ = ' '; *p++ = ' ';
} }
OBJ_INFECT(res, str);
return res; return res;
} }

View file

@ -358,7 +358,7 @@ inspect_struct(s)
rb_bug("non-initialized struct"); rb_bug("non-initialized struct");
} }
str = rb_str_new2("#<"); str = rb_str_buf_new2("#<");
rb_str_cat2(str, cname); rb_str_cat2(str, cname);
rb_str_cat2(str, " "); rb_str_cat2(str, " ");
for (i=0; i<RSTRUCT(s)->len; i++) { for (i=0; i<RSTRUCT(s)->len; i++) {

240
time.c
View file

@ -314,7 +314,10 @@ make_time_t(tptr, utc_p)
{ {
time_t guess, guess_lo, guess_hi; time_t guess, guess_lo, guess_hi;
struct tm *tm, tm_lo, tm_hi; struct tm *tm, tm_lo, tm_hi;
int d; int d, have_guess;
int find_dst;
find_dst = 1;
#ifdef NEGATIVE_TIME_T #ifdef NEGATIVE_TIME_T
guess_lo = 1 << (8 * sizeof(time_t) - 1); guess_lo = 1 << (8 * sizeof(time_t) - 1);
@ -322,7 +325,7 @@ make_time_t(tptr, utc_p)
guess_lo = 0; guess_lo = 0;
#endif #endif
guess_hi = ((time_t)-1) < ((time_t)0) ? 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; ~(time_t)0;
tm = (utc_p ? gmtime : localtime)(&guess_lo); tm = (utc_p ? gmtime : localtime)(&guess_lo);
@ -339,62 +342,87 @@ make_time_t(tptr, utc_p)
if (d == 0) return guess_hi; if (d == 0) return guess_hi;
tm_hi = *tm; tm_hi = *tm;
while (guess_lo + 1 < guess_hi) { /* there is a gap between lo and hi. */ have_guess = 0;
unsigned long range;
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; int a, b;
/* /*
Try precious guess by a linear interpolation at first. Try precious guess by a linear interpolation at first.
`a' and `b' is a coefficient of guess_lo and guess_hi. `a' and `b' is a coefficient of guess_lo and guess_hi as:
`range' is approximation of maximum error by the interpolation.
(a + b)**2 should be less than 2**31 to avoid overflow. guess = (guess_lo * a + guess_hi * b) / (a + b)
When these parameter is wrong, binary search is used.
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); a = (tm_hi.tm_year - tptr->tm_year);
b = (tptr->tm_year - tm_lo.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)'. */ /* 46000 is selected as `some big number less than sqrt(2**31)'. */
/* The distinction between leap/non-leap year is not important here. */ if (a + b <= 46000 / 12) {
static int days[] = { range = 31 * 24 * 60 * 60;
0, a *= 12;
0 + 31, b *= 12;
0 + 31 + 29, a += tm_hi.tm_mon - tptr->tm_mon;
0 + 31 + 29 + 31, b += tptr->tm_mon - tm_lo.tm_mon;
0 + 31 + 29 + 31 + 30, if (a + b <= 46000 / 31) {
0 + 31 + 29 + 31 + 30 + 31, range = 24 * 60 * 60;
0 + 31 + 29 + 31 + 30 + 31 + 30, a *= 31;
0 + 31 + 29 + 31 + 30 + 31 + 30 + 31, b *= 31;
0 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31, a += tm_hi.tm_mday - tptr->tm_mday;
0 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30, b += tptr->tm_mday - tm_lo.tm_mday;
0 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31, if (a + b <= 46000 / 24) {
0 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30 range = 60 * 60;
/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov */ a *= 24;
}; b *= 24;
a *= 366; a += tm_hi.tm_hour - tptr->tm_hour;
b *= 366; b += tptr->tm_hour - tm_lo.tm_hour;
d = days[tptr->tm_mon] + tptr->tm_mday; if (a + b <= 46000 / 60) {
a += days[tm_hi.tm_mon] + tm_hi.tm_mday - d; range = 60;
b += d - (days[tm_lo.tm_mon] + tm_lo.tm_mday); a *= 60;
range = 2 * 24 * 3600; 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 + 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);
} }
if (a <= 0) a = 1; if (a <= 0) a = 1;
if (b <= 0) b = 1; if (b <= 0) b = 1;
d = a + b; d = a + b;
guess = guess_lo / d * a + guess_hi / d * b; /*
/* Although `%' may not work with negative value, Although `/' and `%' may produce unexpected result with negative
it doesn't cause serious problem because there is a fail safe. */ argument, it doesn't cause serious problem because there is a
guess += ((guess_lo % d) * a + (guess_hi % d) * b) / d; fail safe.
*/
guess = guess_lo / d * a + (guess_lo % d) * a / d
+ guess_hi / d * b + (guess_hi % d) * b / d;
have_guess = 1;
}
fixguess: if (guess <= guess_lo || guess_hi <= guess) {
if (guess <= guess_lo || guess >= guess_hi) {
/* Precious guess is invalid. try binary search. */ /* Precious guess is invalid. try binary search. */
guess = guess_lo / 2 + guess_hi / 2; guess = guess_lo / 2 + guess_hi / 2;
if (guess <= guess_lo) if (guess <= guess_lo)
@ -406,53 +434,99 @@ make_time_t(tptr, utc_p)
tm = (utc_p ? gmtime : localtime)(&guess); tm = (utc_p ? gmtime : localtime)(&guess);
if (!tm) goto error; if (!tm) goto error;
have_guess = 0;
d = tmcmp(tptr, tm); d = tmcmp(tptr, tm);
if (d == 0) { if (d < 0) {
if (!utc_p && !tm->tm_isdst) { guess_hi = guess;
/* When leaving DST, there may be two time corresponding to given tm_hi = *tm;
argument. make_time_t returns DST in such cases. */ if (range) {
/* xxx this assumes a difference in time as 3600 seconds. */ guess = guess - range;
time_t guess2 = guess - 3600; range = 0;
if (guess_lo < guess && guess < guess_hi)
have_guess = 1;
}
}
else if (d > 0) {
guess_lo = guess;
tm_lo = *tm;
if (range) {
guess = guess + range;
range = 0;
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); tm = localtime(&guess2);
if (!tm) return guess; if (tm) {
if (tmcmp(tptr, tm) == 0) 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; 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; return guess;
} }
else if (d < 0) {
guess_hi = guess;
tm_hi = *tm;
if (range && range < (unsigned long)(guess_hi - guess_lo)) {
guess = guess - range;
range = 0;
goto fixguess;
} }
/* 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 { else if (tm_hi.tm_year == tptr->tm_year && tm_hi.tm_mon == tptr->tm_mon) {
guess_lo = guess; return guess_hi +
tm_lo = *tm; (tptr->tm_mday - tm_hi.tm_mday) * 24 * 60 * 60 +
if (range && range < (unsigned long)(guess_hi - guess_lo)) { (tptr->tm_hour - tm_hi.tm_hour) * 60 * 60 +
guess = guess + range; (tptr->tm_min - tm_hi.tm_min) * 60 +
range = 0; (tptr->tm_sec - tm_hi.tm_sec);
goto fixguess;
}
}
}
/* 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;
}
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;
} }
out_of_range: out_of_range:

View file

@ -16,6 +16,7 @@
#include "env.h" #include "env.h"
#include "node.h" #include "node.h"
#include "st.h" #include "st.h"
#include "util.h"
static st_table *rb_global_tbl; static st_table *rb_global_tbl;
st_table *rb_class_tbl; st_table *rb_class_tbl;

View file

@ -1,4 +1,4 @@
#define RUBY_VERSION "1.7.0" #define RUBY_VERSION "1.7.1"
#define RUBY_RELEASE_DATE "2001-05-28" #define RUBY_RELEASE_DATE "2001-05-30"
#define RUBY_VERSION_CODE 170 #define RUBY_VERSION_CODE 171
#define RUBY_RELEASE_CODE 20010528 #define RUBY_RELEASE_CODE 20010530