Пример #1
0
static JSBool
array_join_sub(JSContext *cx, JSObject *obj, JSString *sep, JSBool literalize,
               jsval *rval, JSBool localeString)
{
    JSBool ok;
    jsval v;
    jsuint length, index;
    jschar *chars, *ochars;
    size_t nchars, growth, seplen, tmplen;
    const jschar *sepstr;
    JSString *str;
    JSHashEntry *he;
    JSObject *obj2;

    ok = js_GetLengthProperty(cx, obj, &length);
    if (!ok)
        return JS_FALSE;

    he = js_EnterSharpObject(cx, obj, NULL, &chars);
    if (!he)
        return JS_FALSE;
    if (literalize) {
        if (IS_SHARP(he)) {
#if JS_HAS_SHARP_VARS
            nchars = js_strlen(chars);
#else
            chars[0] = '[';
            chars[1] = ']';
            chars[2] = 0;
            nchars = 2;
#endif
            goto make_string;
        }

        /*
         * Allocate 1 + 3 + 1 for "[", the worst-case closing ", ]", and the
         * terminating 0.
         */
        growth = (1 + 3 + 1) * sizeof(jschar);
        if (!chars) {
            nchars = 0;
            chars = (jschar *) malloc(growth);
            if (!chars)
                goto done;
        } else {
            MAKE_SHARP(he);
            nchars = js_strlen(chars);
            chars = (jschar *)
                realloc((ochars = chars), nchars * sizeof(jschar) + growth);
            if (!chars) {
                free(ochars);
                goto done;
            }
        }
        chars[nchars++] = '[';
    } else {
        /*
         * Free any sharp variable definition in chars.  Normally, we would
         * MAKE_SHARP(he) so that only the first sharp variable annotation is
         * a definition, and all the rest are references, but in the current
         * case of (!literalize), we don't need chars at all.
         */
        if (chars)
            JS_free(cx, chars);
        chars = NULL;
        nchars = 0;

        /* Return the empty string on a cycle as well as on empty join. */
        if (IS_BUSY(he) || length == 0) {
            js_LeaveSharpObject(cx, NULL);
            *rval = JS_GetEmptyStringValue(cx);
            return ok;
        }

        /* Flag he as BUSY so we can distinguish a cycle from a join-point. */
        MAKE_BUSY(he);
    }
    sepstr = NULL;
    seplen = JSSTRING_LENGTH(sep);

    v = JSVAL_NULL;
    for (index = 0; index < length; index++) {
        ok = JS_GetElement(cx, obj, index, &v);
        if (!ok)
            goto done;

        if (!literalize && (JSVAL_IS_VOID(v) || JSVAL_IS_NULL(v))) {
            str = cx->runtime->emptyString;
        } else {
            if (localeString) {
                if (!js_ValueToObject(cx, v, &obj2) ||
                    !js_TryMethod(cx, obj2,
                                  cx->runtime->atomState.toLocaleStringAtom,
                                  0, NULL, &v)) {
                    str = NULL;
                } else {
                    str = js_ValueToString(cx, v);
                }
            } else {
                str = (literalize ? js_ValueToSource : js_ValueToString)(cx, v);
            }
            if (!str) {
                ok = JS_FALSE;
                goto done;
            }
        }

        /* Allocate 3 + 1 at end for ", ", closing bracket, and zero. */
        growth = (nchars + (sepstr ? seplen : 0) +
                  JSSTRING_LENGTH(str) +
                  3 + 1) * sizeof(jschar);
        if (!chars) {
            chars = (jschar *) malloc(growth);
            if (!chars)
                goto done;
        } else {
            chars = (jschar *) realloc((ochars = chars), growth);
            if (!chars) {
                free(ochars);
                goto done;
            }
        }

        if (sepstr) {
            js_strncpy(&chars[nchars], sepstr, seplen);
            nchars += seplen;
        }
        sepstr = JSSTRING_CHARS(sep);

        tmplen = JSSTRING_LENGTH(str);
        js_strncpy(&chars[nchars], JSSTRING_CHARS(str), tmplen);
        nchars += tmplen;
    }

  done:
    if (literalize) {
        if (chars) {
            if (JSVAL_IS_VOID(v)) {
                chars[nchars++] = ',';
                chars[nchars++] = ' ';
            }
            chars[nchars++] = ']';
        }
    } else {
        CLEAR_BUSY(he);
    }
    js_LeaveSharpObject(cx, NULL);
    if (!ok) {
        if (chars)
            free(chars);
        return ok;
    }

  make_string:
    if (!chars) {
        JS_ReportOutOfMemory(cx);
        return JS_FALSE;
    }
    chars[nchars] = 0;
    str = js_NewString(cx, chars, nchars, 0);
    if (!str) {
        free(chars);
        return JS_FALSE;
    }
    *rval = STRING_TO_JSVAL(str);
    return JS_TRUE;
}
Пример #2
0
JSBool
js_obj_toString(JSContext *cx, JSObject *obj, uintN argc, jsval *argv,
		jsval *rval)
{
    jschar *chars;
    size_t nchars;
    char *clazz, *prefix;
    JSString *str;

#if JS_HAS_OBJECT_LITERAL
    if (cx->version >= JSVERSION_1_2) {
	JSProperty *list, *prop;
	JSBool ok;
	char *comma, *idquote, *valquote;
	jsval id, val;
	JSString *idstr, *valstr;
#if JS_HAS_SHARP_VARS
	PRHashEntry *he;
#endif

	/* Early returns after this must unlock, or goto done with ok set. */
	JS_LOCK(cx);
	list = obj->map->props;

#if JS_HAS_SHARP_VARS
	he = js_EnterSharpObject(cx, obj, &chars);
	if (!he) {
	    JS_UNLOCK(cx);
	    return JS_FALSE;
	}
	if (IS_SHARP(he)) {	/* we didn't enter -- obj is already sharp */
	    JS_UNLOCK(cx);
	    nchars = js_strlen(chars);
	    goto make_string;
	}
	MAKE_SHARP(he);
#else
	/* Shut off recursion by temporarily clearing obj's property list. */
	obj->map->props = NULL;
	chars = NULL;
#endif
	ok = JS_TRUE;

	/* Allocate 2 + 1 for "{}" and the terminator. */
	if (!chars) {
	    chars = malloc((2 + 1) * sizeof(jschar));
	    nchars = 0;
	} else {
	    nchars = js_strlen(chars);
	    chars = realloc(chars, (nchars + 2 + 1) * sizeof(jschar));
	}
	if (!chars)
	    goto done;
	chars[nchars++] = '{';

	comma = NULL;

	for (prop = list; prop; prop = prop->next) {
	    if (!prop->symbols || !(prop->flags & JSPROP_ENUMERATE))
		continue;

	    /* Get strings for id and val and GC-root them via argv. */
	    id = js_IdToValue(sym_id(prop->symbols));
	    idstr = js_ValueToString(cx, id);
	    if (idstr)
		argv[0] = STRING_TO_JSVAL(idstr);
	    val = prop->object->slots[prop->slot];
	    valstr = js_ValueToString(cx, val);
	    if (!idstr || !valstr) {
		ok = JS_FALSE;
		goto done;
	    }
	    argv[1] = STRING_TO_JSVAL(valstr);

	    /* If id is a non-identifier string, it needs to be quoted. */
	    if (JSVAL_IS_STRING(id) && !js_IsIdentifier(idstr)) {
		idquote = "'";
		idstr = js_EscapeString(cx, idstr, *idquote);
		if (!idstr) {
		    ok = JS_FALSE;
		    goto done;
		}
		argv[0] = STRING_TO_JSVAL(idstr);
	    } else {
		idquote = NULL;
	    }

	    /* Same for val, except it can't be an identifier. */
	    if (JSVAL_IS_STRING(val)) {
		valquote = "\"";
		valstr = js_EscapeString(cx, valstr, *valquote);
		if (!valstr) {
		    ok = JS_FALSE;
		    goto done;
		}
		argv[1] = STRING_TO_JSVAL(valstr);
	    } else {
		valquote = NULL;
	    }

	    /* Allocate 1 + 1 at end for closing brace and terminating 0. */
	    chars = realloc(chars,
			    (nchars + (comma ? 2 : 0) +
			     (idquote ? 2 : 0) + idstr->length + 1 +
			     (valquote ? 2 : 0) + valstr->length +
			     1 + 1) * sizeof(jschar));
	    if (!chars)
		goto done;

	    if (comma) {
		chars[nchars++] = comma[0];
		chars[nchars++] = comma[1];
	    }
	    comma = ", ";

	    if (idquote)
		chars[nchars++] = *idquote;
	    js_strncpy(&chars[nchars], idstr->chars, idstr->length);
	    nchars += idstr->length;
	    if (idquote)
		chars[nchars++] = *idquote;

	    chars[nchars++] = ':';

	    if (valquote)
		chars[nchars++] = *valquote;
	    js_strncpy(&chars[nchars], valstr->chars, valstr->length);
	    nchars += valstr->length;
	    if (valquote)
		chars[nchars++] = *valquote;
	}

      done:
	if (chars) {
	    chars[nchars++] = '}';
	    chars[nchars] = 0;
	}
#if JS_HAS_SHARP_VARS
	js_LeaveSharpObject(cx);
#else
	/* Restore obj's property list before bailing on error. */
	obj->map->props = list;
#endif

	JS_UNLOCK(cx);
	if (!ok) {
	    if (chars)
		free(chars);
	    return ok;
	}
    } else
#endif /* JS_HAS_OBJECT_LITERAL */
    {
	clazz = obj->map->clasp->name;
	nchars = 9 + strlen(clazz);		/* 9 for "[object ]" */
	chars = malloc((nchars + 1) * sizeof(jschar));
	if (chars) {
	    prefix = "[object ";
	    nchars = 0;
	    while ((chars[nchars] = (jschar)*prefix) != 0)
		nchars++, prefix++;
	    while ((chars[nchars] = (jschar)*clazz) != 0)
		nchars++, clazz++;
	    chars[nchars++] = ']';
	    chars[nchars] = 0;
	}
    }

#if JS_HAS_SHARP_VARS
  make_string:
#endif
    if (!chars) {
	JS_ReportOutOfMemory(cx);
	return JS_FALSE;
    }
    str = js_NewString(cx, chars, nchars, 0);
    if (!str) {
	free(chars);
	return JS_FALSE;
    }
    *rval = STRING_TO_JSVAL(str);
    return JS_TRUE;
}