Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Typedefs | Functions | Variables
jsregexp.h File Reference
#include <stddef.h>
#include "jspubtd.h"
#include "jsstr.h"
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Classes

struct  JSRegExpStatics
struct  RECharSet
struct  JSRegExp
union  RECharSet.u
struct  RECharSet.u.src

Defines

#define REGEXP_PAREN_SUBSTRING(res, num)
#define HOLD_REGEXP(cx, re)   JS_ATOMIC_INCREMENT(&(re)->nrefs)
#define DROP_REGEXP(cx, re)   js_DestroyRegExp(cx, re)
#define JSVAL_IS_REGEXP(cx, v)

Typedefs

typedef struct RECharSet RECharSet
typedef struct RENode

Functions

JSRegExpjs_NewRegExp (JSContext *cx, JSTokenStream *ts, JSString *str, uintN flags, JSBool flat)
JSRegExpjs_NewRegExpOpt (JSContext *cx, JSTokenStream *ts, JSString *str, JSString *opt, JSBool flat)
void js_DestroyRegExp (JSContext *cx, JSRegExp *re)
JSBool js_ExecuteRegExp (JSContext *cx, JSRegExp *re, JSString *str, size_t *indexp, JSBool test, jsval *rval)
JSBool js_InitRegExpStatics (JSContext *cx, JSRegExpStatics *res)
void js_FreeRegExpStatics (JSContext *cx, JSRegExpStatics *res)
JSObjectjs_InitRegExpClass (JSContext *cx, JSObject *obj)
JSBool js_regexp_toString (JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
JSObjectjs_NewRegExpObject (JSContext *cx, JSTokenStream *ts, jschar *chars, size_t length, uintN flags)
JSBool js_XDRRegExp (JSXDRState *xdr, JSObject **objp)
JSObjectjs_CloneRegExpObject (JSContext *cx, JSObject *obj, JSObject *parent)
JSBool js_GetLastIndex (JSContext *cx, JSObject *obj, jsdouble *lastIndex)
JSBool js_SetLastIndex (JSContext *cx, JSObject *obj, jsdouble lastIndex)

Variables

JSClass js_RegExpClass

Class Documentation

struct JSRegExpStatics

Definition at line 53 of file jsregexp.h.

Collaboration diagram for JSRegExpStatics:
Class Members
JSString * input
JSSubString lastMatch
JSSubString lastParen
JSSubString leftContext
uint16 moreLength
JSSubString * moreParens
JSBool multiline
uint16 parenCount
JSSubString parens
JSSubString rightContext
struct RECharSet

Definition at line 74 of file jsregexp.h.

Class Members
JSPackedBool converted
uint16 length
JSPackedBool sense
union RECharSet u
struct JSRegExp

Definition at line 100 of file jsregexp.h.

Collaboration diagram for JSRegExp:
Class Members
size_t classCount
RECharSet * classList
uint16 cloneIndex
uint16 flags
jsrefcount nrefs
size_t parenCount
jsbytecode program
JSString * source
union RECharSet.u

Definition at line 78 of file jsregexp.h.

Class Members
uint8 * bits
u src
struct RECharSet.u.src

Definition at line 80 of file jsregexp.h.

Class Members
size_t length
size_t startIndex

Define Documentation

#define DROP_REGEXP (   cx,
  re 
)    js_DestroyRegExp(cx, re)

Definition at line 121 of file jsregexp.h.

#define HOLD_REGEXP (   cx,
  re 
)    JS_ATOMIC_INCREMENT(&(re)->nrefs)

Definition at line 120 of file jsregexp.h.

#define JSVAL_IS_REGEXP (   cx,
  v 
)
Value:

Definition at line 145 of file jsregexp.h.

Value:
(((jsuint)(num) < (jsuint)(res)->parenCount)                              \
     ? ((jsuint)(num) < 9)                                                    \
       ? &(res)->parens[num]                                                  \
       : &(res)->moreParens[(num) - 9]                                        \
     : &js_EmptySubString)

Definition at line 91 of file jsregexp.h.


Typedef Documentation

typedef struct RECharSet RECharSet
typedef struct RENode

Definition at line 98 of file jsregexp.h.


Function Documentation

JSObject* js_CloneRegExpObject ( JSContext cx,
JSObject obj,
JSObject parent 
)

Definition at line 4172 of file jsregexp.c.

{
    JSObject *clone;
    JSRegExp *re;

    JS_ASSERT(OBJ_GET_CLASS(cx, obj) == &js_RegExpClass);
    clone = js_NewObject(cx, &js_RegExpClass, NULL, parent);
    if (!clone)
        return NULL;
    re = JS_GetPrivate(cx, obj);
    if (!JS_SetPrivate(cx, clone, re) || !js_SetLastIndex(cx, clone, 0)) {
        cx->weakRoots.newborn[GCX_OBJECT] = NULL;
        return NULL;
    }
    HOLD_REGEXP(cx, re);
    return clone;
}

Here is the call graph for this function:

Here is the caller graph for this function:

void js_DestroyRegExp ( JSContext cx,
JSRegExp re 
)

Definition at line 2437 of file jsregexp.c.

{
    if (JS_ATOMIC_DECREMENT(&re->nrefs) == 0) {
        if (re->classList) {
            uintN i;
            for (i = 0; i < re->classCount; i++) {
                if (re->classList[i].converted)
                    JS_free(cx, re->classList[i].u.bits);
                re->classList[i].u.bits = NULL;
            }
            JS_free(cx, re->classList);
        }
        JS_free(cx, re);
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool js_ExecuteRegExp ( JSContext cx,
JSRegExp re,
JSString str,
size_t *  indexp,
JSBool  test,
jsval rval 
)

Definition at line 3274 of file jsregexp.c.

{
    REGlobalData gData;
    REMatchState *x, *result;

    const jschar *cp, *ep;
    size_t i, length, start;
    JSSubString *morepar;
    JSBool ok;
    JSRegExpStatics *res;
    ptrdiff_t matchlen;
    uintN num, morenum;
    JSString *parstr, *matchstr;
    JSObject *obj;

    RECapture *parsub = NULL;

    /*
     * It's safe to load from cp because JSStrings have a zero at the end,
     * and we never let cp get beyond cpend.
     */
    start = *indexp;
    length = JSSTRING_LENGTH(str);
    if (start > length)
        start = length;
    cp = JSSTRING_CHARS(str);
    gData.cpbegin = cp;
    gData.cpend = cp + length;
    cp += start;
    gData.start = start;
    gData.skipped = 0;

    JS_InitArenaPool(&gData.pool, "RegExpPool", 8096, 4);
    x = InitMatch(cx, &gData, re);
    if (!x) {
        ok = JS_FALSE;
        goto out;
    }
    x->cp = cp;

    /*
     * Call the recursive matcher to do the real work.  Return null on mismatch
     * whether testing or not.  On match, return an extended Array object.
     */
    result = MatchRegExp(&gData, x);
    ok = gData.ok;
    if (!ok)
        goto out;
    if (!result) {
        *rval = JSVAL_NULL;
        goto out;
    }
    cp = result->cp;
    i = cp - gData.cpbegin;
    *indexp = i;
    matchlen = i - (start + gData.skipped);
    ep = cp;
    cp -= matchlen;

    if (test) {
        /*
         * Testing for a match and updating cx->regExpStatics: don't allocate
         * an array object, do return true.
         */
        *rval = JSVAL_TRUE;

        /* Avoid warning.  (gcc doesn't detect that obj is needed iff !test); */
        obj = NULL;
    } else {
        /*
         * The array returned on match has element 0 bound to the matched
         * string, elements 1 through state.parenCount bound to the paren
         * matches, an index property telling the length of the left context,
         * and an input property referring to the input string.
         */
        obj = js_NewArrayObject(cx, 0, NULL);
        if (!obj) {
            ok = JS_FALSE;
            goto out;
        }
        *rval = OBJECT_TO_JSVAL(obj);

#define DEFVAL(val, id) {                                                     \
    ok = js_DefineProperty(cx, obj, id, val,                                  \
                           JS_PropertyStub, JS_PropertyStub,                  \
                           JSPROP_ENUMERATE, NULL);                           \
    if (!ok) {                                                                \
        cx->weakRoots.newborn[GCX_OBJECT] = NULL;                             \
        cx->weakRoots.newborn[GCX_STRING] = NULL;                             \
        goto out;                                                             \
    }                                                                         \
}

        matchstr = js_NewStringCopyN(cx, cp, matchlen, 0);
        if (!matchstr) {
            cx->weakRoots.newborn[GCX_OBJECT] = NULL;
            ok = JS_FALSE;
            goto out;
        }
        DEFVAL(STRING_TO_JSVAL(matchstr), INT_TO_JSID(0));
    }

    res = &cx->regExpStatics;
    res->input = str;
    res->parenCount = re->parenCount;
    if (re->parenCount == 0) {
        res->lastParen = js_EmptySubString;
    } else {
        for (num = 0; num < re->parenCount; num++) {
            parsub = &result->parens[num];
            if (num < 9) {
                if (parsub->index == -1) {
                    res->parens[num].chars = NULL;
                    res->parens[num].length = 0;
                } else {
                    res->parens[num].chars = gData.cpbegin + parsub->index;
                    res->parens[num].length = parsub->length;
                }
            } else {
                morenum = num - 9;
                morepar = res->moreParens;
                if (!morepar) {
                    res->moreLength = 10;
                    morepar = (JSSubString*)
                        JS_malloc(cx, 10 * sizeof(JSSubString));
                } else if (morenum >= res->moreLength) {
                    res->moreLength += 10;
                    morepar = (JSSubString*)
                        JS_realloc(cx, morepar,
                                   res->moreLength * sizeof(JSSubString));
                }
                if (!morepar) {
                    cx->weakRoots.newborn[GCX_OBJECT] = NULL;
                    cx->weakRoots.newborn[GCX_STRING] = NULL;
                    ok = JS_FALSE;
                    goto out;
                }
                res->moreParens = morepar;
                if (parsub->index == -1) {
                    morepar[morenum].chars = NULL;
                    morepar[morenum].length = 0;
                } else {
                    morepar[morenum].chars = gData.cpbegin + parsub->index;
                    morepar[morenum].length = parsub->length;
                }
            }
            if (test)
                continue;
            if (parsub->index == -1) {
                ok = js_DefineProperty(cx, obj, INT_TO_JSID(num + 1),
                                       JSVAL_VOID, NULL, NULL,
                                       JSPROP_ENUMERATE, NULL);
            } else {
                parstr = js_NewStringCopyN(cx, gData.cpbegin + parsub->index,
                                           parsub->length, 0);
                if (!parstr) {
                    cx->weakRoots.newborn[GCX_OBJECT] = NULL;
                    cx->weakRoots.newborn[GCX_STRING] = NULL;
                    ok = JS_FALSE;
                    goto out;
                }
                ok = js_DefineProperty(cx, obj, INT_TO_JSID(num + 1),
                                       STRING_TO_JSVAL(parstr), NULL, NULL,
                                       JSPROP_ENUMERATE, NULL);
            }
            if (!ok) {
                cx->weakRoots.newborn[GCX_OBJECT] = NULL;
                cx->weakRoots.newborn[GCX_STRING] = NULL;
                goto out;
            }
        }
        if (parsub->index == -1) {
            res->lastParen = js_EmptySubString;
        } else {
            res->lastParen.chars = gData.cpbegin + parsub->index;
            res->lastParen.length = parsub->length;
        }
    }

    if (!test) {
        /*
         * Define the index and input properties last for better for/in loop
         * order (so they come after the elements).
         */
        DEFVAL(INT_TO_JSVAL(start + gData.skipped),
               ATOM_TO_JSID(cx->runtime->atomState.indexAtom));
        DEFVAL(STRING_TO_JSVAL(str),
               ATOM_TO_JSID(cx->runtime->atomState.inputAtom));
    }

#undef DEFVAL

    res->lastMatch.chars = cp;
    res->lastMatch.length = matchlen;

    /*
     * For JS1.3 and ECMAv2, emulate Perl5 exactly:
     *
     * js1.3        "hi", "hi there"            "hihitherehi therebye"
     */
    res->leftContext.chars = JSSTRING_CHARS(str);
    res->leftContext.length = start + gData.skipped;
    res->rightContext.chars = ep;
    res->rightContext.length = gData.cpend - ep;

out:
    JS_FinishArenaPool(&gData.pool);
    return ok;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 3588 of file jsregexp.c.

{
    if (res->moreParens) {
        JS_free(cx, res->moreParens);
        res->moreParens = NULL;
    }
    js_RemoveRoot(cx->runtime, &res->input);
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool js_GetLastIndex ( JSContext cx,
JSObject obj,
jsdouble lastIndex 
)

Definition at line 4191 of file jsregexp.c.

{
    jsval v;

    return JS_GetReservedSlot(cx, obj, 0, &v) &&
           js_ValueToNumber(cx, v, lastIndex);
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 4114 of file jsregexp.c.

{
    JSObject *proto, *ctor;
    jsval rval;

    proto = JS_InitClass(cx, obj, NULL, &js_RegExpClass, RegExp, 1,
                         regexp_props, regexp_methods,
                         regexp_static_props, NULL);

    if (!proto || !(ctor = JS_GetConstructor(cx, proto)))
        return NULL;
    if (!JS_AliasProperty(cx, ctor, "input",        "$_") ||
        !JS_AliasProperty(cx, ctor, "multiline",    "$*") ||
        !JS_AliasProperty(cx, ctor, "lastMatch",    "$&") ||
        !JS_AliasProperty(cx, ctor, "lastParen",    "$+") ||
        !JS_AliasProperty(cx, ctor, "leftContext",  "$`") ||
        !JS_AliasProperty(cx, ctor, "rightContext", "$'")) {
        goto bad;
    }

    /* Give RegExp.prototype private data so it matches the empty string. */
    if (!regexp_compile(cx, proto, 0, NULL, &rval))
        goto bad;
    return proto;

bad:
    JS_DeleteProperty(cx, obj, js_RegExpClass.name);
    return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 3581 of file jsregexp.c.

{
    JS_ClearRegExpStatics(cx);
    return js_AddRoot(cx, &res->input, "res->input");
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSRegExp* js_NewRegExp ( JSContext cx,
JSTokenStream ts,
JSString str,
uintN  flags,
JSBool  flat 
)

Definition at line 1913 of file jsregexp.c.

{
    JSRegExp *re;
    void *mark;
    CompilerState state;
    size_t resize;
    jsbytecode *endPC;
    uintN i;
    size_t len;

    re = NULL;
    mark = JS_ARENA_MARK(&cx->tempPool);
    len = JSSTRING_LENGTH(str);

    state.context = cx;
    state.tokenStream = ts;
    state.cp = js_UndependString(cx, str);
    if (!state.cp)
        goto out;
    state.cpbegin = state.cp;
    state.cpend = state.cp + len;
    state.flags = flags;
    state.parenCount = 0;
    state.classCount = 0;
    state.progLength = 0;
    state.treeDepth = 0;
    state.classBitmapsMem = 0;
    for (i = 0; i < CLASS_CACHE_SIZE; i++)
        state.classCache[i].start = NULL;

    if (len != 0 && flat) {
        state.result = NewRENode(&state, REOP_FLAT);
        state.result->u.flat.chr = *state.cpbegin;
        state.result->u.flat.length = len;
        state.result->kid = (void *) state.cpbegin;
        /* Flat bytecode: REOP_FLAT compact(string_offset) compact(len). */
        state.progLength += 1 + GetCompactIndexWidth(0)
                          + GetCompactIndexWidth(len);
    } else {
        if (!ParseRegExp(&state))
            goto out;
    }
    resize = offsetof(JSRegExp, program) + state.progLength + 1;
    re = (JSRegExp *) JS_malloc(cx, resize);
    if (!re)
        goto out;

    re->nrefs = 1;
    JS_ASSERT(state.classBitmapsMem <= CLASS_BITMAPS_MEM_LIMIT);
    re->classCount = state.classCount;
    if (re->classCount) {
        re->classList = (RECharSet *)
            JS_malloc(cx, re->classCount * sizeof(RECharSet));
        if (!re->classList) {
            js_DestroyRegExp(cx, re);
            re = NULL;
            goto out;
        }
        for (i = 0; i < re->classCount; i++)
            re->classList[i].converted = JS_FALSE;
    } else {
        re->classList = NULL;
    }
    endPC = EmitREBytecode(&state, re, state.treeDepth, re->program, state.result);
    if (!endPC) {
        js_DestroyRegExp(cx, re);
        re = NULL;
        goto out;
    }
    *endPC++ = REOP_END;
    /*
     * Check whether size was overestimated and shrink using realloc.
     * This is safe since no pointers to newly parsed regexp or its parts
     * besides re exist here.
     */
    if ((size_t)(endPC - re->program) != state.progLength + 1) {
        JSRegExp *tmp;
        JS_ASSERT((size_t)(endPC - re->program) < state.progLength + 1);
        resize = offsetof(JSRegExp, program) + (endPC - re->program);
        tmp = (JSRegExp *) JS_realloc(cx, re, resize);
        if (tmp)
            re = tmp;
    }

    re->flags = flags;
    re->cloneIndex = 0;
    re->parenCount = state.parenCount;
    re->source = str;

out:
    JS_ARENA_RELEASE(&cx->tempPool, mark);
    return re;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSObject* js_NewRegExpObject ( JSContext cx,
JSTokenStream ts,
jschar chars,
size_t  length,
uintN  flags 
)

Definition at line 4145 of file jsregexp.c.

{
    JSString *str;
    JSObject *obj;
    JSRegExp *re;
    JSTempValueRooter tvr;

    str = js_NewStringCopyN(cx, chars, length, 0);
    if (!str)
        return NULL;
    re = js_NewRegExp(cx, ts,  str, flags, JS_FALSE);
    if (!re)
        return NULL;
    JS_PUSH_TEMP_ROOT_STRING(cx, str, &tvr);
    obj = js_NewObject(cx, &js_RegExpClass, NULL, NULL);
    if (!obj || !JS_SetPrivate(cx, obj, re)) {
        js_DestroyRegExp(cx, re);
        obj = NULL;
    }
    if (obj && !js_SetLastIndex(cx, obj, 0))
        obj = NULL;
    JS_POP_TEMP_ROOT(cx, &tvr);
    return obj;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSRegExp* js_NewRegExpOpt ( JSContext cx,
JSTokenStream ts,
JSString str,
JSString opt,
JSBool  flat 
)

Definition at line 2009 of file jsregexp.c.

{
    uintN flags;
    jschar *s;
    size_t i, n;
    char charBuf[2];

    flags = 0;
    if (opt) {
        s = JSSTRING_CHARS(opt);
        for (i = 0, n = JSSTRING_LENGTH(opt); i < n; i++) {
            switch (s[i]) {
            case 'g':
                flags |= JSREG_GLOB;
                break;
            case 'i':
                flags |= JSREG_FOLD;
                break;
            case 'm':
                flags |= JSREG_MULTILINE;
                break;
            default:
                charBuf[0] = (char)s[i];
                charBuf[1] = '\0';
                js_ReportCompileErrorNumber(cx, ts,
                                            JSREPORT_TS | JSREPORT_ERROR,
                                            JSMSG_BAD_FLAG, charBuf);
                return NULL;
            }
        }
    }
    return js_NewRegExp(cx, ts, str, flags, flat);
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool js_regexp_toString ( JSContext cx,
JSObject obj,
uintN  argc,
jsval argv,
jsval rval 
)

Definition at line 3809 of file jsregexp.c.

{
    JSRegExp *re;
    const jschar *source;
    jschar *chars;
    size_t length, nflags;
    uintN flags;
    JSString *str;

    if (!JS_InstanceOf(cx, obj, &js_RegExpClass, argv))
        return JS_FALSE;
    JS_LOCK_OBJ(cx, obj);
    re = (JSRegExp *) JS_GetPrivate(cx, obj);
    if (!re) {
        JS_UNLOCK_OBJ(cx, obj);
        *rval = STRING_TO_JSVAL(cx->runtime->emptyString);
        return JS_TRUE;
    }

    source = JSSTRING_CHARS(re->source);
    length = JSSTRING_LENGTH(re->source);
    if (length == 0) {
        source = empty_regexp_ucstr;
        length = sizeof(empty_regexp_ucstr) / sizeof(jschar) - 1;
    }
    length += 2;
    nflags = 0;
    for (flags = re->flags; flags != 0; flags &= flags - 1)
        nflags++;
    chars = (jschar*) JS_malloc(cx, (length + nflags + 1) * sizeof(jschar));
    if (!chars) {
        JS_UNLOCK_OBJ(cx, obj);
        return JS_FALSE;
    }

    chars[0] = '/';
    js_strncpy(&chars[1], source, length - 2);
    chars[length-1] = '/';
    if (nflags) {
        if (re->flags & JSREG_GLOB)
            chars[length++] = 'g';
        if (re->flags & JSREG_FOLD)
            chars[length++] = 'i';
        if (re->flags & JSREG_MULTILINE)
            chars[length++] = 'm';
    }
    JS_UNLOCK_OBJ(cx, obj);
    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;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool js_SetLastIndex ( JSContext cx,
JSObject obj,
jsdouble  lastIndex 
)

Definition at line 4200 of file jsregexp.c.

{
    jsval v;

    return js_NewNumberValue(cx, lastIndex, &v) &&
           JS_SetReservedSlot(cx, obj, 0, v);
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSBool js_XDRRegExp ( JSXDRState xdr,
JSObject **  objp 
)

Variable Documentation

Definition at line 3792 of file jsregexp.c.