/*
 *  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;
}