summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog78
-rw-r--r--array.c40
-rw-r--r--class.c12
-rw-r--r--dln.c15
-rw-r--r--error.c10
-rw-r--r--eval.c33
-rw-r--r--file.c16
-rw-r--r--hash.c26
-rw-r--r--intern.h4
-rw-r--r--io.c2
-rw-r--r--marshal.c4
-rw-r--r--object.c4
-rw-r--r--pack.c110
-rw-r--r--parse.y314
-rw-r--r--range.c95
-rw-r--r--re.c74
-rw-r--r--regex.c47
-rw-r--r--ruby.c10
-rw-r--r--ruby.h1
-rw-r--r--string.c186
-rw-r--r--struct.c2
-rw-r--r--time.c250
-rw-r--r--variable.c1
-rw-r--r--version.h8
24 files changed, 922 insertions, 420 deletions
diff --git a/ChangeLog b/ChangeLog
index 7113ccbda4b..00381b7b725 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -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.
diff --git a/array.c b/array.c
index 1d63a9fa2b1..010afd9a39f 100644
--- a/array.c
+++ b/array.c
@@ -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;
}
diff --git a/class.c b/class.c
index b1cc94c3c19..0f5dcd709d5 100644
--- a/class.c
+++ b/class.c
@@ -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) {
diff --git a/dln.c b/dln.c
index 36f416a010d..6910fa91d3e 100644
--- a/dln.c
+++ b/dln.c
@@ -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__)
diff --git a/error.c b/error.c
index ac5e1e5ba81..eaaa54647b7 100644
--- a/error.c
+++ b/error.c
@@ -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;
}
diff --git a/eval.c b/eval.c
index cc21c7c6064..1dbd43b2d13 100644
--- a/eval.c
+++ b/eval.c
@@ -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;
}
diff --git a/file.c b/file.c
index 128b6672141..14c6d9271b3 100644
--- a/file.c
+++ b/file.c
@@ -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
}
diff --git a/hash.c b/hash.c
index 61400c0b17c..7a08b0d500b 100644
--- a/hash.c
+++ b/hash.c
@@ -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;
diff --git a/intern.h b/intern.h
index a5e3565c413..cf7df058b86 100644
--- a/intern.h
+++ b/intern.h
@@ -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));
diff --git a/io.c b/io.c
index bd7d91957ab..3d6dac5c601 100644
--- a/io.c
+++ b/io.c
@@ -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);
diff --git a/marshal.c b/marshal.c
index a0dfb68b280..8bb8d2c9848 100644
--- a/marshal.c
+++ b/marshal.c
@@ -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;
}
diff --git a/object.c b/object.c
index e510d26cfe0..dc0379050bc 100644
--- a/object.c
+++ b/object.c
@@ -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);
diff --git a/pack.c b/pack.c
index 256fa62eae5..44a683a37f4 100644
--- a/pack.c
+++ b/pack.c
@@ -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);
}
}
diff --git a/parse.y b/parse.y
index 51b04288c0d..1f79918d599 100644
--- a/parse.y
+++ b/parse.y
@@ -51,6 +51,7 @@ static enum lex_state {
EXPR_BEG, /* ignore newline, +/- is a sign. */
EXPR_END, /* newline significant, +/- is a operator. */
EXPR_ARG, /* newline significant, +/- is a operator. */
+ EXPR_CMDARG, /* newline significant, +/- is a operator. */
EXPR_MID, /* newline significant, +/- is a operator. */
EXPR_FNAME, /* ignore newline, no reserved words. */
EXPR_DOT, /* right after `.' or `::', no reserved words. */
@@ -63,32 +64,40 @@ typedef unsigned LONG_LONG stack_type;
typedef unsigned long stack_type;
#endif
-static int cond_nest = 0;
static stack_type cond_stack = 0;
-#define COND_PUSH do {\
- cond_nest++;\
- cond_stack = (cond_stack<<1)|1;\
+#define COND_PUSH(n) do {\
+ cond_stack = (cond_stack<<1)|((n)&1);\
} while(0)
-#define COND_POP do {\
- cond_nest--;\
+#define COND_POP() do {\
cond_stack >>= 1;\
} while (0)
-#define COND_P() (cond_nest > 0 && (cond_stack&1))
+#define COND_LEXPOP() do {\
+ int last = COND_P();\
+ cond_stack >>= 1;\
+ if (last) cond_stack |= 1;\
+} while (0)
+#define COND_P() (cond_stack&1)
static stack_type cmdarg_stack = 0;
-#define CMDARG_PUSH do {\
- cmdarg_stack = (cmdarg_stack<<1)|1;\
+#define CMDARG_PUSH(n) do {\
+ cmdarg_stack = (cmdarg_stack<<1)|((n)&1);\
} while(0)
-#define CMDARG_POP do {\
+#define CMDARG_POP() do {\
+ cmdarg_stack >>= 1;\
+} while (0)
+#define CMDARG_LEXPOP() do {\
+ int last = CMDARG_P();\
cmdarg_stack >>= 1;\
+ if (last) cmdarg_stack |= 1;\
} while (0)
-#define CMDARG_P() (cmdarg_stack && (cmdarg_stack&1))
+#define CMDARG_P() (cmdarg_stack&1)
static int class_nest = 0;
static int in_single = 0;
static int in_def = 0;
static int compile_for_eval = 0;
static ID cur_mid = 0;
+static ID last_id = 0;
static NODE *cond();
static NODE *logop();
@@ -104,9 +113,11 @@ static NODE *block_append();
static NODE *list_append();
static NODE *list_concat();
static NODE *arg_concat();
+static NODE *arg_prepend();
static NODE *call_op();
static int in_defined = 0;
+static NODE *ret_args();
static NODE *arg_blk_pass();
static NODE *new_call();
static NODE *new_fcall();
@@ -133,6 +144,7 @@ static int dyna_in_block();
static void top_local_init();
static void top_local_setup();
+
%}
%union {
@@ -199,7 +211,7 @@ static void top_local_setup();
%type <val> literal numeric
%type <node> compstmt stmts stmt expr arg primary command command_call method_call
%type <node> if_tail opt_else case_body cases rescue exc_list exc_var ensure
-%type <node> args ret_args when_args call_args paren_args opt_paren_args
+%type <node> args when_args call_args call_args2 open_args paren_args opt_paren_args
%type <node> command_args aref_args opt_block_arg block_arg var_ref
%type <node> mrhs mrhs_basic superclass block_call block_command
%type <node> f_arglist f_args f_optarg f_opt f_block_arg opt_f_block_arg
@@ -228,9 +240,11 @@ static void top_local_setup();
%token <id> tOP_ASGN /* +=, -= etc. */
%token tASSOC /* => */
%token tLPAREN /* ( */
+%token tLPAREN_ARG /* ( */
%token tRPAREN /* ) */
%token tLBRACK /* [ */
%token tLBRACE /* { */
+%token tLBRACE_ARG /* { */
%token tSTAR /* * */
%token tAMPER /* & */
%token tSYMBEG
@@ -420,19 +434,19 @@ stmt : kALIAS fitem {lex_state = EXPR_FNAME;} fitem
}
| expr
-expr : kRETURN ret_args
+expr : kRETURN call_args
{
if (!compile_for_eval && !in_def && !in_single)
yyerror("return appeared outside of method");
- $$ = NEW_RETURN($2);
+ $$ = NEW_RETURN(ret_args($2));
}
- | kBREAK ret_args
+ | kBREAK call_args
{
- $$ = NEW_BREAK($2);
+ $$ = NEW_BREAK(ret_args($2));
}
- | kNEXT ret_args
+ | kNEXT call_args
{
- $$ = NEW_NEXT($2);
+ $$ = NEW_NEXT(ret_args($2));
}
| command_call
| expr kAND expr
@@ -469,7 +483,7 @@ block_command : block_call
$$ = new_call($1, $3, $4);
}
-command : operation command_args
+command : operation command_args
{
$$ = new_fcall($1, $2);
fixpos($$, $2);
@@ -493,9 +507,9 @@ command : operation command_args
$$ = new_super($2);
fixpos($$, $2);
}
- | kYIELD ret_args
+ | kYIELD call_args
{
- $$ = NEW_YIELD($2);
+ $$ = NEW_YIELD(ret_args($2));
fixpos($$, $2);
}
@@ -1001,9 +1015,90 @@ call_args : command
}
| block_arg
-command_args : {CMDARG_PUSH;} call_args
+call_args2 : arg ',' args opt_block_arg
+ {
+ $$ = arg_blk_pass(list_append(NEW_LIST($1),$3), $4);
+ }
+ | arg ',' tSTAR arg opt_block_arg
+ {
+ value_expr($1);
+ value_expr($4);
+ $$ = arg_concat(NEW_LIST($1), $4);
+ $$ = arg_blk_pass($$, $5);
+ }
+ | arg ',' args ',' tSTAR arg opt_block_arg
+ {
+ value_expr($1);
+ value_expr($6);
+ $$ = arg_concat(list_append($1,$3), $6);
+ $$ = arg_blk_pass($$, $7);
+ }
+ | assocs opt_block_arg
+ {
+ $$ = NEW_LIST(NEW_HASH($1));
+ $$ = arg_blk_pass($$, $2);
+ }
+ | assocs ',' tSTAR arg opt_block_arg
+ {
+ value_expr($4);
+ $$ = arg_concat(NEW_LIST(NEW_HASH($1)), $4);
+ $$ = arg_blk_pass($$, $5);
+ }
+ | arg ',' assocs opt_block_arg
+ {
+ $$ = list_append(NEW_LIST($1), NEW_HASH($3));
+ $$ = arg_blk_pass($$, $4);
+ }
+ | arg ',' args ',' assocs opt_block_arg
+ {
+ value_expr($1);
+ value_expr($6);
+ $$ = list_append(list_append($1,$3), NEW_HASH($5));
+ $$ = arg_blk_pass($$, $6);
+ }
+ | arg ',' assocs ',' tSTAR arg opt_block_arg
+ {
+ value_expr($1);
+ value_expr($6);
+ $$ = arg_concat(list_append(NEW_LIST($1), NEW_HASH($3)), $6);
+ $$ = arg_blk_pass($$, $7);
+ }
+ | arg ',' args ',' assocs ',' tSTAR arg opt_block_arg
+ {
+ value_expr($1);
+ value_expr($8);
+ $$ = arg_concat(list_append(list_append(NEW_LIST($1), $3), NEW_HASH($5)), $8);
+ $$ = arg_blk_pass($$, $9);
+ }
+ | tSTAR arg opt_block_arg
+ {
+ value_expr($2);
+ $$ = arg_blk_pass(NEW_RESTARGS($2), $3);
+ }
+ | block_arg
+
+command_args : {
+ $<num>$ = cmdarg_stack;
+ CMDARG_PUSH(1);
+ }
+ open_args
+ {
+ /* CMDARG_POP() */
+ cmdarg_stack = $<num>1;
+ $$ = $2;
+ }
+
+open_args : call_args
+ | tLPAREN_ARG ')'
+ {
+ rb_warning("%s (...) interpreted as method call",
+ rb_id2name(last_id));
+ $$ = 0;
+ }
+ | tLPAREN_ARG call_args2 ')'
{
- CMDARG_POP;
+ rb_warning("%s (...) interpreted as method call",
+ rb_id2name(last_id));
$$ = $2;
}
@@ -1053,20 +1148,6 @@ mrhs_basic : args ',' arg
$$ = $2;
}
-ret_args : call_args
- {
- $$ = $1;
- if ($1) {
- if (nd_type($1) == NODE_ARRAY &&
- $1->nd_next == 0) {
- $$ = $1->nd_head;
- }
- else if (nd_type($1) == NODE_BLOCK_PASS) {
- rb_compile_error("block argument should not be given");
- }
- }
- }
-
primary : literal
{
$$ = NEW_LIT($1);
@@ -1104,6 +1185,11 @@ primary : literal
}
fixpos($$, $2);
}
+ | tLPAREN_ARG expr ')'
+ {
+ rb_warning("%s (...) interpreted as command call", rb_id2name(last_id));
+ $$ = $2;
+ }
| tLPAREN compstmt ')'
{
$$ = $2;
@@ -1140,10 +1226,10 @@ primary : literal
yyerror("return appeared outside of method");
$$ = NEW_RETURN(0);
}
- | kYIELD '(' ret_args ')'
+ | kYIELD '(' call_args ')'
{
value_expr($3);
- $$ = NEW_YIELD($3);
+ $$ = NEW_YIELD(ret_args($3));
}
| kYIELD '(' ')'
{
@@ -1191,7 +1277,7 @@ primary : literal
$$ = NEW_UNLESS(cond($2), $4, $5);
fixpos($$, $2);
}
- | kWHILE {COND_PUSH;} expr do {COND_POP;}
+ | kWHILE {COND_PUSH(1);} expr do {COND_POP();}
compstmt
kEND
{
@@ -1199,7 +1285,7 @@ primary : literal
$$ = NEW_WHILE(cond($3), $6, 1);
fixpos($$, $3);
}
- | kUNTIL {COND_PUSH;} expr do {COND_POP;}
+ | kUNTIL {COND_PUSH(1);} expr do {COND_POP();}
compstmt
kEND
{
@@ -1219,7 +1305,7 @@ primary : literal
{
$$ = $3;
}
- | kFOR block_var kIN {COND_PUSH;} expr do {COND_POP;}
+ | kFOR block_var kIN {COND_PUSH(1);} expr do {COND_POP();}
compstmt
kEND
{
@@ -1407,6 +1493,16 @@ do_block : kDO_BLOCK
fixpos($$, $3?$3:$4);
dyna_pop($<vars>2);
}
+ | tLBRACE_ARG {$<vars>$ = dyna_push();}
+ opt_block_var
+ compstmt
+ '}'
+ {
+ $$ = NEW_ITER($3, 0, $4);
+ fixpos($$, $3?$3:$4);
+ dyna_pop($<vars>2);
+ }
+
block_call : command do_block
{
@@ -1913,6 +2009,7 @@ yyerror(msg)
}
static int heredoc_end;
+static int command_start = Qtrue;
int ruby_in_compile = 0;
int ruby__end__seen;
@@ -1958,9 +2055,9 @@ yycompile(f, line)
ruby_debug_lines = 0;
compile_for_eval = 0;
ruby_in_compile = 0;
- cond_nest = 0;
cond_stack = 0;
cmdarg_stack = 0;
+ command_start = 1;
class_nest = 0;
in_single = 0;
in_def = 0;
@@ -2711,13 +2808,6 @@ here_document(term, indent)
lex_pbeg = lex_p = RSTRING(line)->ptr;
lex_pend = lex_p + RSTRING(line)->len;
-#if 0
- if (indent) {
- while (*lex_p && *lex_p == '\t') {
- lex_p++;
- }
- }
-#endif
retry:
switch (parse_string(term, '\n', '\n')) {
case tSTRING:
@@ -2791,13 +2881,18 @@ arg_ambiguous()
double strtod ();
#endif
+#define IS_ARG() (lex_state == EXPR_ARG || lex_state == EXPR_CMDARG)
+
static int
yylex()
{
register int c;
int space_seen = 0;
+ int cmd_state;
struct kwtable *kw;
+ cmd_state = command_start;
+ command_start = Qfalse;
retry:
switch (c = nextc()) {
case '\0': /* NUL */
@@ -2827,6 +2922,7 @@ yylex()
default:
break;
}
+ command_start = Qtrue;
lex_state = EXPR_BEG;
return '\n';
@@ -2846,7 +2942,7 @@ yylex()
return tOP_ASGN;
}
pushback(c);
- if (lex_state == EXPR_ARG && space_seen && !ISSPACE(c)){
+ if (IS_ARG() && space_seen && !ISSPACE(c)){
rb_warning("`*' interpreted as argument prefix");
c = tSTAR;
}
@@ -2913,7 +3009,7 @@ yylex()
c = nextc();
if (c == '<' &&
lex_state != EXPR_END && lex_state != EXPR_CLASS &&
- (lex_state != EXPR_ARG || space_seen)) {
+ (!IS_ARG() || space_seen)) {
int c2 = nextc();
int indent = 0;
if (c2 == '-') {
@@ -2980,7 +3076,7 @@ yylex()
rb_compile_error("incomplete character syntax");
return 0;
}
- if (lex_state == EXPR_ARG && ISSPACE(c)){
+ if (IS_ARG() && ISSPACE(c)){
pushback(c);
lex_state = EXPR_BEG;
return '?';
@@ -3009,8 +3105,8 @@ yylex()
return tOP_ASGN;
}
pushback(c);
- if (lex_state == EXPR_ARG && space_seen && !ISSPACE(c)){
- rb_warning("`&' interpreted as argument prefix");
+ if (IS_ARG() && space_seen && !ISSPACE(c)){
+ rb_warning("`&' interpeted as argument prefix");
c = tAMPER;
}
else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
@@ -3054,8 +3150,8 @@ yylex()
return tOP_ASGN;
}
if (lex_state == EXPR_BEG || lex_state == EXPR_MID ||
- (lex_state == EXPR_ARG && space_seen && !ISSPACE(c))) {
- if (lex_state == EXPR_ARG) arg_ambiguous();
+ (IS_ARG() && space_seen && !ISSPACE(c))) {
+ if (IS_ARG()) arg_ambiguous();
lex_state = EXPR_BEG;
pushback(c);
if (ISDIGIT(c)) {
@@ -3083,8 +3179,8 @@ yylex()
return tOP_ASGN;
}
if (lex_state == EXPR_BEG || lex_state == EXPR_MID ||
- (lex_state == EXPR_ARG && space_seen && !ISSPACE(c))) {
- if (lex_state == EXPR_ARG) arg_ambiguous();
+ (IS_ARG() && space_seen && !ISSPACE(c))) {
+ if (IS_ARG()) arg_ambiguous();
lex_state = EXPR_BEG;
pushback(c);
if (ISDIGIT(c)) {
@@ -3276,13 +3372,9 @@ yylex()
case ']':
case '}':
- lex_state = EXPR_END;
- return c;
-
case ')':
- if (cond_nest > 0) {
- cond_stack >>= 1;
- }
+ COND_LEXPOP();
+ CMDARG_LEXPOP();
lex_state = EXPR_END;
return c;
@@ -3290,7 +3382,7 @@ yylex()
c = nextc();
if (c == ':') {
if (lex_state == EXPR_BEG || lex_state == EXPR_MID ||
- (lex_state == EXPR_ARG && space_seen)) {
+ (IS_ARG() && space_seen)) {
lex_state = EXPR_BEG;
return tCOLON3;
}
@@ -3315,7 +3407,7 @@ yylex()
return tOP_ASGN;
}
pushback(c);
- if (lex_state == EXPR_ARG && space_seen) {
+ if (IS_ARG() && space_seen) {
if (!ISSPACE(c)) {
arg_ambiguous();
return parse_regx('/', '/');
@@ -3333,8 +3425,9 @@ yylex()
pushback(c);
return '^';
- case ',':
case ';':
+ command_start = Qtrue;
+ case ',':
lex_state = EXPR_BEG;
return c;
@@ -3348,15 +3441,21 @@ yylex()
return '~';
case '(':
- if (cond_nest > 0) {
- cond_stack = (cond_stack<<1)|0;
- }
+ command_start = Qtrue;
if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
c = tLPAREN;
}
- else if (lex_state == EXPR_ARG && space_seen) {
- rb_warning("%s (...) interpreted as method call", tok());
+ else if (space_seen) {
+ if (lex_state == EXPR_CMDARG) {
+ c = tLPAREN_ARG;
+ }
+ else if (lex_state == EXPR_ARG) {
+ rb_warning("%s (...) interpreted as method call", tok());
+ c = tLPAREN_ARG;
+ }
}
+ COND_PUSH(0);
+ CMDARG_PUSH(0);
lex_state = EXPR_BEG;
return c;
@@ -3375,15 +3474,23 @@ yylex()
else if (lex_state == EXPR_BEG || lex_state == EXPR_MID) {
c = tLBRACK;
}
- else if (lex_state == EXPR_ARG && space_seen) {
+ else if (IS_ARG() && space_seen) {
c = tLBRACK;
}
lex_state = EXPR_BEG;
+ COND_PUSH(0);
+ CMDARG_PUSH(0);
return c;
case '{':
- if (lex_state != EXPR_END && lex_state != EXPR_ARG)
- c = tLBRACE;
+ if (!IS_ARG()) {
+ if (lex_state != EXPR_END)
+ c = tLBRACE;
+ if (space_seen && CMDARG_P())
+ c = tLBRACE_ARG;
+ }
+ COND_PUSH(0);
+ CMDARG_PUSH(0);
lex_state = EXPR_BEG;
return c;
@@ -3446,7 +3553,7 @@ yylex()
yylval.id = '%';
return tOP_ASGN;
}
- if (lex_state == EXPR_ARG && space_seen && !ISSPACE(c)) {
+ if (IS_ARG() && space_seen && !ISSPACE(c)) {
goto quotation;
}
lex_state = EXPR_BEG;
@@ -3608,7 +3715,8 @@ yylex()
}
if (kw->id[0] == kDO) {
if (COND_P()) return kDO_COND;
- if (CMDARG_P()) return kDO_BLOCK;
+ if (CMDARG_P() && state != EXPR_CMDARG && state != EXPR_ARG)
+ return kDO_BLOCK;
return kDO;
}
if (state == EXPR_BEG)
@@ -3626,12 +3734,8 @@ yylex()
}
else {
if (lex_state == EXPR_FNAME) {
-#if 0
- if ((c = nextc()) == '=' && !peek('=') && !peek('~') && !peek('>')) {
-#else
if ((c = nextc()) == '=' && !peek('~') && !peek('>') &&
(!peek('=') || lex_p + 1 < lex_pend && lex_p[1] == '>')) {
-#endif
result = tIDENTIFIER;
tokadd(c);
}
@@ -3648,15 +3752,19 @@ yylex()
}
if (lex_state == EXPR_BEG ||
lex_state == EXPR_DOT ||
- lex_state == EXPR_ARG) {
- lex_state = EXPR_ARG;
+ lex_state == EXPR_ARG ||
+ lex_state == EXPR_CMDARG) {
+ if (cmd_state)
+ lex_state = EXPR_CMDARG;
+ else
+ lex_state = EXPR_ARG;
}
else {
lex_state = EXPR_END;
}
}
tokfix();
- yylval.id = rb_intern(tok());
+ last_id = yylval.id = rb_intern(tok());
return result;
}
}
@@ -4549,6 +4657,21 @@ logop(type, left, right)
}
static NODE *
+ret_args(node)
+ NODE *node;
+{
+ if (node) {
+ if (nd_type(node) == NODE_ARRAY && node->nd_next == 0) {
+ node = node->nd_head;
+ }
+ else if (nd_type(node) == NODE_BLOCK_PASS) {
+ rb_compile_error("block argument should not be given");
+ }
+ }
+ return node;
+}
+
+static NODE *
arg_blk_pass(node1, node2)
NODE *node1;
NODE *node2;
@@ -4561,6 +4684,27 @@ arg_blk_pass(node1, node2)
}
static NODE*
+arg_prepend(node1, node2)
+ NODE *node1, *node2;
+{
+ switch (nodetype(node2)) {
+ case NODE_ARRAY:
+ return list_concat(NEW_LIST(node1), node2);
+
+ case NODE_RESTARGS:
+ return arg_concat(node1, node2->nd_head);
+
+ case NODE_BLOCK_PASS:
+ node2->nd_body = arg_prepend(node1, node2->nd_body);
+ return node2;
+
+ default:
+ rb_bug("unknown nodetype(%d) for arg_prepend");
+ }
+ return 0; /* not reached */
+}
+
+static NODE*
new_call(r,m,a)
NODE *r;
ID m;
diff --git a/range.c b/range.c
index 627c704c77f..f6760ec9fa4 100644
--- a/range.c
+++ b/range.c
@@ -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");
diff --git a/re.c b/re.c
index 92e0420f508..bd8f34a1737 100644
--- a/re.c
+++ b/re.c
@@ -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;
diff --git a/regex.c b/regex.c
index eb4c530bad1..bd2d613e03f 100644
--- a/regex.c
+++ b/regex.c
@@ -370,6 +370,7 @@ enum regexpcode
duplicate, /* Match a duplicate of something remembered.
Followed by one byte containing the index of the memory
register. */
+ fail, /* always fails. */
wordchar, /* Matches any word-constituent character. */
notwordchar, /* Matches any char that is not a word-constituent. */
wordbeg, /* Succeeds if at word beginning. */
@@ -2246,32 +2247,23 @@ re_compile_pattern(pattern, size, bufp)
case '1': case '2': case '3':
case '4': case '5': case '6':
case '7': case '8': case '9':
- {
- const char *p_save;
-
- PATUNFETCH;
- p_save = p;
+ PATUNFETCH;
+ p0 = p;
- had_mbchar = 0;
+ had_mbchar = 0;
+ c1 = 0;
+ GET_UNSIGNED_NUMBER(c1);
+ if (!ISDIGIT(c)) PATUNFETCH;
+
+ if (9 < c1 && c1 >= regnum) {
+ /* need to get octal */
+ c = scan_oct(p0, 3, &numlen) & 0xff;
+ p = p0 + numlen;
c1 = 0;
- GET_UNSIGNED_NUMBER(c1);
- if (!ISDIGIT(c)) PATUNFETCH;
-
- if (c1 >= regnum) {
- /* need to get octal */
- p = p_save;
- c = scan_oct(p_save, 3, &numlen) & 0xff;
- p = p_save + numlen;
- c1 = 0;
- had_num_literal = 1;
- goto numeric_char;
- }
+ had_num_literal = 1;
+ goto numeric_char;
}
- /* Can't back reference to a subexpression if inside of it. */
- for (stackt = stackp - 2; stackt > stackb; stackt -= 5)
- if (*stackt == c1)
- goto normal_char;
laststart = b;
BUFPUSH(duplicate);
BUFPUSH(c1);
@@ -3736,11 +3728,16 @@ re_match(bufp, string_arg, size, pos, regs)
int regno = *p++; /* Get which register to match against */
register unsigned char *d2, *dend2;
- if (IS_ACTIVE(reg_info[regno])) break;
+#if 0
+ /* Check if corresponding group is still open */
+ if (IS_ACTIVE(reg_info[regno])) goto fail;
/* Where in input to try to start matching. */
d2 = regstart[regno];
- if (REG_UNSET(d2)) break;
+#else
+ d2 = IS_ACTIVE(reg_info[regno])?old_regstart[regno]:regstart[regno];
+#endif
+ if (REG_UNSET(d2)) goto fail;
/* Where to stop matching; if both the place to start and
the place to stop matching are in the same string, then
@@ -3748,7 +3745,7 @@ re_match(bufp, string_arg, size, pos, regs)
the end of the first string. */
dend2 = regend[regno];
- if (REG_UNSET(dend2)) break;
+ if (REG_UNSET(dend2)) goto fail;
for (;;) {
/* At end of register contents => success */
if (d2 == dend2) break;
diff --git a/ruby.c b/ruby.c
index 2c3102ed594..e0108299ee8 100644
--- a/ruby.c
+++ b/ruby.c
@@ -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;
diff --git a/ruby.h b/ruby.h
index 81a87b02be5..f13d76c5a62 100644
--- a/ruby.h
+++ b/ruby.h
@@ -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)
diff --git a/string.c b/string.c
index 660fa0c509d..5bf2c043980 100644
--- a/string.c
+++ b/string.c
@@ -28,6 +28,7 @@
VALUE rb_cString;
#define STR_NO_ORIG FL_USER2
+#define STR_ASSOC FL_USER3
VALUE rb_fs;
@@ -132,6 +133,40 @@ rb_str_new4(orig)
}
}
+#define STR_BUF_MIN_SIZE 128
+
+VALUE
+rb_str_buf_new(capa)
+ long capa;
+{
+ NEWOBJ(str, struct RString);
+ OBJSETUP(str, rb_cString, T_STRING);
+
+ FL_SET(str, STR_NO_ORIG);
+ if (capa < STR_BUF_MIN_SIZE)
+ capa = STR_BUF_MIN_SIZE;
+ str->ptr = 0;
+ str->len = 0;
+ str->orig = LONG2FIX(capa);
+ str->ptr = ALLOC_N(char, capa+1);
+ str->ptr[0] = '\0';
+
+ return (VALUE)str;
+}
+
+VALUE
+rb_str_buf_new2(ptr)
+ const char *ptr;
+{
+ VALUE str;
+ long len = strlen(ptr);
+
+ str = rb_str_buf_new(len + STR_BUF_MIN_SIZE);
+ rb_str_cat(str, ptr, len);
+
+ return str;
+}
+
VALUE
rb_str_to_str(str)
VALUE str;
@@ -176,7 +211,7 @@ rb_str_associate(str, add)
rb_str_modify(str);
}
RSTRING(str)->orig = rb_ary_new();
- FL_SET(str, STR_NO_ORIG);
+ FL_SET(str, STR_NO_ORIG|STR_ASSOC);
}
rb_ary_push(RSTRING(str)->orig, add);
}
@@ -185,7 +220,7 @@ VALUE
rb_str_associated(str)
VALUE str;
{
- if (!FL_TEST(str, STR_NO_ORIG)) {
+ if (!FL_TEST(str, STR_NO_ORIG|STR_ASSOC)) {
return Qfalse;
}
return RSTRING(str)->orig;
@@ -443,27 +478,69 @@ rb_str_resize(str, len)
}
VALUE
+rb_str_buf_cat(str, ptr, len)
+ VALUE str;
+ const char *ptr;
+ long len;
+{
+ long i, capa, total;
+
+ if (RSTRING(str)->orig == 0) {
+ capa = RSTRING(str)->len;
+ FL_SET(str, STR_NO_ORIG);
+ }
+ else {
+ capa = FIX2LONG(RSTRING(str)->orig);
+ }
+
+ total = RSTRING(str)->len+len;
+ if (capa <= total) {
+ while (total > capa) {
+ capa = (capa + 1) * 2;
+ }
+ REALLOC_N(RSTRING(str)->ptr, char, capa+1);
+ RSTRING(str)->orig = LONG2FIX(capa);
+ }
+ memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len);
+ RSTRING(str)->len = total;
+ RSTRING(str)->ptr[total] = '\0'; /* sentinel */
+
+ return str;
+}
+
+VALUE
+rb_str_buf_cat2(str, ptr)
+ VALUE str;
+ const char *ptr;
+{
+ return rb_str_buf_cat(str, ptr, strlen(ptr));
+}
+
+VALUE
rb_str_cat(str, ptr, len)
VALUE str;
const char *ptr;
long len;
{
- if (len > 0) {
- int poffset = -1;
+ long i, capa;
- rb_str_modify(str);
- if (RSTRING(str)->ptr <= ptr &&
- ptr < RSTRING(str)->ptr + RSTRING(str)->len) {
- poffset = ptr - RSTRING(str)->ptr;
+ rb_str_modify(str);
+ if (len > 0) {
+ if (RSTRING(str)->orig == 0 ||
+ (FL_TEST(str, STR_NO_ORIG) && !FL_TEST(str, STR_ASSOC))) {
+ return rb_str_buf_cat(str, ptr, len);
}
- REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len + len + 1);
+ REALLOC_N(RSTRING(str)->ptr, char, RSTRING(str)->len+1);
if (ptr) {
- if (poffset >= 0) ptr = RSTRING(str)->ptr + poffset;
memcpy(RSTRING(str)->ptr + RSTRING(str)->len, ptr, len);
}
+ else {
+ MEMZERO(RSTRING(str)->ptr + RSTRING(str)->len, char, len);
+ }
RSTRING(str)->len += len;
RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */
}
+
return str;
}
@@ -476,14 +553,61 @@ rb_str_cat2(str, ptr)
}
VALUE
-rb_str_append(str1, str2)
- VALUE str1, str2;
+rb_str_buf_append(str, str2)
+ VALUE str, str2;
{
+ long i, capa, len;
+
+ if (RSTRING(str)->orig == 0) {
+ capa = RSTRING(str)->len;
+ FL_SET(str, STR_NO_ORIG);
+ }
+ else {
+ capa = FIX2LONG(RSTRING(str)->orig);
+ }
+
+ len = RSTRING(str)->len+RSTRING(str2)->len;
+ if (capa <= len) {
+ while (len > capa) {
+ capa = (capa + 1) * 2;
+ }
+ REALLOC_N(RSTRING(str)->ptr, char, capa+1);
+ RSTRING(str)->orig = LONG2FIX(capa);
+ }
+ memcpy(RSTRING(str)->ptr + RSTRING(str)->len,
+ RSTRING(str2)->ptr, RSTRING(str2)->len);
+ RSTRING(str)->len += RSTRING(str2)->len;
+ RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */
+
+ return str;
+}
+
+VALUE
+rb_str_append(str, str2)
+ VALUE str, str2;
+{
+ long i, capa, len;
+
StringValue(str2);
- str1 = rb_str_cat(str1, RSTRING(str2)->ptr, RSTRING(str2)->len);
- OBJ_INFECT(str1, str2);
+ rb_str_modify(str);
+ len = RSTRING(str)->len+RSTRING(str2)->len;
+ if (len > 0) {
+ if (RSTRING(str)->orig == 0 ||
+ (FL_TEST(str, STR_NO_ORIG) && !FL_TEST(str, STR_ASSOC))) {
+ rb_str_buf_append(str, str2);
+ OBJ_INFECT(str, str2);
+
+ return str;
+ }
+ REALLOC_N(RSTRING(str)->ptr, char, len+1);
+ memcpy(RSTRING(str)->ptr + RSTRING(str)->len,
+ RSTRING(str2)->ptr, RSTRING(str2)->len);
+ RSTRING(str)->len += RSTRING(str2)->len;
+ RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; /* sentinel */
+ }
+ OBJ_INFECT(str, str2);
- return str1;
+ return str;
}
VALUE
@@ -998,6 +1122,7 @@ rb_str_update(str, beg, len, val)
}
RSTRING(str)->len += RSTRING(val)->len - len;
RSTRING(str)->ptr[RSTRING(str)->len] = '\0';
+ OBJ_INFECT(str, val);
}
static VALUE rb_str_sub_bang _((int, VALUE*, VALUE));
@@ -1518,7 +1643,7 @@ rb_str_inspect(str)
VALUE str;
{
char *p, *pend;
- VALUE result = rb_str_new2("\"");
+ VALUE result = rb_str_buf_new2("\"");
char s[5];
p = RSTRING(str)->ptr; pend = p + RSTRING(str)->len;
@@ -1526,51 +1651,51 @@ rb_str_inspect(str)
char c = *p++;
if (ismbchar(c) && p < pend) {
int len = mbclen(c);
- rb_str_cat(result, p - 1, len);
+ rb_str_buf_cat(result, p - 1, len);
p += len - 1;
}
else if (c == '"'|| c == '\\') {
s[0] = '\\'; s[1] = c;
- rb_str_cat(result, s, 2);
+ rb_str_buf_cat(result, s, 2);
}
else if (ISPRINT(c)) {
s[0] = c;
- rb_str_cat(result, s, 1);
+ rb_str_buf_cat(result, s, 1);
}
else if (c == '\n') {
s[0] = '\\'; s[1] = 'n';
- rb_str_cat(result, s, 2);
+ rb_str_buf_cat(result, s, 2);
}
else if (c == '\r') {
s[0] = '\\'; s[1] = 'r';
- rb_str_cat(result, s, 2);
+ rb_str_buf_cat(result, s, 2);
}
else if (c == '\t') {
s[0] = '\\'; s[1] = 't';
- rb_str_cat(result, s, 2);
+ rb_str_buf_cat(result, s, 2);
}
else if (c == '\f') {
s[0] = '\\'; s[1] = 'f';
- rb_str_cat(result, s, 2);
+ rb_str_buf_cat(result, s, 2);
}
else if (c == '\013') {
s[0] = '\\'; s[1] = 'v';
- rb_str_cat(result, s, 2);
+ rb_str_buf_cat(result, s, 2);
}
else if (c == '\007') {
s[0] = '\\'; s[1] = 'a';
- rb_str_cat(result, s, 2);
+ rb_str_buf_cat(result, s, 2);
}
else if (c == 033) {
s[0] = '\\'; s[1] = 'e';
- rb_str_cat(result, s, 2);
+ rb_str_buf_cat(result, s, 2);
}
else {
sprintf(s, "\\%03o", c & 0377);
- rb_str_cat2(result, s);
+ rb_str_buf_cat2(result, s);
}
}
- rb_str_cat2(result, "\"");
+ rb_str_buf_cat2(result, "\"");
OBJ_INFECT(result, str);
return result;
@@ -2661,7 +2786,7 @@ rb_str_crypt(str, salt)
StringValue(salt);
if (RSTRING(salt)->len < 2)
rb_raise(rb_eArgError, "salt too short(need >=2 bytes)");
- return rb_str_new2(crypt(RSTRING(str)->ptr, RSTRING(salt)->ptr));
+ return rb_tainted_str_new2(crypt(RSTRING(str)->ptr, RSTRING(salt)->ptr));
}
static VALUE
@@ -2738,6 +2863,7 @@ rb_str_ljust(str, w)
while (p < pend) {
*p++ = ' ';
}
+ OBJ_INFECT(res, str);
return res;
}
@@ -2757,6 +2883,7 @@ rb_str_rjust(str, w)
*p++ = ' ';
}
memcpy(pend, RSTRING(str)->ptr, RSTRING(str)->len);
+ OBJ_INFECT(res, str);
return res;
}
@@ -2782,6 +2909,7 @@ rb_str_center(str, w)
while (p < pend) {
*p++ = ' ';
}
+ OBJ_INFECT(res, str);
return res;
}
diff --git a/struct.c b/struct.c
index 82b69964a80..a07df5836fb 100644
--- a/struct.c
+++ b/struct.c
@@ -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++) {
diff --git a/time.c b/time.c
index 49aba768588..53b60e16cf1 100644
--- a/time.c
+++ b/time.c
@@ -314,7 +314,10 @@ make_time_t(tptr, utc_p)
{
time_t guess, guess_lo, guess_hi;
struct tm *tm, tm_lo, tm_hi;
- int d;
+ int d, have_guess;
+ int find_dst;
+
+ find_dst = 1;
#ifdef NEGATIVE_TIME_T
guess_lo = 1 << (8 * sizeof(time_t) - 1);
@@ -322,7 +325,7 @@ make_time_t(tptr, utc_p)
guess_lo = 0;
#endif
guess_hi = ((time_t)-1) < ((time_t)0) ?
- (1U << (8 * sizeof(time_t) - 1)) - 1 :
+ (1UL << (8 * sizeof(time_t) - 1)) - 1 :
~(time_t)0;
tm = (utc_p ? gmtime : localtime)(&guess_lo);
@@ -339,62 +342,87 @@ make_time_t(tptr, utc_p)
if (d == 0) return guess_hi;
tm_hi = *tm;
- while (guess_lo + 1 < guess_hi) { /* there is a gap between lo and hi. */
- unsigned long range;
- int a, b;
- /*
- Try precious guess by a linear interpolation at first.
- `a' and `b' is a coefficient of guess_lo and guess_hi.
- `range' is approximation of maximum error by the interpolation.
- (a + b)**2 should be less than 2**31 to avoid overflow.
- When these parameter is wrong, binary search is used.
- */
- a = (tm_hi.tm_year - tptr->tm_year);
- b = (tptr->tm_year - tm_lo.tm_year);
- range = 366 * 24 * 3600;
- if (a + b < 46000 / 366) {
- /* 46000 is selected as `some big number less than sqrt(2**31)'. */
- /* The distinction between leap/non-leap year is not important here. */
- static int days[] = {
- 0,
- 0 + 31,
- 0 + 31 + 29,
- 0 + 31 + 29 + 31,
- 0 + 31 + 29 + 31 + 30,
- 0 + 31 + 29 + 31 + 30 + 31,
- 0 + 31 + 29 + 31 + 30 + 31 + 30,
- 0 + 31 + 29 + 31 + 30 + 31 + 30 + 31,
- 0 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31,
- 0 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30,
- 0 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31,
- 0 + 31 + 29 + 31 + 30 + 31 + 30 + 31 + 31 + 30 + 31 + 30
- /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov */
- };
- a *= 366;
- b *= 366;
- d = days[tptr->tm_mon] + tptr->tm_mday;
- a += days[tm_hi.tm_mon] + tm_hi.tm_mday - d;
- b += d - (days[tm_lo.tm_mon] + tm_lo.tm_mday);
- range = 2 * 24 * 3600;
- }
- if (a + b <= 1) {
- range = 2;
- a *= 24 * 3600;
- b *= 24 * 3600;
- d = tptr->tm_hour * 3600 + tptr->tm_min * 60 + tptr->tm_sec;
- a += tm_hi.tm_hour * 3600 + tm_hi.tm_min * 60 + tm_hi.tm_sec - d;
- b += d - (tm_lo.tm_hour * 3600 + tm_lo.tm_min * 60 + tm_lo.tm_sec);
+ have_guess = 0;
+
+ while (guess_lo + 1 < guess_hi) {
+ /* there is a gap between guess_lo and guess_hi. */
+ unsigned long range = 0;
+ if (!have_guess) {
+ int a, b;
+ /*
+ Try precious guess by a linear interpolation at first.
+ `a' and `b' is a coefficient of guess_lo and guess_hi as:
+
+ guess = (guess_lo * a + guess_hi * b) / (a + b)
+
+ However this causes overflow in most cases, following assignment
+ is used instead:
+
+ guess = guess_lo / d * a + (guess_lo % d) * a / d
+ + guess_hi / d * b + (guess_hi % d) * b / d
+ where d = a + b
+
+ To avoid overflow in this assignment, `d' is restricted to less than
+ sqrt(2**31). By this restriction and other reasons, the guess is
+ not accurate and some error is expected. `range' approximates
+ the maximum error.
+
+ When these parameters are not suitable, i.e. guess is not within
+ guess_lo and guess_hi, simple guess by binary search is used.
+ */
+ range = 366 * 24 * 60 * 60;
+ a = (tm_hi.tm_year - tptr->tm_year);
+ b = (tptr->tm_year - tm_lo.tm_year);
+ /* 46000 is selected as `some big number less than sqrt(2**31)'. */
+ if (a + b <= 46000 / 12) {
+ range = 31 * 24 * 60 * 60;
+ a *= 12;
+ b *= 12;
+ a += tm_hi.tm_mon - tptr->tm_mon;
+ b += tptr->tm_mon - tm_lo.tm_mon;
+ if (a + b <= 46000 / 31) {
+ range = 24 * 60 * 60;
+ a *= 31;
+ b *= 31;
+ a += tm_hi.tm_mday - tptr->tm_mday;
+ b += tptr->tm_mday - tm_lo.tm_mday;
+ if (a + b <= 46000 / 24) {
+ range = 60 * 60;
+ a *= 24;
+ b *= 24;
+ a += tm_hi.tm_hour - tptr->tm_hour;
+ b += tptr->tm_hour - tm_lo.tm_hour;
+ if (a + b <= 46000 / 60) {
+ range = 60;
+ a *= 60;
+ b *= 60;
+ a += tm_hi.tm_min - tptr->tm_min;
+ b += tptr->tm_min - tm_lo.tm_min;
+ if (a + b <= 46000 / 60) {
+ range = 1;
+ a *= 60;
+ b *= 60;
+ a += tm_hi.tm_sec - tptr->tm_sec;
+ b += tptr->tm_sec - tm_lo.tm_sec;
+ }
+ }
+ }
+ }
+ }
+ if (a <= 0) a = 1;
+ if (b <= 0) b = 1;
+ d = a + b;
+ /*
+ Although `/' and `%' may produce unexpected result with negative
+ argument, it doesn't cause serious problem because there is a
+ fail safe.
+ */
+ guess = guess_lo / d * a + (guess_lo % d) * a / d
+ + guess_hi / d * b + (guess_hi % d) * b / d;
+ have_guess = 1;
}
- if (a <= 0) a = 1;
- if (b <= 0) b = 1;
- d = a + b;
- guess = guess_lo / d * a + guess_hi / d * b;
- /* Although `%' may not work with negative value,
- it doesn't cause serious problem because there is a fail safe. */
- guess += ((guess_lo % d) * a + (guess_hi % d) * b) / d;
-
- fixguess:
- if (guess <= guess_lo || guess >= guess_hi) {
+
+ if (guess <= guess_lo || guess_hi <= guess) {
/* Precious guess is invalid. try binary search. */
guess = guess_lo / 2 + guess_hi / 2;
if (guess <= guess_lo)
@@ -406,53 +434,99 @@ make_time_t(tptr, utc_p)
tm = (utc_p ? gmtime : localtime)(&guess);
if (!tm) goto error;
+ have_guess = 0;
d = tmcmp(tptr, tm);
- if (d == 0) {
- if (!utc_p && !tm->tm_isdst) {
- /* When leaving DST, there may be two time corresponding to given
- argument. make_time_t returns DST in such cases. */
- /* xxx this assumes a difference in time as 3600 seconds. */
- time_t guess2 = guess - 3600;
- tm = localtime(&guess2);
- if (!tm) return guess;
- if (tmcmp(tptr, tm) == 0)
- return guess2;
- }
- return guess;
- }
- else if (d < 0) {
+ if (d < 0) {
guess_hi = guess;
tm_hi = *tm;
- if (range && range < (unsigned long)(guess_hi - guess_lo)) {
+ if (range) {
guess = guess - range;
range = 0;
- goto fixguess;
+ if (guess_lo < guess && guess < guess_hi)
+ have_guess = 1;
}
}
- else {
+ else if (d > 0) {
guess_lo = guess;
tm_lo = *tm;
- if (range && range < (unsigned long)(guess_hi - guess_lo)) {
+ if (range) {
guess = guess + range;
range = 0;
- goto fixguess;
+ if (guess_lo < guess && guess < guess_hi)
+ have_guess = 1;
}
}
+ else {
+ if (!utc_p) {
+ /* If localtime is nonmonotonic, another result may exist. */
+ time_t guess2;
+ if (find_dst) {
+ guess2 = guess - 2 * 60 * 60;
+ tm = localtime(&guess2);
+ if (tm) {
+ if (tptr->tm_hour != (tm->tm_hour + 2) % 24 ||
+ tptr->tm_min != tm->tm_min ||
+ tptr->tm_sec != tm->tm_sec) {
+ guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
+ (tm->tm_min - tptr->tm_min) * 60 +
+ (tm->tm_sec - tptr->tm_sec);
+ if (tptr->tm_mday != tm->tm_mday)
+ guess2 += 24 * 60 * 60;
+ if (guess != guess2) {
+ tm = localtime(&guess2);
+ if (tmcmp(tptr, tm) == 0) {
+ if (guess < guess2)
+ return guess;
+ else
+ return guess2;
+ }
+ }
+ }
+ }
+ }
+ else {
+ guess2 = guess + 2 * 60 * 60;
+ tm = localtime(&guess2);
+ if (tm) {
+ if ((tptr->tm_hour + 2) % 24 != tm->tm_hour ||
+ tptr->tm_min != tm->tm_min ||
+ tptr->tm_sec != tm->tm_sec) {
+ guess2 -= (tm->tm_hour - tptr->tm_hour) * 60 * 60 +
+ (tm->tm_min - tptr->tm_min) * 60 +
+ (tm->tm_sec - tptr->tm_sec);
+ if (tptr->tm_mday != tm->tm_mday)
+ guess2 -= 24 * 60 * 60;
+ if (guess != guess2) {
+ tm = localtime(&guess2);
+ if (tmcmp(tptr, tm) == 0) {
+ if (guess < guess2)
+ return guess2;
+ else
+ return guess;
+ }
+ }
+ }
+ }
+ }
+ }
+ return guess;
+ }
}
- /* given time is not found. */
- if (guess_lo + 1 == guess_hi) {
- /* given argument is invalid: 04/29 at non-leap year for example. */
- return guess_hi;
+ /* Given argument has no corresponding time_t. Let's outerpolation. */
+ if (tm_lo.tm_year == tptr->tm_year && tm_lo.tm_mon == tptr->tm_mon) {
+ return guess_lo +
+ (tptr->tm_mday - tm_lo.tm_mday) * 24 * 60 * 60 +
+ (tptr->tm_hour - tm_lo.tm_hour) * 60 * 60 +
+ (tptr->tm_min - tm_lo.tm_min) * 60 +
+ (tptr->tm_sec - tm_lo.tm_sec);
}
- else {
- /* given argument is in a gap. When it enters DST, for example. */
- d = tptr->tm_sec - tm_lo.tm_sec;
- d += (tptr->tm_min - tm_lo.tm_min) * 60;
- d += (tptr->tm_hour - tm_lo.tm_hour) * 3600;
- if (d < 0)
- d += 24 * 3600;
- return guess_hi + d - 1;
+ else if (tm_hi.tm_year == tptr->tm_year && tm_hi.tm_mon == tptr->tm_mon) {
+ return guess_hi +
+ (tptr->tm_mday - tm_hi.tm_mday) * 24 * 60 * 60 +
+ (tptr->tm_hour - tm_hi.tm_hour) * 60 * 60 +
+ (tptr->tm_min - tm_hi.tm_min) * 60 +
+ (tptr->tm_sec - tm_hi.tm_sec);
}
out_of_range:
diff --git a/variable.c b/variable.c
index 4286f560864..fe0272d21e4 100644
--- a/variable.c
+++ b/variable.c
@@ -16,6 +16,7 @@
#include "env.h"
#include "node.h"
#include "st.h"
+#include "util.h"
static st_table *rb_global_tbl;
st_table *rb_class_tbl;
diff --git a/version.h b/version.h
index dae01613f4a..b732f529f65 100644
--- a/version.h
+++ b/version.h
@@ -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