* eval.c (rb_f_require): searches ".rb" and ".so" at the same

time.  previous behavior (search ".rb", then ".so") has a
  security risk (ruby-bugs#PR140).

* array.c (rb_ary_to_ary): new function to replace internal
  rb_Array(), which never calls to_a, but to_ary (rb_Array() might
  call both). [new]

* regex.c (PUSH_FAILURE_POINT): push option status again.

* regex.c (re_compile_pattern): avoid pushing unnecessary
  option_set.

* eval.c (rb_load): tainted string is OK if wrapped *and*
  $SAFE >= 4.

* eval.c (rb_thread_start_0): should not nail down higher blocks
  before preserving original context (i.e. should not alter
  original context).

* eval.c (proc_yield): new method equivalent to Proc#call but no
  check for number of arguments. [new]


git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@1526 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
matz 2001-06-19 04:35:17 +00:00
parent 6aa71d4c80
commit 9d51cf8a6a
10 changed files with 253 additions and 108 deletions

View File

@ -1,9 +1,42 @@
Mon Jun 18 17:38:50 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (rb_f_require): searches ".rb" and ".so" at the same
time. previous behavior (search ".rb", then ".so") has a
security risk (ruby-bugs#PR140).
* array.c (rb_ary_to_ary): new function to replace internal
rb_Array(), which never calls to_a, but to_ary (rb_Array() might
call both). [new]
Mon Jun 18 00:43:20 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* regex.c (PUSH_FAILURE_POINT): push option status again.
* regex.c (re_compile_pattern): avoid pushing unnecessary
option_set.
Sat Jun 16 10:58:48 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (rb_load): tainted string is OK if wrapped *and*
$SAFE >= 4.
Thu Jun 14 16:27:07 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (rb_thread_start_0): should not nail down higher blocks
before preserving original context (i.e. should not alter
original context).
Wed Jun 13 19:34:59 2001 Akinori MUSHA <knu@iDaemons.org> Wed Jun 13 19:34:59 2001 Akinori MUSHA <knu@iDaemons.org>
* dir.c (Init_Dir): add a new method File::fnmatch? along with * dir.c (Init_Dir): add a new method File::fnmatch? along with
File::Constants::FNM_*. While I am here, FNM_NOCASE is renamed File::Constants::FNM_*. While I am here, FNM_NOCASE is renamed
to FNM_CASEFOLD which is commonly used by *BSD and GNU libc. to FNM_CASEFOLD which is commonly used by *BSD and GNU libc.
Wed Jun 13 09:33:45 2001 Yukihiro Matsumoto <matz@ruby-lang.org>
* eval.c (proc_yield): new method equivalent to Proc#call but no
check for number of arguments. [new]
Tue Jun 12 14:21:28 2001 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp> Tue Jun 12 14:21:28 2001 Nobuyoshi Nakada <nobu.nakada@nifty.ne.jp>
* lib/mkmf.rb: target_prefix is only for installation, not for * lib/mkmf.rb: target_prefix is only for installation, not for

1
ToDo
View File

@ -83,6 +83,7 @@ Standard Libraries
* hash etc. should handle self referenceing array/hash * hash etc. should handle self referenceing array/hash
* move NameError under StandardError. * move NameError under StandardError.
* library to load per-user profile seeking .ruby_profile or ruby.ini file. * library to load per-user profile seeking .ruby_profile or ruby.ini file.
* warning framework
Extension Libraries Extension Libraries

17
array.c
View File

@ -17,6 +17,7 @@
#include "st.h" #include "st.h"
VALUE rb_cArray; VALUE rb_cArray;
static ID cmp;
#define ARY_DEFAULT_SIZE 16 #define ARY_DEFAULT_SIZE 16
@ -729,6 +730,20 @@ to_ary(ary)
return rb_convert_type(ary, T_ARRAY, "Array", "to_ary"); return rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
} }
VALUE
rb_ary_to_ary(obj)
VALUE obj;
{
if (NIL_P(obj)) return rb_ary_new2(0);
if (TYPE(obj) == T_ARRAY) {
return obj;
}
if (rb_respond_to(obj, rb_intern("to_ary"))) {
return rb_convert_type(obj, T_ARRAY, "Array", "to_ary");
}
return rb_ary_new3(1, obj);
}
extern VALUE rb_output_fs; extern VALUE rb_output_fs;
static VALUE static VALUE
@ -958,8 +973,6 @@ rb_ary_reverse_m(ary)
return rb_ary_reverse(rb_obj_dup(ary)); return rb_ary_reverse(rb_obj_dup(ary));
} }
static ID cmp;
static int static int
sort_1(a, b) sort_1(a, b)
VALUE *a, *b; VALUE *a, *b;

111
eval.c
View File

@ -1676,7 +1676,7 @@ copy_node_scope(node, rval)
char *file = ruby_sourcefile;\ char *file = ruby_sourcefile;\
int line = ruby_sourceline;\ int line = ruby_sourceline;\
if (TYPE(args) != T_ARRAY)\ if (TYPE(args) != T_ARRAY)\
args = rb_Array(args);\ args = rb_ary_to_ary(args);\
argc = RARRAY(args)->len;\ argc = RARRAY(args)->len;\
argv = ALLOCA_N(VALUE, argc);\ argv = ALLOCA_N(VALUE, argc);\
MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);\ MEMCPY(argv, RARRAY(args)->ptr, VALUE, argc);\
@ -2129,7 +2129,7 @@ rb_eval(self, n)
VALUE v = rb_eval(self, tag->nd_head->nd_head); VALUE v = rb_eval(self, tag->nd_head->nd_head);
int i; int i;
if (TYPE(v) != T_ARRAY) v = rb_Array(v); if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v);
for (i=0; i<RARRAY(v)->len; i++) { for (i=0; i<RARRAY(v)->len; i++) {
if (RTEST(RARRAY(v)->ptr[i])) { if (RTEST(RARRAY(v)->ptr[i])) {
node = node->nd_body; node = node->nd_body;
@ -2174,7 +2174,7 @@ rb_eval(self, n)
VALUE v = rb_eval(self, tag->nd_head->nd_head); VALUE v = rb_eval(self, tag->nd_head->nd_head);
int i; int i;
if (TYPE(v) != T_ARRAY) v = rb_Array(v); if (TYPE(v) != T_ARRAY) v = rb_ary_to_ary(v);
for (i=0; i<RARRAY(v)->len; i++) { for (i=0; i<RARRAY(v)->len; i++) {
if (RTEST(rb_funcall2(RARRAY(v)->ptr[i], eqq, 1, &val))){ if (RTEST(rb_funcall2(RARRAY(v)->ptr[i], eqq, 1, &val))){
node = node->nd_body; node = node->nd_body;
@ -2347,14 +2347,14 @@ rb_eval(self, n)
case NODE_RESTARY: case NODE_RESTARY:
result = rb_eval(self, node->nd_head); result = rb_eval(self, node->nd_head);
if (TYPE(result) != T_ARRAY) { if (TYPE(result) != T_ARRAY) {
result = rb_Array(result); result = rb_ary_to_ary(result);
} }
break; break;
case NODE_REXPAND: case NODE_REXPAND:
result = rb_eval(self, node->nd_head); result = rb_eval(self, node->nd_head);
if (TYPE(result) != T_ARRAY) { if (TYPE(result) != T_ARRAY) {
result = rb_Array(result); result = rb_ary_to_ary(result);
} }
if (RARRAY(result)->len == 0) { if (RARRAY(result)->len == 0) {
result = Qnil; result = Qnil;
@ -2520,7 +2520,7 @@ rb_eval(self, n)
case NODE_ARGSCAT: case NODE_ARGSCAT:
result = rb_ary_concat(rb_eval(self, node->nd_head), result = rb_ary_concat(rb_eval(self, node->nd_head),
rb_Array(rb_eval(self, node->nd_body))); rb_ary_to_ary(rb_eval(self, node->nd_body)));
break; break;
case NODE_ARGSPUSH: case NODE_ARGSPUSH:
@ -3546,16 +3546,20 @@ rb_f_block_given_p()
return Qfalse; return Qfalse;
} }
#define PC_NONE 0x0
#define PC_ACHECK 0x1
#define PC_PCALL 0x2
static VALUE static VALUE
rb_yield_0(val, self, klass, acheck) rb_yield_0(val, self, klass, pcall)
VALUE val, self, klass; /* OK */ VALUE val, self, klass; /* OK */
int acheck; int pcall;
{ {
NODE *node; NODE *node;
volatile VALUE result = Qnil; volatile VALUE result = Qnil;
volatile VALUE old_cref; volatile VALUE old_cref;
struct BLOCK *block; struct BLOCK * volatile block;
struct SCOPE *old_scope; struct SCOPE * volatile old_scope;
struct FRAME frame; struct FRAME frame;
int state; int state;
static unsigned serial = 1; static unsigned serial = 1;
@ -3591,7 +3595,7 @@ rb_yield_0(val, self, klass, acheck)
PUSH_TAG(PROT_NONE); PUSH_TAG(PROT_NONE);
if ((state = EXEC_TAG()) == 0) { if ((state = EXEC_TAG()) == 0) {
if (block->var == (NODE*)1) { if (block->var == (NODE*)1) {
if (acheck && val != Qundef && if ((pcall&PC_ACHECK) && val != Qundef &&
TYPE(val) == T_ARRAY && RARRAY(val)->len != 0) { TYPE(val) == T_ARRAY && RARRAY(val)->len != 0) {
rb_raise(rb_eArgError, "wrong # of arguments (%d for 0)", rb_raise(rb_eArgError, "wrong # of arguments (%d for 0)",
RARRAY(val)->len); RARRAY(val)->len);
@ -3605,14 +3609,14 @@ rb_yield_0(val, self, klass, acheck)
} }
else { else {
if (nd_type(block->var) == NODE_MASGN) if (nd_type(block->var) == NODE_MASGN)
massign(self, block->var, val, acheck); massign(self, block->var, val, (pcall&PC_ACHECK));
else { else {
/* argument adjust for proc_call etc. */ /* argument adjust for proc_call etc. */
if (acheck && val != Qundef && if (pcall && val != Qundef &&
TYPE(val) == T_ARRAY && RARRAY(val)->len == 1) { TYPE(val) == T_ARRAY && RARRAY(val)->len == 1) {
val = RARRAY(val)->ptr[0]; val = RARRAY(val)->ptr[0];
} }
assign(self, block->var, val, acheck); assign(self, block->var, val, (pcall&PC_ACHECK));
} }
} }
} }
@ -3621,7 +3625,7 @@ rb_yield_0(val, self, klass, acheck)
} }
else { else {
/* argument adjust for proc_call etc. */ /* argument adjust for proc_call etc. */
if (acheck && val != Qundef && if (pcall && val != Qundef &&
TYPE(val) == T_ARRAY && RARRAY(val)->len == 1) { TYPE(val) == T_ARRAY && RARRAY(val)->len == 1) {
val = RARRAY(val)->ptr[0]; val = RARRAY(val)->ptr[0];
} }
@ -5171,7 +5175,12 @@ rb_load(fname, wrap)
NODE *saved_cref = ruby_cref; NODE *saved_cref = ruby_cref;
TMP_PROTECT; TMP_PROTECT;
SafeStringValue(fname); if (wrap && ruby_safe_level >= 4) {
StringValue(fname);
}
else {
SafeStringValue(fname);
}
file = rb_find_file(RSTRING(fname)->ptr); file = rb_find_file(RSTRING(fname)->ptr);
if (!file) { if (!file) {
rb_raise(rb_eLoadError, "No such file to load -- %s", RSTRING(fname)->ptr); rb_raise(rb_eLoadError, "No such file to load -- %s", RSTRING(fname)->ptr);
@ -5402,28 +5411,20 @@ rb_f_require(obj, fname)
} }
buf = ALLOCA_N(char, strlen(RSTRING(fname)->ptr) + 5); buf = ALLOCA_N(char, strlen(RSTRING(fname)->ptr) + 5);
strcpy(buf, RSTRING(fname)->ptr); strcpy(buf, RSTRING(fname)->ptr);
strcat(buf, ".rb"); switch (rb_find_file_noext(buf)) {
if (rb_find_file(buf)) { case 0:
break;
case 1:
fname = rb_str_new2(buf); fname = rb_str_new2(buf);
feature = buf; file = feature = buf;
goto load_rb; goto load_rb;
}
strcpy(buf, RSTRING(fname)->ptr); default:
strcat(buf, DLEXT);
file = rb_find_file(buf);
if (file) {
feature = buf; feature = buf;
file = rb_find_file(buf);
goto load_dyna; goto load_dyna;
} }
#ifdef DLEXT2
strcpy(buf, RSTRING(fname)->ptr);
strcat(buf, DLEXT2);
file = rb_find_file(buf);
if (file) {
feature = buf;
goto load_dyna;
}
#endif
rb_raise(rb_eLoadError, "No such file to load -- %s", rb_raise(rb_eLoadError, "No such file to load -- %s",
RSTRING(fname)->ptr); RSTRING(fname)->ptr);
@ -6330,8 +6331,9 @@ callargs(args)
} }
static VALUE static VALUE
proc_call(proc, args) proc_invoke(proc, args, pcall)
VALUE proc, args; /* OK */ VALUE proc, args; /* OK */
int pcall;
{ {
struct BLOCK * volatile old_block; struct BLOCK * volatile old_block;
struct BLOCK _block; struct BLOCK _block;
@ -6341,6 +6343,13 @@ proc_call(proc, args)
volatile int orphan; volatile int orphan;
volatile int safe = ruby_safe_level; volatile int safe = ruby_safe_level;
if (pcall) {
pcall = PC_ACHECK|PC_PCALL;
}
else {
pcall = PC_PCALL;
}
if (rb_block_given_p() && ruby_frame->last_func) { if (rb_block_given_p() && ruby_frame->last_func) {
rb_warning("block for %s#%s is useless", rb_warning("block for %s#%s is useless",
rb_class2name(CLASS_OF(proc)), rb_class2name(CLASS_OF(proc)),
@ -6367,7 +6376,7 @@ proc_call(proc, args)
state = EXEC_TAG(); state = EXEC_TAG();
if (state == 0) { if (state == 0) {
proc_set_safe_level(proc); proc_set_safe_level(proc);
result = rb_yield_0(args, 0, 0, Qtrue); result = rb_yield_0(args, 0, 0, pcall);
} }
POP_TAG(); POP_TAG();
@ -6398,6 +6407,20 @@ proc_call(proc, args)
return result; return result;
} }
static VALUE
proc_call(proc, args)
VALUE proc, args; /* OK */
{
return proc_invoke(proc, args, Qtrue);
}
static VALUE
proc_yield(proc, args)
VALUE proc, args; /* OK */
{
return proc_invoke(proc, args, Qfalse);
}
static VALUE static VALUE
proc_arity(proc) proc_arity(proc)
VALUE proc; VALUE proc;
@ -6899,6 +6922,7 @@ Init_Proc()
rb_define_singleton_method(rb_cProc, "new", proc_s_new, -1); rb_define_singleton_method(rb_cProc, "new", proc_s_new, -1);
rb_define_method(rb_cProc, "call", proc_call, -2); rb_define_method(rb_cProc, "call", proc_call, -2);
rb_define_method(rb_cProc, "yield", proc_yield, -2);
rb_define_method(rb_cProc, "arity", proc_arity, 0); rb_define_method(rb_cProc, "arity", proc_arity, 0);
rb_define_method(rb_cProc, "[]", proc_call, -2); rb_define_method(rb_cProc, "[]", proc_call, -2);
rb_define_method(rb_cProc, "==", proc_eq, 1); rb_define_method(rb_cProc, "==", proc_eq, 1);
@ -8210,7 +8234,11 @@ rb_thread_start_0(fn, arg, th_arg)
} }
#endif #endif
if (ruby_block) { /* should nail down higher scopes */ if (THREAD_SAVE_CONTEXT(curr_thread)) {
return thread;
}
if (ruby_block) { /* should nail down higher blocks */
struct BLOCK dummy; struct BLOCK dummy;
dummy.prev = ruby_block; dummy.prev = ruby_block;
@ -8219,9 +8247,6 @@ rb_thread_start_0(fn, arg, th_arg)
} }
scope_dup(ruby_scope); scope_dup(ruby_scope);
FL_SET(ruby_scope, SCOPE_SHARED); FL_SET(ruby_scope, SCOPE_SHARED);
if (THREAD_SAVE_CONTEXT(curr_thread)) {
return thread;
}
if (!th->next) { if (!th->next) {
/* merge in thread list */ /* merge in thread list */
@ -8243,17 +8268,21 @@ rb_thread_start_0(fn, arg, th_arg)
POP_TAG(); POP_TAG();
status = th->status; status = th->status;
if (th == main_thread) ruby_stop(state);
rb_thread_remove(th);
while (saved_block) { while (saved_block) {
struct BLOCK *tmp = saved_block; struct BLOCK *tmp = saved_block;
if (curr_thread == main_thread) {
printf("free(%p)\n", saved_block);
}
if (tmp->frame.argc > 0) if (tmp->frame.argc > 0)
free(tmp->frame.argv); free(tmp->frame.argv);
saved_block = tmp->prev; saved_block = tmp->prev;
free(tmp); free(tmp);
} }
if (th == main_thread) ruby_stop(state);
rb_thread_remove(th);
if (state && status != THREAD_TO_KILL && !NIL_P(ruby_errinfo)) { if (state && status != THREAD_TO_KILL && !NIL_P(ruby_errinfo)) {
th->flags |= THREAD_RAISED; th->flags |= THREAD_RAISED;
if (state == TAG_FATAL) { if (state == TAG_FATAL) {

110
file.c
View File

@ -2202,41 +2202,76 @@ is_macos_native_path(path)
} }
#endif #endif
static char*
file_load_ok(file)
char *file;
{
FILE *f;
f = fopen(file, "r");
if (f == NULL) return 0;
fclose(f);
return file;
}
extern VALUE rb_load_path;
int
rb_find_file_noext(file)
char *file;
{
char *path, *e, *found;
char *fend = file + strlen(file);
VALUE fname;
int i, j;
static char *ext[] = {
".rb", DLEXT,
#ifdef DLEXT2
DLEXT2,
#endif
0
};
if (file[0] == '~') {
fname = rb_str_new2(file);
fname = rb_file_s_expand_path(1, &fname);
file = StringValuePtr(fname);
}
if (is_absolute_path(file)) {
for (i=0; ext[i]; i++) {
strcpy(fend, ext[i]);
if (file_load_ok(file)) return i+1;
}
return 0;
}
if (!rb_load_path) return 0;
Check_Type(rb_load_path, T_ARRAY);
for (i=0;i<RARRAY(rb_load_path)->len;i++) {
VALUE str = RARRAY(rb_load_path)->ptr[i];
SafeStringValue(str);
path = RSTRING(str)->ptr;
for (j=0; ext[j]; j++) {
strcpy(fend, ext[j]);
found = dln_find_file(file, path);
if (found && file_load_ok(found)) return j+1;
}
}
return 0;
}
char* char*
rb_find_file(file) rb_find_file(file)
char *file; char *file;
{ {
extern VALUE rb_load_path;
VALUE vpath, fname; VALUE vpath, fname;
char *path; char *path;
struct stat st; struct stat st;
#if defined(__MACOS__) || defined(riscos)
if (is_macos_native_path(file)) {
FILE *f;
if (rb_safe_level() >= 2 && !rb_path_check(file)) {
rb_raise(rb_eSecurityError, "loading from unsafe file %s", file);
}
f= fopen(file, "r");
if (f == NULL) return 0;
fclose(f);
return file;
}
#endif
if (is_absolute_path(file)) {
FILE *f;
if (rb_safe_level() >= 2 && !rb_path_check(file)) {
rb_raise(rb_eSecurityError, "loading from unsafe file %s", file);
}
f = fopen(file, "r");
if (f == NULL) return 0;
fclose(f);
return file;
}
if (file[0] == '~') { if (file[0] == '~') {
fname = rb_str_new2(file); fname = rb_str_new2(file);
fname = rb_file_s_expand_path(1, &fname); fname = rb_file_s_expand_path(1, &fname);
@ -2246,6 +2281,22 @@ rb_find_file(file)
file = StringValuePtr(fname); file = StringValuePtr(fname);
} }
#if defined(__MACOS__) || defined(riscos)
if (is_macos_native_path(file)) {
if (rb_safe_level() >= 2 && !rb_path_check(file)) {
rb_raise(rb_eSecurityError, "loading from unsafe file %s", file);
}
return file_load_ok(file);
}
#endif
if (is_absolute_path(file)) {
if (rb_safe_level() >= 2 && !rb_path_check(file)) {
rb_raise(rb_eSecurityError, "loading from unsafe file %s", file);
}
return file_load_ok(file);
}
if (rb_load_path) { if (rb_load_path) {
int i; int i;
@ -2269,10 +2320,7 @@ rb_find_file(file)
} }
path = dln_find_file(file, path); path = dln_find_file(file, path);
if (path && stat(path, &st) == 0) { return file_load_ok(path);
return path;
}
return 0;
} }
static void static void

View File

@ -27,6 +27,7 @@ VALUE rb_ary_new4 _((long, VALUE *));
VALUE rb_ary_freeze _((VALUE)); VALUE rb_ary_freeze _((VALUE));
VALUE rb_ary_aref _((int, VALUE*, VALUE)); VALUE rb_ary_aref _((int, VALUE*, VALUE));
void rb_ary_store _((VALUE, long, VALUE)); void rb_ary_store _((VALUE, long, VALUE));
VALUE rb_ary_to_ary _((VALUE));
VALUE rb_ary_to_s _((VALUE)); VALUE rb_ary_to_s _((VALUE));
VALUE rb_ary_push _((VALUE, VALUE)); VALUE rb_ary_push _((VALUE, VALUE));
VALUE rb_ary_pop _((VALUE)); VALUE rb_ary_pop _((VALUE));
@ -179,6 +180,7 @@ void rb_thread_atfork _((void));
int eaccess _((const char*, int)); int eaccess _((const char*, int));
VALUE rb_file_s_expand_path _((int, VALUE *)); VALUE rb_file_s_expand_path _((int, VALUE *));
void rb_file_const _((const char*, VALUE)); void rb_file_const _((const char*, VALUE));
int rb_find_file_noext _((char*));
char *rb_find_file _((char*)); char *rb_find_file _((char*));
/* gc.c */ /* gc.c */
void rb_gc_mark_locations _((VALUE*, VALUE*)); void rb_gc_mark_locations _((VALUE*, VALUE*));

6
io.c
View File

@ -3462,10 +3462,8 @@ opt_i_set(val)
VALUE val; VALUE val;
{ {
if (ruby_inplace_mode) free(ruby_inplace_mode); if (ruby_inplace_mode) free(ruby_inplace_mode);
if (!RTEST(val)) { ruby_inplace_mode = 0;
ruby_inplace_mode = 0; if (!RTEST(val)) return;
return;
}
StringValue(val); StringValue(val);
ruby_inplace_mode = strdup(RSTRING(val)->ptr); ruby_inplace_mode = strdup(RSTRING(val)->ptr);
} }

View File

@ -854,7 +854,7 @@ class Resolv
raise DecodeError.new("limit exceed") if @limit < @index + len raise DecodeError.new("limit exceed") if @limit < @index + len
arr = @data.unpack("@#{@index}#{template}") arr = @data.unpack("@#{@index}#{template}")
@index += len @index += len
return *arr return arr
end end
def get_string def get_string

View File

@ -660,21 +660,24 @@ An end of a defun is found by moving forward from the beginning of one."
(cond (cond
((featurep 'font-lock) ((featurep 'font-lock)
(or (boundp 'font-lock-variable-name-face)
(setq font-lock-variable-name-face font-lock-type-face))
(setq ruby-font-lock-syntactic-keywords
'(("\\$\\([#\"'`$\\]\\)" 1 (1 . nil)) (add-hook 'ruby-mode-hook
("\\(#\\)[{$@]" 1 (1 . nil)) '(lambda ()
("\\(/\\)\\([^/\n]\\|\\/\\)*\\(/\\)" (make-local-variable 'font-lock-syntactic-keywords)
(1 (7 . ?')) (setq font-lock-syntactic-keywords
(3 (7 . ?'))) '(("\\$\\([#\"'`$\\]\\)" 1 (1 . nil))
("^\\(=\\)begin\\(\\s \\|$\\)" 1 (7 . nil)) ("\\(#\\)[{$@]" 1 (1 . nil))
("^\\(=\\)end\\(\\s \\|$\\)" 1 (7 . nil)))) ("\\(/\\)\\([^/\n]\\|\\/\\)*\\(/\\)"
(put major-mode 'font-lock-defaults (1 (7 . ?'))
'((ruby-font-lock-keywords) (3 (7 . ?')))
nil nil nil ("^\\(=\\)begin\\(\\s \\|$\\)" 1 (7 . nil))
beginning-of-line ("^\\(=\\)end\\(\\s \\|$\\)" 1 (7 . nil))))
(font-lock-syntactic-keywords (make-local-variable 'font-lock-defaults)
. ruby-font-lock-syntactic-keywords))) (setq font-lock-defaults '((ruby-font-lock-keywords) nil nil))
(setq font-lock-keywords ruby-font-lock-keywords)))
(defun ruby-font-lock-docs (limit) (defun ruby-font-lock-docs (limit)
(if (re-search-forward "^=begin\\(\\s \\|$\\)" limit t) (if (re-search-forward "^=begin\\(\\s \\|$\\)" limit t)
@ -687,6 +690,21 @@ An end of a defun is found by moving forward from the beginning of one."
(set-match-data (list beg (point))) (set-match-data (list beg (point)))
t))))) t)))))
(defun ruby-font-lock-maybe-docs (limit)
(let (beg)
(save-excursion
(if (and (re-search-backward "^=\\(begin\\|end\\)\\(\\s \\|$\\)" nil t)
(string= (match-string-no-properties 1) "begin"))
(progn
(beginning-of-line)
(setq beg (point)))))
(if (and beg (and (re-search-forward "^=\\(begin\\|end\\)\\(\\s \\|$\\)" nil t)
(string= (match-string-no-properties 1) "end")))
(progn
(set-match-data (list beg (point)))
t)
nil)))
(defvar ruby-font-lock-keywords (defvar ruby-font-lock-keywords
(list (list
(cons (concat (cons (concat
@ -741,6 +759,8 @@ An end of a defun is found by moving forward from the beginning of one."
;; embedded document ;; embedded document
'(ruby-font-lock-docs '(ruby-font-lock-docs
0 font-lock-comment-face t) 0 font-lock-comment-face t)
'(ruby-font-lock-maybe-docs
0 font-lock-comment-face t)
;; constants ;; constants
'("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)" '("\\(^\\|[^_]\\)\\b\\([A-Z]+\\(\\w\\|_\\)*\\)"
2 font-lock-type-face) 2 font-lock-type-face)

31
regex.c
View File

@ -1874,8 +1874,10 @@ re_compile_pattern(pattern, size, bufp)
if ((options ^ stackp[-1]) & RE_OPTION_IGNORECASE) { if ((options ^ stackp[-1]) & RE_OPTION_IGNORECASE) {
BUFPUSH((options&RE_OPTION_IGNORECASE)?casefold_off:casefold_on); BUFPUSH((options&RE_OPTION_IGNORECASE)?casefold_off:casefold_on);
} }
BUFPUSH(option_set); if ((options ^ stackp[-1]) != RE_OPTION_IGNORECASE) {
BUFPUSH(stackp[-1]); BUFPUSH(option_set);
BUFPUSH(stackp[-1]);
}
} }
p0 = b; p0 = b;
options = *--stackp; options = *--stackp;
@ -3262,7 +3264,8 @@ re_search(bufp, string, size, startpos, range, regs)
} }
if (startpos > size) return -1; if (startpos > size) return -1;
if (anchor && size > 0 && startpos == size) return -1; if ((anchor || !bufp->can_be_null) && size > 0 && startpos == size)
return -1;
val = re_match(bufp, string, size, startpos, regs); val = re_match(bufp, string, size, startpos, regs);
if (val >= 0) return startpos; if (val >= 0) return startpos;
if (val == -2) return -2; if (val == -2) return -2;
@ -3362,7 +3365,7 @@ re_search(bufp, string, size, startpos, range, regs)
#define NUM_COUNT_ITEMS 2 #define NUM_COUNT_ITEMS 2
/* Individual items aside from the registers. */ /* Individual items aside from the registers. */
#define NUM_NONREG_ITEMS 3 #define NUM_NONREG_ITEMS 4
/* We push at most this many things on the stack whenever we /* We push at most this many things on the stack whenever we
fail. The `+ 2' refers to PATTERN_PLACE and STRING_PLACE, which are fail. The `+ 2' refers to PATTERN_PLACE and STRING_PLACE, which are
@ -3412,6 +3415,7 @@ re_search(bufp, string, size, startpos, range, regs)
\ \
*stackp++ = pattern_place; \ *stackp++ = pattern_place; \
*stackp++ = string_place; \ *stackp++ = string_place; \
*stackp++ = (unsigned char*)options; /* current option status */ \
*stackp++ = (unsigned char*)0; /* non-greedy flag */ \ *stackp++ = (unsigned char*)0; /* non-greedy flag */ \
} while(0) } while(0)
@ -3735,15 +3739,11 @@ re_match(bufp, string_arg, size, pos, regs)
int regno = *p++; /* Get which register to match against */ int regno = *p++; /* Get which register to match against */
register unsigned char *d2, *dend2; register unsigned char *d2, *dend2;
#if 0
/* Check if corresponding group is still open */ /* Check if corresponding group is still open */
if (IS_ACTIVE(reg_info[regno])) goto fail; if (IS_ACTIVE(reg_info[regno])) goto fail;
/* Where in input to try to start matching. */ /* Where in input to try to start matching. */
d2 = regstart[regno]; d2 = regstart[regno];
#else
d2 = IS_ACTIVE(reg_info[regno])?old_regstart[regno]:regstart[regno];
#endif
if (REG_UNSET(d2)) goto fail; if (REG_UNSET(d2)) goto fail;
/* Where to stop matching; if both the place to start and /* Where to stop matching; if both the place to start and
@ -3791,7 +3791,7 @@ re_match(bufp, string_arg, size, pos, regs)
case stop_nowidth: case stop_nowidth:
EXTRACT_NUMBER_AND_INCR(mcnt, p); EXTRACT_NUMBER_AND_INCR(mcnt, p);
stackp = stackb + mcnt; stackp = stackb + mcnt;
d = stackp[-2]; d = stackp[-3];
POP_FAILURE_POINT(); POP_FAILURE_POINT();
continue; continue;
@ -4015,8 +4015,8 @@ re_match(bufp, string_arg, size, pos, regs)
because didn't fail. Also remove the register information because didn't fail. Also remove the register information
put on by the on_failure_jump. */ put on by the on_failure_jump. */
case finalize_jump: case finalize_jump:
if (stackp > stackb && stackp[-2] == d) { if (stackp > stackb && stackp[-3] == d) {
p = stackp[-3]; p = stackp[-4];
POP_FAILURE_POINT(); POP_FAILURE_POINT();
continue; continue;
} }
@ -4032,7 +4032,7 @@ re_match(bufp, string_arg, size, pos, regs)
case jump: case jump:
nofinalize: nofinalize:
EXTRACT_NUMBER_AND_INCR(mcnt, p); EXTRACT_NUMBER_AND_INCR(mcnt, p);
if (mcnt < 0 && stackp > stackb && stackp[-2] == d) /* avoid infinite loop */ if (mcnt < 0 && stackp > stackb && stackp[-3] == d) /* avoid infinite loop */
goto fail; goto fail;
p += mcnt; p += mcnt;
continue; continue;
@ -4123,7 +4123,7 @@ re_match(bufp, string_arg, size, pos, regs)
case finalize_push: case finalize_push:
POP_FAILURE_POINT(); POP_FAILURE_POINT();
EXTRACT_NUMBER_AND_INCR(mcnt, p); EXTRACT_NUMBER_AND_INCR(mcnt, p);
if (mcnt < 0 && stackp > stackb && stackp[-2] == d) /* avoid infinite loop */ if (mcnt < 0 && stackp > stackb && stackp[-3] == d) /* avoid infinite loop */
goto fail; goto fail;
PUSH_FAILURE_POINT(p + mcnt, d); PUSH_FAILURE_POINT(p + mcnt, d);
stackp[-1] = NON_GREEDY; stackp[-1] = NON_GREEDY;
@ -4288,11 +4288,12 @@ re_match(bufp, string_arg, size, pos, regs)
/* If this failure point is from a dummy_failure_point, just /* If this failure point is from a dummy_failure_point, just
skip it. */ skip it. */
if (stackp[-3] == 0 || (best_regs_set && stackp[-1] == NON_GREEDY)) { if (stackp[-4] == 0 || (best_regs_set && stackp[-1] == NON_GREEDY)) {
POP_FAILURE_POINT(); POP_FAILURE_POINT();
goto fail; goto fail;
} }
stackp--; /* discard flag */ stackp--; /* discard greedy flag */
options = (int)*--stackp;
d = *--stackp; d = *--stackp;
p = *--stackp; p = *--stackp;
/* Restore register info. */ /* Restore register info. */