/* * call-seq: * str.chomp!(separator=$/) => str or nil * * Modifies <i>str</i> in place as described for <code>String#chomp</code>, * returning <i>str</i>, or <code>nil</code> if no modifications were made. */ static VALUE rb_str_chomp_bang(argc, argv, str) int argc; VALUE *argv; VALUE str; { VALUE rs; int newline; char *p; long len, rslen; if (rb_scan_args(argc, argv, "01", &rs) == 0) { len = RSTRING(str)->len; if (len == 0) return Qnil; p = RSTRING(str)->ptr; rs = rb_rs; if (rs == rb_default_rs) { smart_chomp: rb_str_modify(str); if (RSTRING(str)->ptr[len-1] == '\n') { RSTRING(str)->len--; if (RSTRING(str)->len > 0 && RSTRING(str)->ptr[RSTRING(str)->len-1] == '\r') { RSTRING(str)->len--; } } else if (RSTRING(str)->ptr[len-1] == '\r') { RSTRING(str)->len--; } else { return Qnil; } RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; return str; } } if (NIL_P(rs)) return Qnil; StringValue(rs); len = RSTRING(str)->len; if (len == 0) return Qnil; p = RSTRING(str)->ptr; rslen = RSTRING(rs)->len; if (rslen == 0) { while (len>0 && p[len-1] == '\n') { len--; if (len>0 && p[len-1] == '\r') len--; } if (len < RSTRING(str)->len) { rb_str_modify(str); RSTRING(str)->len = len; RSTRING(str)->ptr[len] = '\0'; return str; } return Qnil; } if (rslen > len) return Qnil; newline = RSTRING(rs)->ptr[rslen-1]; if (rslen == 1 && newline == '\n') goto smart_chomp; if (p[len-1] == newline && (rslen <= 1 || rb_memcmp(RSTRING(rs)->ptr, p+len-rslen, rslen) == 0)) { rb_str_modify(str); RSTRING(str)->len -= rslen; RSTRING(str)->ptr[RSTRING(str)->len] = '\0'; return str; } return Qnil; }