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>
* 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.

40
array.c
View file

@ -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;
}

12
class.c
View file

@ -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) {

15
dln.c
View file

@ -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__)

10
error.c
View file

@ -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;
}

33
eval.c
View file

@ -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;
}

16
file.c
View file

@ -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
}

26
hash.c
View file

@ -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;

View file

@ -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));

2
io.c
View file

@ -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);

View file

@ -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;
}

View file

@ -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);

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 *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);
}
}

314
parse.y
View file

@ -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_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 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
{
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;
}
@ -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;
}
}
@ -4548,6 +4656,21 @@ logop(type, left, right)
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 *
arg_blk_pass(node1, node2)
NODE *node1;
@ -4560,6 +4683,27 @@ arg_blk_pass(node1, node2)
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*
new_call(r,m,a)
NODE *r;

95
range.c
View file

@ -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");

74
re.c
View file

@ -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;

45
regex.c
View file

@ -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;
p0 = p;
PATUNFETCH;
p_save = p;
had_mbchar = 0;
c1 = 0;
GET_UNSIGNED_NUMBER(c1);
if (!ISDIGIT(c)) PATUNFETCH;
had_mbchar = 0;
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;

10
ruby.c
View file

@ -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;

1
ruby.h
View file

@ -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)

188
string.c
View file

@ -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;
@ -442,28 +477,70 @@ rb_str_resize(str, len)
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
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;
{
StringValue(str2);
str1 = rb_str_cat(str1, RSTRING(str2)->ptr, RSTRING(str2)->len);
OBJ_INFECT(str1, str2);
long i, capa, len;
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
@ -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;
}

View file

@ -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++) {

256
time.c
View file

@ -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);
}
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;
have_guess = 0;
fixguess:
if (guess <= guess_lo || guess >= guess_hi) {
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 (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 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 {
guess_lo = guess;
tm_lo = *tm;
if (range && range < (unsigned long)(guess_hi - guess_lo)) {
guess = guess + range;
range = 0;
goto fixguess;
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:

View file

@ -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;

View file

@ -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