rdata.dollar = repstr ? js_strchr(JSSTRING_CHARS(repstr), '$') : NULL;
if (repstr) { rdata.dollarEnd = JSSTRING_CHARS(repstr) + JSSTRING_LENGTH(repstr); rdata.dollar = js_strchr_limit(JSSTRING_CHARS(repstr), '$', rdata.dollarEnd); } else { rdata.dollar = rdata.dollarEnd = NULL; }
str_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval){#if JS_HAS_REGEXPS    JSObject *lambda;    JSString *repstr, *str;    ReplaceData rdata;    jschar *chars;    size_t leftlen, rightlen, length;#if JS_HAS_REPLACE_LAMBDA    if (JS_TypeOfValue(cx, argv[1]) == JSTYPE_FUNCTION) {        lambda = JSVAL_TO_OBJECT(argv[1]);        repstr = NULL;    } else#endif    {        if (!JS_ConvertValue(cx, argv[1], JSTYPE_STRING, &argv[1]))            return JS_FALSE;        repstr = JSVAL_TO_STRING(argv[1]);        if (!js_UndependString(cx, repstr))     /* XXX flatten for js_strchr */            return JS_FALSE;        lambda = NULL;    }    rdata.base.optarg = 2;    rdata.base.mode = GLOB_REPLACE;    rdata.lambda = lambda;    rdata.repstr = repstr;    rdata.dollar = repstr ? js_strchr(JSSTRING_CHARS(repstr), '$') : NULL;    rdata.chars = NULL;    rdata.length = 0;    rdata.index = 0;    rdata.leftIndex = 0;    /*     * For ECMA 3, the first argument is to be treated as a string     * (i.e. converted to one if necessary) UNLESS it's a reg.exp object.     */    if (!match_or_replace(cx, obj, argc, argv, replace_glob, &rdata.base, rval,                          (cx->version == JSVERSION_DEFAULT ||                           cx->version > JSVERSION_1_4))) {        return JS_FALSE;    }    if (!rdata.chars) {        if (rdata.base.global || *rval != JSVAL_TRUE) {            /* Didn't match even once. */            *rval = STRING_TO_JSVAL(rdata.base.str);            return JS_TRUE;        }        leftlen = cx->regExpStatics.leftContext.length;        if (!find_replen(cx, &rdata, &length))            return JS_FALSE;        length += leftlen;        chars = (jschar *) JS_malloc(cx, (length + 1) * sizeof(jschar));        if (!chars)            return JS_FALSE;        js_strncpy(chars, cx->regExpStatics.leftContext.chars, leftlen);        do_replace(cx, &rdata, chars + leftlen);        rdata.chars = chars;        rdata.length = length;    }    rightlen = cx->regExpStatics.rightContext.length;    length = rdata.length + rightlen;    chars = (jschar *)        JS_realloc(cx, rdata.chars, (length + 1) * sizeof(jschar));    if (!chars) {        JS_free(cx, rdata.chars);        return JS_FALSE;    }    js_strncpy(chars + rdata.length, cx->regExpStatics.rightContext.chars,               rightlen);    chars[length] = 0;    str = js_NewString(cx, chars, length, 0);    if (!str) {        JS_free(cx, chars);        return JS_FALSE;    }    *rval = STRING_TO_JSVAL(str);    return JS_TRUE;#else    return str_nyi(cx, "replace");#endif}