diff --git a/array.c b/array.c index bbf4c1d4c7..e3c331c833 100644 --- a/array.c +++ b/array.c @@ -242,7 +242,7 @@ rb_ary_set_shared(VALUE ary, VALUE shared) static inline void rb_ary_modify_check(VALUE ary) { - if (OBJ_FROZEN(ary)) rb_error_frozen("array"); + rb_check_frozen(ary); if (!OBJ_UNTRUSTED(ary) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify array"); } diff --git a/ext/readline/readline.c b/ext/readline/readline.c index ac88c84f59..80358debe4 100644 --- a/ext/readline/readline.c +++ b/ext/readline/readline.c @@ -43,10 +43,20 @@ static VALUE mReadline; #define EDIT_LINE_LIBRARY_VERSION "EditLine wrapper" +#ifndef USE_INSERT_IGNORE_ESCAPE +# ifndef HAVE_EDITLINE_READLINE_H +# define USE_INSERT_IGNORE_ESCAPE 1 +# else +# define USE_INSERT_IGNORE_ESCAPE 0 +# endif +#endif #define COMPLETION_PROC "completion_proc" #define COMPLETION_CASE_FOLD "completion_case_fold" static ID completion_proc, completion_case_fold; +#if USE_INSERT_IGNORE_ESCAPE +static ID id_orig_prompt, id_last_prompt, id_ignore_escape; +#endif #ifndef HAVE_RL_FILENAME_COMPLETION_FUNCTION # define rl_filename_completion_function filename_completion_function @@ -145,6 +155,81 @@ readline_event(void) } #endif +#if USE_INSERT_IGNORE_ESCAPE +static VALUE +insert_ignore_escape(VALUE self, VALUE prompt) +{ + VALUE last_prompt, orig_prompt = rb_attr_get(self, id_orig_prompt); + int ignoring = 0; + const char *s0, *s, *e; + long len; + static const char ignore_code[2] = {RL_PROMPT_START_IGNORE, RL_PROMPT_END_IGNORE}; + + prompt = rb_str_new_shared(prompt); + last_prompt = rb_attr_get(self, id_last_prompt); + if (orig_prompt == prompt) return last_prompt; + len = RSTRING_LEN(prompt); + if (NIL_P(last_prompt)) { + last_prompt = rb_str_tmp_new(len); + } + + s = s0 = RSTRING_PTR(prompt); + e = s0 + len; + rb_str_set_len(last_prompt, 0); + while (s < e && *s) { + switch (*s) { + case RL_PROMPT_START_IGNORE: + ignoring = -1; + rb_str_cat(last_prompt, s0, ++s - s0); + s0 = s; + break; + case RL_PROMPT_END_IGNORE: + ignoring = 0; + rb_str_cat(last_prompt, s0, ++s - s0); + s0 = s; + break; + case '\033': + if (++s < e && *s == '[') { + rb_str_cat(last_prompt, s0, s - s0 - 1); + s0 = s - 1; + while (++s < e && *s) { + if (ISALPHA(*s)) { + if (!ignoring) { + ignoring = 1; + rb_str_cat(last_prompt, ignore_code+0, 1); + } + rb_str_cat(last_prompt, s0, ++s - s0); + s0 = s; + break; + } + else if (!('0' <= *s && *s <= '9' || *s == ';')) { + break; + } + } + } + break; + default: + if (ignoring > 0) { + ignoring = 0; + rb_str_cat(last_prompt, ignore_code+1, 1); + } + s++; + break; + } + } + if (ignoring > 0) { + ignoring = 0; + rb_str_cat(last_prompt, ignore_code+1, 1); + } + rb_str_cat(last_prompt, s0, s - s0); + + rb_ivar_set(self, id_orig_prompt, prompt); + rb_ivar_set(self, id_last_prompt, last_prompt); + + return last_prompt; +} +#endif + static VALUE readline_get(VALUE prompt) { @@ -244,10 +329,18 @@ readline_readline(int argc, VALUE *argv, VALUE self) char *prompt = NULL; char *buff; int status; + int ignore_escape = 0; rb_secure(4); if (rb_scan_args(argc, argv, "02", &tmp, &add_hist) > 0) { OutputStringValue(tmp); +#if USE_INSERT_IGNORE_ESCAPE + ignore_escape = RTEST(rb_attr_get(mReadline, id_ignore_escape)); + if (ignore_escape) { + tmp = insert_ignore_escape(self, tmp); + rb_str_locktmp(tmp); + } +#endif prompt = RSTRING_PTR(tmp); } @@ -257,6 +350,11 @@ readline_readline(int argc, VALUE *argv, VALUE self) rl_prep_terminal(1); #endif buff = (char*)rb_protect(readline_get, (VALUE)prompt, &status); +#if USE_INSERT_IGNORE_ESCAPE + if (prompt && ignore_escape) { + rb_str_unlocktmp(tmp); + } +#endif if (status) { #if defined HAVE_RL_CLEANUP_AFTER_SIGNAL /* restore terminal mode and signal handler*/ @@ -1312,6 +1410,27 @@ username_completion_proc_call(VALUE self, VALUE str) return result; } +static VALUE +readline_s_ignore_escape(VALUE self) +{ +#if USE_INSERT_IGNORE_ESCAPE + return RTEST(rb_attr_get(mReadline, id_ignore_escape)) ? Qtrue : Qfalse; +#elif defined HAVE_EDITLINE_READLINE_H + return Qtrue; +#else + return Qfalse; +#endif +} + +static VALUE +readline_s_ignore_escape_set(VALUE self, VALUE flag) +{ +#if USE_INSERT_IGNORE_ESCAPE + rb_ivar_set(mReadline, id_ignore_escape, RTEST(flag) ? Qtrue : Qfalse); +#endif + return flag; +} + void Init_readline() { @@ -1383,6 +1502,18 @@ Init_readline() rb_define_singleton_method(mReadline, "refresh_line", readline_s_refresh_line, 0); +#if USE_INSERT_IGNORE_ESCAPE + rb_define_singleton_method(mReadline, "ignore_escape", + readline_s_ignore_escape, 0); + rb_define_singleton_method(mReadline, "ignore_escape=", + readline_s_ignore_escape_set, 1); + + CONST_ID(id_orig_prompt, "orig_prompt"); + CONST_ID(id_last_prompt, "last_prompt"); + CONST_ID(id_ignore_escape, "ignore_escape"); + rb_ivar_set(mReadline, id_ignore_escape, Qtrue); +#endif + history = rb_obj_alloc(rb_cObject); rb_extend_object(history, rb_mEnumerable); rb_define_singleton_method(history,"to_s", hist_to_s, 0); diff --git a/gc.c b/gc.c index b011f4a1c3..99aacdb3d5 100644 --- a/gc.c +++ b/gc.c @@ -2677,7 +2677,7 @@ static VALUE undefine_final(VALUE os, VALUE obj) { rb_objspace_t *objspace = &rb_objspace; - if (OBJ_FROZEN(obj)) rb_error_frozen("object"); + rb_check_frozen(obj); if (finalizer_table) { st_data_t data = obj; st_delete(finalizer_table, &data, 0); @@ -2703,7 +2703,7 @@ define_final(int argc, VALUE *argv, VALUE os) st_data_t data; rb_scan_args(argc, argv, "11", &obj, &block); - if (OBJ_FROZEN(obj)) rb_error_frozen("object"); + rb_check_frozen(obj); if (argc == 1) { block = rb_block_proc(); } diff --git a/hash.c b/hash.c index 0d1898313b..873219a433 100644 --- a/hash.c +++ b/hash.c @@ -248,7 +248,7 @@ rb_hash_dup(VALUE hash) static void rb_hash_modify_check(VALUE hash) { - if (OBJ_FROZEN(hash)) rb_error_frozen("hash"); + rb_check_frozen(hash); if (!OBJ_UNTRUSTED(hash) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify hash"); } diff --git a/misc/ruby-mode.el b/misc/ruby-mode.el index 0072f1e0d5..9a21c485a9 100644 --- a/misc/ruby-mode.el +++ b/misc/ruby-mode.el @@ -451,8 +451,12 @@ The variable ruby-indent-level controls the amount of indentation. (or (eq (char-syntax (char-before (point))) ?w) (ruby-special-char-p)))) nil) - ((and (eq option 'heredoc) (< space 0)) t) - ((or (looking-at ruby-operator-re) + ((and (progn (goto-char start) (eq option 'heredoc)) + (progn (forward-word -1) + (not (and (or (bolp) (not (eq (char-before (point)) ?_))) + (looking-at "class<<"))))) + t) + ((or (progn (goto-char start) (looking-at ruby-operator-re)) (looking-at "[\\[({,;]") (and (looking-at "[!?]") (or (not (eq option 'modifier)) diff --git a/object.c b/object.c index 5ad5680d88..7eecf49bfc 100644 --- a/object.c +++ b/object.c @@ -712,9 +712,7 @@ rb_obj_taint(VALUE obj) { rb_secure(4); if (!OBJ_TAINTED(obj)) { - if (OBJ_FROZEN(obj)) { - rb_error_frozen("object"); - } + rb_check_frozen(obj); OBJ_TAINT(obj); } return obj; @@ -733,9 +731,7 @@ rb_obj_untaint(VALUE obj) { rb_secure(3); if (OBJ_TAINTED(obj)) { - if (OBJ_FROZEN(obj)) { - rb_error_frozen("object"); - } + rb_check_frozen(obj); FL_UNSET(obj, FL_TAINT); } return obj; @@ -768,9 +764,7 @@ rb_obj_untrust(VALUE obj) { rb_secure(4); if (!OBJ_UNTRUSTED(obj)) { - if (OBJ_FROZEN(obj)) { - rb_error_frozen("object"); - } + rb_check_frozen(obj); OBJ_UNTRUST(obj); } return obj; @@ -789,9 +783,7 @@ rb_obj_trust(VALUE obj) { rb_secure(3); if (OBJ_UNTRUSTED(obj)) { - if (OBJ_FROZEN(obj)) { - rb_error_frozen("object"); - } + rb_check_frozen(obj); FL_UNSET(obj, FL_UNTRUSTED); } return obj; diff --git a/string.c b/string.c index efb0481937..daabb97a46 100644 --- a/string.c +++ b/string.c @@ -350,14 +350,6 @@ str_mod_check(VALUE s, const char *p, long len) } } -static inline void -str_frozen_check(VALUE s) -{ - if (OBJ_FROZEN(s)) { - rb_raise(rb_eRuntimeError, "string frozen"); - } -} - size_t rb_str_capacity(VALUE str) { @@ -1250,7 +1242,7 @@ str_modifiable(VALUE str) if (FL_TEST(str, STR_TMPLOCK)) { rb_raise(rb_eRuntimeError, "can't modify string; temporarily locked"); } - if (OBJ_FROZEN(str)) rb_error_frozen("string"); + rb_check_frozen(str); if (!OBJ_UNTRUSTED(str) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify string"); } @@ -1335,7 +1327,7 @@ void rb_str_associate(VALUE str, VALUE add) { /* sanity check */ - if (OBJ_FROZEN(str)) rb_error_frozen("string"); + rb_check_frozen(str); if (STR_ASSOC_P(str)) { /* already associated */ rb_ary_concat(RSTRING(str)->as.heap.aux.shared, add); @@ -3546,7 +3538,7 @@ rb_str_sub_bang(int argc, VALUE *argv, VALUE str) repl = rb_obj_as_string(repl); } str_mod_check(str, p, len); - str_frozen_check(str); + rb_check_frozen(str); } else { repl = rb_reg_regsub(repl, str, regs, pat); diff --git a/struct.c b/struct.c index f0a377c211..78f836f8f5 100644 --- a/struct.c +++ b/struct.c @@ -151,7 +151,7 @@ static VALUE (*const ref_func[])(VALUE) = { static void rb_struct_modify(VALUE s) { - if (OBJ_FROZEN(s)) rb_error_frozen("Struct"); + rb_check_frozen(s); if (!OBJ_UNTRUSTED(s) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify Struct"); } diff --git a/transcode.c b/transcode.c index 17bad37e27..cd4829f291 100644 --- a/transcode.c +++ b/transcode.c @@ -2711,9 +2711,7 @@ str_encode_bang(int argc, VALUE *argv, VALUE str) VALUE newstr; int encidx; - if (OBJ_FROZEN(str)) { /* in future, may use str_frozen_check from string.c, but that's currently static */ - rb_raise(rb_eRuntimeError, "string frozen"); - } + rb_check_frozen(str); newstr = str; encidx = str_transcode(argc, argv, &newstr); diff --git a/variable.c b/variable.c index ce5c2b8258..46717e73c4 100644 --- a/variable.c +++ b/variable.c @@ -1043,7 +1043,7 @@ rb_ivar_set(VALUE obj, ID id, VALUE val) if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); - if (OBJ_FROZEN(obj)) rb_error_frozen("object"); + rb_check_frozen(obj); switch (TYPE(obj)) { case T_OBJECT: iv_index_tbl = ROBJECT_IV_INDEX_TBL(obj); @@ -1305,7 +1305,7 @@ rb_obj_remove_instance_variable(VALUE obj, VALUE name) if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); - if (OBJ_FROZEN(obj)) rb_error_frozen("object"); + rb_check_frozen(obj); if (!rb_is_instance_id(id)) { rb_name_error(id, "`%s' is not allowed as an instance variable name", rb_id2name(id)); } @@ -1653,8 +1653,7 @@ rb_const_remove(VALUE mod, ID id) if (!OBJ_UNTRUSTED(mod) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't remove constant"); - if (OBJ_FROZEN(mod)) rb_error_frozen("class/module"); - + rb_check_frozen(mod); if (!RCLASS_IV_TBL(mod) || !st_delete(RCLASS_IV_TBL(mod), &n, &v)) { if (rb_const_defined_at(mod, id)) { rb_name_error(id, "cannot remove %s::%s", @@ -1819,14 +1818,7 @@ mod_av_set(VALUE klass, ID id, VALUE val, int isconst) if (!OBJ_UNTRUSTED(klass) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't set %s", dest); - if (OBJ_FROZEN(klass)) { - if (BUILTIN_TYPE(klass) == T_MODULE) { - rb_error_frozen("module"); - } - else { - rb_error_frozen("class"); - } - } + rb_check_frozen(klass); if (!RCLASS_IV_TBL(klass)) { RCLASS_IV_TBL(klass) = st_init_numtable(); } @@ -2075,8 +2067,7 @@ rb_mod_remove_cvar(VALUE mod, VALUE name) } if (!OBJ_UNTRUSTED(mod) && rb_safe_level() >= 4) rb_raise(rb_eSecurityError, "Insecure: can't remove class variable"); - if (OBJ_FROZEN(mod)) rb_error_frozen("class/module"); - + rb_check_frozen(mod); if (RCLASS_IV_TBL(mod) && st_delete(RCLASS_IV_TBL(mod), &n, &val)) { return (VALUE)val; } diff --git a/vm.c b/vm.c index 084c30964a..27185f6786 100644 --- a/vm.c +++ b/vm.c @@ -1858,10 +1858,7 @@ vm_define_method(rb_thread_t *th, VALUE obj, ID id, VALUE iseqval, rb_id2name(id), rb_obj_classname(obj)); } - if (OBJ_FROZEN(obj)) { - rb_error_frozen("object"); - } - + rb_check_frozen(obj); klass = rb_singleton_class(obj); noex = NOEX_PUBLIC; } diff --git a/vm_insnhelper.c b/vm_insnhelper.c index 75e0f91b36..236b3fd3f5 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1298,9 +1298,8 @@ vm_setivar(VALUE obj, ID id, VALUE val, IC ic) if (!OBJ_UNTRUSTED(obj) && rb_safe_level() >= 4) { rb_raise(rb_eSecurityError, "Insecure: can't modify instance variable"); } - if (OBJ_FROZEN(obj)) { - rb_error_frozen("object"); - } + + rb_check_frozen(obj); if (TYPE(obj) == T_OBJECT) { VALUE klass = RBASIC(obj)->klass; diff --git a/vm_method.c b/vm_method.c index a76277c81d..41c53a5b47 100644 --- a/vm_method.c +++ b/vm_method.c @@ -211,10 +211,8 @@ rb_method_entry_make(VALUE klass, ID mid, rb_method_type_t type, rb_class2name(rb_ivar_get(klass, attached))); mid = ID_ALLOCATOR; } - if (OBJ_FROZEN(klass)) { - rb_error_frozen("class/module"); - } + rb_check_frozen(klass); mtbl = RCLASS_M_TBL(klass); /* check re-definition */ @@ -463,8 +461,7 @@ remove_method(VALUE klass, ID mid) if (rb_safe_level() >= 4 && !OBJ_UNTRUSTED(klass)) { rb_raise(rb_eSecurityError, "Insecure: can't remove method"); } - if (OBJ_FROZEN(klass)) - rb_error_frozen("class/module"); + rb_check_frozen(klass); if (mid == object_id || mid == id__send__ || mid == idInitialize) { rb_warn("removing `%s' may cause serious problems", rb_id2name(mid)); }