Bug #20547 & 20549 - ECMA3 compatible handling of String.replace and fixes
to $ handling.
This commit is contained in:
rogerl%netscape.com 1999-12-22 21:57:10 +00:00
Родитель 8af17f66e2
Коммит e94220b323
3 изменённых файлов: 99 добавлений и 34 удалений

Просмотреть файл

@ -1114,14 +1114,17 @@ nothex:
}
JSRegExp *
js_NewRegExp(JSContext *cx, JSString *str, uintN flags)
js_NewRegExp(JSContext *cx, JSString *str, uintN flags, JSBool flat)
{
JSRegExp *re;
void *mark;
CompilerState state;
RENode *ren, *end;
RENode *ren, *ren2, *end;
size_t resize;
const jschar *cp;
uintN len;
re = NULL;
mark = JS_ARENA_MARK(&cx->tempPool);
@ -1132,7 +1135,41 @@ js_NewRegExp(JSContext *cx, JSString *str, uintN flags)
state.parenCount = 0;
state.progLength = 0;
ren = ParseRegExp(&state);
if (flat) {
len = str->length;
cp = str->chars;
ren = NULL;
while (len > 0) {
ren2 = NewRENode(&state,
(len == 1) ? REOP_FLAT1 : REOP_FLAT, (void *)cp);
if (!ren2)
goto out;
ren2->flags = RENODE_NONEMPTY;
if (len > 1) {
if (len > REOP_FLATLEN_MAX) {
cp += REOP_FLATLEN_MAX;
len -= REOP_FLATLEN_MAX;
}
else {
cp += len;
len = 0;
}
ren2->u.kid2 = (void *)cp;
} else {
ren2->flags |= RENODE_SINGLE;
ren2->u.chr = *cp;
len = 0;
}
if (ren) {
if (!SetNext(&state, ren, ren2));
goto out;
}
else
ren = ren2;
}
}
else
ren = ParseRegExp(&state);
if (!ren)
goto out;
@ -1164,7 +1201,7 @@ out:
}
JSRegExp *
js_NewRegExpOpt(JSContext *cx, JSString *str, JSString *opt)
js_NewRegExpOpt(JSContext *cx, JSString *str, JSString *opt, JSBool flat)
{
uintN flags;
jschar *cp;
@ -1192,7 +1229,7 @@ js_NewRegExpOpt(JSContext *cx, JSString *str, JSString *opt)
}
}
}
return js_NewRegExp(cx, str, flags);
return js_NewRegExp(cx, str, flags, flat);
}
static void freeRENtree(JSContext *cx, RENode *ren, RENode *stop)
@ -2371,7 +2408,7 @@ regexp_xdrObject(JSXDRState *xdr, JSObject **objp)
*objp = js_NewObject(xdr->cx, &js_RegExpClass, NULL, NULL);
if (!*objp)
return JS_FALSE;
re = js_NewRegExp(xdr->cx, source, flags);
re = js_NewRegExp(xdr->cx, source, flags, JS_FALSE);
if (!re)
return JS_FALSE;
if (!JS_SetPrivate(xdr->cx, *objp, re)) {
@ -2484,7 +2521,7 @@ regexp_compile(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
argv[1] = STRING_TO_JSVAL(opt);
}
}
re = js_NewRegExpOpt(cx, str, opt);
re = js_NewRegExpOpt(cx, str, opt, JS_FALSE);
if (!re) {
ok = JS_FALSE;
goto out;
@ -2626,7 +2663,7 @@ js_NewRegExpObject(JSContext *cx, jschar *chars, size_t length, uintN flags)
str = js_NewStringCopyN(cx, chars, length, 0);
if (!str)
return NULL;
re = js_NewRegExp(cx, str, flags);
re = js_NewRegExp(cx, str, flags, JS_FALSE);
if (!re)
return NULL;
obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL);

Просмотреть файл

@ -74,10 +74,10 @@ struct JSRegExp {
};
extern JSRegExp *
js_NewRegExp(JSContext *cx, JSString *str, uintN flags);
js_NewRegExp(JSContext *cx, JSString *str, uintN flags, JSBool flat);
extern JSRegExp *
js_NewRegExpOpt(JSContext *cx, JSString *str, JSString *opt);
js_NewRegExpOpt(JSContext *cx, JSString *str, JSString *opt, JSBool flat);
extern void
js_DestroyRegExp(JSContext *cx, JSRegExp *re);

Просмотреть файл

@ -255,10 +255,10 @@ str_uneval(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
#endif
static JSFunctionSpec string_functions[] = {
{"escape", str_escape, 1,0,0},
{"unescape", str_unescape, 1,0,0},
{"escape", str_escape, 1,0,0},
{"unescape", str_unescape, 1,0,0},
#if JS_HAS_UNEVAL
{"uneval", str_uneval, 1,0,0},
{"uneval", str_uneval, 1,0,0},
#endif
{0,0,0,0,0}
};
@ -808,7 +808,7 @@ typedef struct GlobData {
static JSBool
match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
JSBool (*glob)(JSContext *cx, jsint count, GlobData *data),
GlobData *data, jsval *rval)
GlobData *data, jsval *rval, JSBool forceFlat)
{
JSString *str, *src, *opt;
JSObject *reobj;
@ -828,7 +828,7 @@ match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
re = JS_GetPrivate(cx, reobj);
} else {
if (JSVAL_IS_VOID(argv[0]))
re = js_NewRegExp(cx, cx->runtime->emptyString, 0);
re = js_NewRegExp(cx, cx->runtime->emptyString, 0, JS_FALSE);
else {
src = js_ValueToString(cx, argv[0]);
if (!src)
@ -841,7 +841,7 @@ match_or_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
} else {
opt = NULL;
}
re = js_NewRegExpOpt(cx, src, opt);
re = js_NewRegExpOpt(cx, src, opt, forceFlat);
}
if (!re)
return JS_FALSE;
@ -933,7 +933,7 @@ str_match(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
mdata.arrayobj = NULL;
if (!js_AddRoot(cx, &mdata.arrayobj, "mdata.arrayobj"))
return JS_FALSE;
ok = match_or_replace(cx, obj, argc, argv, match_glob, &mdata.base, rval);
ok = match_or_replace(cx, obj, argc, argv, match_glob, &mdata.base, rval, JS_FALSE);
if (ok && mdata.arrayobj)
*rval = OBJECT_TO_JSVAL(mdata.arrayobj);
js_RemoveRoot(cx->runtime, &mdata.arrayobj);
@ -951,7 +951,7 @@ str_search(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
mdata.base.optarg = 1;
mdata.base.mode = GLOB_SEARCH;
return match_or_replace(cx, obj, argc, argv, match_glob, &mdata.base, rval);
return match_or_replace(cx, obj, argc, argv, match_glob, &mdata.base, rval, JS_FALSE);
#else
return str_nyi(cx, "search");
#endif
@ -969,6 +969,8 @@ typedef struct ReplaceData {
jsint leftIndex; /* left context index in base.str->chars */
} ReplaceData;
static JSSubString dollarStr;
static JSSubString *
interpret_dollar(JSContext *cx, jschar *dp, ReplaceData *rdata, size_t *skip)
{
@ -986,19 +988,31 @@ interpret_dollar(JSContext *cx, jschar *dp, ReplaceData *rdata, size_t *skip)
res = &cx->regExpStatics;
dc = dp[1];
if (JS7_ISDEC(dc)) {
if (dc == '0')
return NULL;
/* Check for overflow to avoid gobbling arbitrary decimal digits. */
num = 0;
cp = dp;
while ((dc = *++cp) != 0 && JS7_ISDEC(dc)) {
tmp = 10 * num + JS7_UNDEC(dc);
if (tmp < num)
break;
num = tmp;
}
if (cx->version != JSVERSION_DEFAULT &&
cx->version <= JSVERSION_1_4) {
if (dc == '0')
return NULL;
/* Check for overflow to avoid gobbling arbitrary decimal digits. */
num = 0;
cp = dp;
while ((dc = *++cp) != 0 && JS7_ISDEC(dc)) {
tmp = 10 * num + JS7_UNDEC(dc);
if (tmp < num)
break;
num = tmp;
}
}
else { /* ECMA 3, 1-9 or 01-99 */
num = JS7_UNDEC(dc);
cp = dp + 2;
dc = dp[2];
if ((dc != 0) && JS7_ISDEC(dc)) {
num = 10 * num + JS7_UNDEC(dc);
cp++;
}
if (num == 0) return NULL;
}
/* Adjust num from 1 $n-origin to 0 array-index-origin. */
num--;
*skip = cp - dp;
@ -1007,6 +1021,10 @@ interpret_dollar(JSContext *cx, jschar *dp, ReplaceData *rdata, size_t *skip)
*skip = 2;
switch (dc) {
case '$':
dollarStr.chars = dp;
dollarStr.length = 1;
return &dollarStr;
case '&':
return &res->lastMatch;
case '+':
@ -1131,10 +1149,14 @@ find_replen(JSContext *cx, ReplaceData *rdata, size_t *sizep)
repstr = rdata->repstr;
replen = repstr->length;
for (dp = rdata->dollar; dp; dp = js_strchr(dp + 1, '$')) {
for (dp = rdata->dollar; dp; dp = js_strchr(dp, '$')) {
sub = interpret_dollar(cx, dp, rdata, &skip);
if (sub)
if (sub) {
replen += sub->length - skip;
dp += skip;
}
else
dp++;
}
*sizep = replen;
return JS_TRUE;
@ -1162,8 +1184,11 @@ do_replace(JSContext *cx, ReplaceData *rdata, jschar *chars)
js_strncpy(chars, sub->chars, len);
chars += len;
cp += skip;
dp += skip;
}
dp = js_strchr(dp + 1, '$');
else
dp++;
dp = js_strchr(dp, '$');
}
js_strncpy(chars, cp, repstr->length - (cp - repstr->chars));
}
@ -1239,7 +1264,10 @@ str_replace(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
rdata.length = 0;
rdata.index = 0;
rdata.leftIndex = 0;
if (!match_or_replace(cx, obj, argc, argv, replace_glob, &rdata.base, rval))
/* 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) {