/* * call-seq: * str.sub!(pattern, replacement) => str or nil * str.sub!(pattern) {|match| block } => str or nil * * Performs the substitutions of <code>String#sub</code> in place, * returning <i>str</i>, or <code>nil</code> if no substitutions were * performed. */ static VALUE rb_str_sub_bang(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE pat, repl, match; struct re_registers *regs; int iter = 0; int tainted = 0; long plen; if (argc == 1 && rb_block_given_p()) { iter = 1; } else if (argc == 2) { repl = argv[1]; StringValue(repl); if (OBJ_TAINTED(repl)) tainted = 1; } else { rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc); } pat = get_pat(argv[0], 1); if (rb_reg_search(pat, str, 0, 0) >= 0) { rb_str_modify(str); match = rb_backref_get(); regs = RMATCH(match)->regs; if (iter) { char *p = RSTRING(str)->ptr; long len = RSTRING(str)->len; rb_match_busy(match); repl = rb_obj_as_string(rb_yield(rb_reg_nth_match(0, match))); str_mod_check(str, p, len); str_frozen_check(str); rb_backref_set(match); } else { repl = rb_reg_regsub(repl, str, regs); } if (OBJ_TAINTED(repl)) tainted = 1; plen = END(0) - BEG(0); if (RSTRING(repl)->len > plen) { RESIZE_CAPA(str, RSTRING(str)->len + RSTRING(repl)->len - plen); } if (RSTRING(repl)->len != plen) { memmove(RSTRING(str)->ptr + BEG(0) + RSTRING(repl)->len, RSTRING(str)->ptr + BEG(0) + plen, RSTRING(str)->len - BEG(0) - plen); } memcpy(RSTRING(str)->ptr + BEG(0), RSTRING(repl)->ptr, RSTRING(repl)->len); RSTRING(str)->len += RSTRING(repl)->len - plen; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; if (tainted) OBJ_TAINT(str); return str; } return Qnil; }