/*
* 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) {
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);
}
rb_str_modify(str);
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;
}