зеркало из https://github.com/mozilla/gecko-dev.git
Added custom JS_{Convert,Push}Arguments{,VA} formatter function support for
use by XPConnect and other clients.
This commit is contained in:
Родитель
6501c344cd
Коммит
e3df4f3ab2
57
js/src/js.c
57
js/src/js.c
|
@ -1032,6 +1032,40 @@ EscapeWideString(jschar *w)
|
|||
return enuf;
|
||||
}
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
static JSBool
|
||||
ZZ_formatter(JSContext *cx, const char *format, JSBool fromJS, jsval **vpp,
|
||||
va_list *app)
|
||||
{
|
||||
jsval *vp;
|
||||
va_list ap;
|
||||
jsdouble re, im;
|
||||
|
||||
printf("entering ZZ_formatter");
|
||||
vp = *vpp;
|
||||
ap = *app;
|
||||
if (fromJS) {
|
||||
if (!JS_ValueToNumber(cx, vp[0], &re))
|
||||
return JS_FALSE;
|
||||
if (!JS_ValueToNumber(cx, vp[1], &im))
|
||||
return JS_FALSE;
|
||||
*va_arg(ap, jsdouble *) = re;
|
||||
*va_arg(ap, jsdouble *) = im;
|
||||
} else {
|
||||
re = va_arg(ap, jsdouble);
|
||||
im = va_arg(ap, jsdouble);
|
||||
if (!JS_NewNumberValue(cx, re, &vp[0]))
|
||||
return JS_FALSE;
|
||||
if (!JS_NewNumberValue(cx, im, &vp[1]))
|
||||
return JS_FALSE;
|
||||
}
|
||||
*vpp = vp + 2;
|
||||
*app = ap;
|
||||
printf("leaving ZZ_formatter");
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
static JSBool
|
||||
ConvertArgs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
||||
{
|
||||
|
@ -1039,28 +1073,33 @@ ConvertArgs(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|||
jschar c = 0;
|
||||
int32 i = 0, j = 0;
|
||||
uint32 u = 0;
|
||||
jsdouble d = 0, I = 0;
|
||||
jsdouble d = 0, I = 0, re = 0, im = 0;
|
||||
char *s = NULL;
|
||||
JSString *str = NULL;
|
||||
jschar *w = NULL;
|
||||
JSObject *obj = NULL;
|
||||
JSObject *obj2 = NULL;
|
||||
JSFunction *fun = NULL;
|
||||
jsval v = JSVAL_VOID;
|
||||
JSBool ok;
|
||||
|
||||
if (!JS_ConvertArguments(cx, argc, argv, "b/ciujdIsSWofv*",
|
||||
&b, &c, &i, &u, &j, &d, &I, &s, &str, &w, &obj,
|
||||
&fun, &v)) {
|
||||
if (!JS_AddArgumentFormatter(cx, "ZZ", ZZ_formatter))
|
||||
return JS_FALSE;;
|
||||
ok = JS_ConvertArguments(cx, argc, argv, "b/ciujdIsSWofvZZ*",
|
||||
&b, &c, &i, &u, &j, &d, &I, &s, &str, &w, &obj2,
|
||||
&fun, &v, &re, &im);
|
||||
JS_RemoveArgumentFormatter(cx, "ZZ");
|
||||
if (!ok)
|
||||
return JS_FALSE;
|
||||
}
|
||||
fprintf(gOutFile,
|
||||
"b %u, c %x (%c), i %ld, u %lu, j %ld\n",
|
||||
b, c, (char)c, i, u, j);
|
||||
fprintf(gOutFile,
|
||||
"d %g, I %g, s %s, S %s, W %s, obj %s, fun %s, v %s\n",
|
||||
"d %g, I %g, s %s, S %s, W %s, obj %s, fun %s\n"
|
||||
"v %s, re %g, im %g\n",
|
||||
d, I, s, str ? JS_GetStringBytes(str) : "", EscapeWideString(w),
|
||||
JS_GetStringBytes(JS_ValueToString(cx, OBJECT_TO_JSVAL(obj))),
|
||||
JS_GetStringBytes(JS_ValueToString(cx, OBJECT_TO_JSVAL(obj2))),
|
||||
fun ? JS_GetStringBytes(JS_DecompileFunction(cx, fun, 4)) : "",
|
||||
JS_GetStringBytes(JS_ValueToString(cx, v)));
|
||||
JS_GetStringBytes(JS_ValueToString(cx, v)), re, im);
|
||||
return JS_TRUE;
|
||||
}
|
||||
#endif
|
||||
|
|
127
js/src/jsapi.c
127
js/src/jsapi.c
|
@ -91,6 +91,24 @@ JS_GetEmptyStringValue(JSContext *cx)
|
|||
return STRING_TO_JSVAL(cx->runtime->emptyString);
|
||||
}
|
||||
|
||||
static JSBool
|
||||
TryArgumentFormatter(JSContext *cx, const char **formatp, JSBool fromJS,
|
||||
jsval **vpp, va_list *app)
|
||||
{
|
||||
const char *format;
|
||||
JSArgumentFormatMap *map;
|
||||
|
||||
format = *formatp;
|
||||
for (map = cx->argumentFormatMap; map; map = map->next) {
|
||||
if (!strncmp(format, map->format, map->length)) {
|
||||
*formatp = format + map->length;
|
||||
return map->formatter(cx, format, fromJS, vpp, app);
|
||||
}
|
||||
}
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR, format);
|
||||
return JS_FALSE;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ConvertArguments(JSContext *cx, uintN argc, jsval *argv, const char *format,
|
||||
...)
|
||||
|
@ -108,7 +126,7 @@ JS_PUBLIC_API(JSBool)
|
|||
JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
|
||||
const char *format, va_list ap)
|
||||
{
|
||||
uintN i;
|
||||
jsval *sp;
|
||||
JSBool required;
|
||||
char c;
|
||||
JSFunction *fun;
|
||||
|
@ -117,7 +135,7 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
|
|||
JSObject *obj;
|
||||
|
||||
CHECK_REQUEST(cx);
|
||||
i = 0;
|
||||
sp = argv;
|
||||
required = JS_TRUE;
|
||||
while ((c = *format++) != '\0') {
|
||||
if (isspace(c))
|
||||
|
@ -126,7 +144,7 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
|
|||
required = JS_FALSE;
|
||||
continue;
|
||||
}
|
||||
if (i == argc) {
|
||||
if (sp == argv + argc) {
|
||||
if (required) {
|
||||
fun = js_ValueToFunction(cx, &argv[-2], JS_FALSE);
|
||||
if (fun) {
|
||||
|
@ -143,41 +161,41 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
|
|||
}
|
||||
switch (c) {
|
||||
case 'b':
|
||||
if (!js_ValueToBoolean(cx, argv[i], va_arg(ap, JSBool *)))
|
||||
if (!js_ValueToBoolean(cx, *sp, va_arg(ap, JSBool *)))
|
||||
return JS_FALSE;
|
||||
break;
|
||||
case 'c':
|
||||
if (!js_ValueToUint16(cx, argv[i], va_arg(ap, uint16 *)))
|
||||
if (!js_ValueToUint16(cx, *sp, va_arg(ap, uint16 *)))
|
||||
return JS_FALSE;
|
||||
break;
|
||||
case 'i':
|
||||
if (!js_ValueToECMAInt32(cx, argv[i], va_arg(ap, int32 *)))
|
||||
if (!js_ValueToECMAInt32(cx, *sp, va_arg(ap, int32 *)))
|
||||
return JS_FALSE;
|
||||
break;
|
||||
case 'u':
|
||||
if (!js_ValueToECMAUint32(cx, argv[i], va_arg(ap, uint32 *)))
|
||||
if (!js_ValueToECMAUint32(cx, *sp, va_arg(ap, uint32 *)))
|
||||
return JS_FALSE;
|
||||
break;
|
||||
case 'j':
|
||||
if (!js_ValueToInt32(cx, argv[i], va_arg(ap, int32 *)))
|
||||
if (!js_ValueToInt32(cx, *sp, va_arg(ap, int32 *)))
|
||||
return JS_FALSE;
|
||||
break;
|
||||
case 'd':
|
||||
if (!js_ValueToNumber(cx, argv[i], va_arg(ap, jsdouble *)))
|
||||
if (!js_ValueToNumber(cx, *sp, va_arg(ap, jsdouble *)))
|
||||
return JS_FALSE;
|
||||
break;
|
||||
case 'I':
|
||||
if (!js_ValueToNumber(cx, argv[i], &d))
|
||||
if (!js_ValueToNumber(cx, *sp, &d))
|
||||
return JS_FALSE;
|
||||
*va_arg(ap, jsdouble *) = js_DoubleToInteger(d);
|
||||
break;
|
||||
case 's':
|
||||
case 'S':
|
||||
case 'W':
|
||||
str = js_ValueToString(cx, argv[i]);
|
||||
str = js_ValueToString(cx, *sp);
|
||||
if (!str)
|
||||
return JS_FALSE;
|
||||
argv[i] = STRING_TO_JSVAL(str);
|
||||
*sp = STRING_TO_JSVAL(str);
|
||||
if (c == 's')
|
||||
*va_arg(ap, char **) = JS_GetStringBytes(str);
|
||||
else if (c == 'W')
|
||||
|
@ -186,32 +204,31 @@ JS_ConvertArgumentsVA(JSContext *cx, uintN argc, jsval *argv,
|
|||
*va_arg(ap, JSString **) = str;
|
||||
break;
|
||||
case 'o':
|
||||
if (!js_ValueToObject(cx, argv[i], &obj))
|
||||
if (!js_ValueToObject(cx, *sp, &obj))
|
||||
return JS_FALSE;
|
||||
argv[i] = OBJECT_TO_JSVAL(obj);
|
||||
*sp = OBJECT_TO_JSVAL(obj);
|
||||
*va_arg(ap, JSObject **) = obj;
|
||||
break;
|
||||
case 'f':
|
||||
fun = js_ValueToFunction(cx, &argv[i], JS_FALSE);
|
||||
fun = js_ValueToFunction(cx, sp, JS_FALSE);
|
||||
if (!fun)
|
||||
return JS_FALSE;
|
||||
argv[i] = OBJECT_TO_JSVAL(fun->object);
|
||||
*sp = OBJECT_TO_JSVAL(fun->object);
|
||||
*va_arg(ap, JSFunction **) = fun;
|
||||
break;
|
||||
case 'v':
|
||||
*va_arg(ap, jsval *) = argv[i];
|
||||
*va_arg(ap, jsval *) = *sp;
|
||||
break;
|
||||
case '*':
|
||||
break;
|
||||
default: {
|
||||
char charBuf[2] = " ";
|
||||
charBuf[0] = c;
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR,
|
||||
charBuf);
|
||||
return JS_FALSE;
|
||||
}
|
||||
default:
|
||||
format--;
|
||||
if (!TryArgumentFormatter(cx, &format, JS_TRUE, &sp, &ap))
|
||||
return JS_FALSE;
|
||||
/* NB: the formatter already updated sp, so we continue here. */
|
||||
continue;
|
||||
}
|
||||
i++;
|
||||
sp++;
|
||||
}
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
@ -300,13 +317,12 @@ JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap)
|
|||
case 'v':
|
||||
*sp = va_arg(ap, jsval);
|
||||
break;
|
||||
default: {
|
||||
char charBuf[2] = " ";
|
||||
charBuf[0] = c;
|
||||
JS_ReportErrorNumber(cx, js_GetErrorMessage, NULL, JSMSG_BAD_CHAR,
|
||||
charBuf);
|
||||
goto bad;
|
||||
}
|
||||
default:
|
||||
format--;
|
||||
if (!TryArgumentFormatter(cx, &format, JS_FALSE, &sp, &ap))
|
||||
goto bad;
|
||||
/* NB: the formatter already updated sp, so we continue here. */
|
||||
continue;
|
||||
}
|
||||
sp++;
|
||||
}
|
||||
|
@ -324,6 +340,53 @@ JS_PopArguments(JSContext *cx, void *mark)
|
|||
js_FreeStack(cx, mark);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_AddArgumentFormatter(JSContext *cx, const char *format,
|
||||
JSArgumentFormatter formatter)
|
||||
{
|
||||
size_t length;
|
||||
JSArgumentFormatMap **mpp, *map;
|
||||
|
||||
length = strlen(format);
|
||||
mpp = &cx->argumentFormatMap;
|
||||
while ((map = *mpp) != NULL) {
|
||||
/* Insert before any shorter string to match before prefixes. */
|
||||
if (map->length < length)
|
||||
break;
|
||||
if (map->length == length && !strcmp(map->format, format))
|
||||
goto out;
|
||||
mpp = &map->next;
|
||||
}
|
||||
map = JS_malloc(cx, sizeof *map);
|
||||
if (!map)
|
||||
return JS_FALSE;
|
||||
map->format = format;
|
||||
map->length = length;
|
||||
map->next = *mpp;
|
||||
*mpp = map;
|
||||
out:
|
||||
map->formatter = formatter;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_RemoveArgumentFormatter(JSContext *cx, const char *format)
|
||||
{
|
||||
size_t length;
|
||||
JSArgumentFormatMap **mpp, *map;
|
||||
|
||||
length = strlen(format);
|
||||
mpp = &cx->argumentFormatMap;
|
||||
while ((map = *mpp) != NULL) {
|
||||
if (map->length == length && !strcmp(map->format, format)) {
|
||||
*mpp = map->next;
|
||||
JS_free(cx, map);
|
||||
return;
|
||||
}
|
||||
mpp = &map->next;
|
||||
}
|
||||
}
|
||||
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp)
|
||||
{
|
||||
|
|
|
@ -192,6 +192,54 @@ JS_PushArgumentsVA(JSContext *cx, void **markp, const char *format, va_list ap);
|
|||
extern JS_PUBLIC_API(void)
|
||||
JS_PopArguments(JSContext *cx, void *mark);
|
||||
|
||||
#ifdef va_start
|
||||
/*
|
||||
* Add and remove a format string handler for JS_{Convert,Push}Arguments{,VA}.
|
||||
* The handler function has this signature (see jspubtd.h):
|
||||
*
|
||||
* JSBool MyArgumentFormatter(JSContext *cx, const char *format,
|
||||
* JSBool fromJS, jsval **vpp, va_list *app);
|
||||
*
|
||||
* It should return true on success, and return false after reporting an error
|
||||
* or detecting an already-reported error.
|
||||
*
|
||||
* For a given format string, for example "AA", the formatter is called from
|
||||
* JS_ConvertArgumentsVA like so:
|
||||
*
|
||||
* formatter(cx, "AA...", JS_TRUE, &sp, &ap);
|
||||
*
|
||||
* sp points into the arguments array on the JS stack, while ap points into
|
||||
* the stdarg.h va_list on the C stack. The JS_TRUE passed for fromJS tells
|
||||
* the formatter to convert zero or more jsvals at sp to zero or more C values
|
||||
* accessed via pointers-to-values at ap, updating both sp (via *vpp) and ap
|
||||
* (via *app) to point past the converted arguments and their result pointers
|
||||
* on the C stack.
|
||||
*
|
||||
* When called from JS_PushArgumentsVA, the formatter is invoked thus:
|
||||
*
|
||||
* formatter(cx, "AA...", JS_FALSE, &sp, &ap);
|
||||
*
|
||||
* where JS_FALSE for fromJS means to wrap the C values at ap according to the
|
||||
* format specifier and store them at sp, updating ap and sp appropriately.
|
||||
*
|
||||
* The "..." after "AA" is the rest of the format string that was passed into
|
||||
* JS_{Convert,Push}Arguments{,VA}. The actual format trailing substring used
|
||||
* in each Convert or PushArguments call is passed to the formatter, so that
|
||||
* one such function may implement several formats, in order to share code.
|
||||
*
|
||||
* Remove just forgets about any handler associated with format. Add does not
|
||||
* copy format, it points at the string storage allocated by the caller, which
|
||||
* is typically a string constant. If format is in dynamic storage, it is up
|
||||
* to the caller to keep the string alive until Remove is called.
|
||||
*/
|
||||
JS_PUBLIC_API(JSBool)
|
||||
JS_AddArgumentFormatter(JSContext *cx, const char *format,
|
||||
JSArgumentFormatter formatter);
|
||||
|
||||
JS_PUBLIC_API(void)
|
||||
JS_RemoveArgumentFormatter(JSContext *cx, const char *format);
|
||||
#endif /* va_start */
|
||||
|
||||
extern JS_PUBLIC_API(JSBool)
|
||||
JS_ConvertValue(JSContext *cx, jsval v, JSType type, jsval *vp);
|
||||
|
||||
|
|
|
@ -117,6 +117,20 @@ struct JSRuntime {
|
|||
#endif
|
||||
};
|
||||
|
||||
#ifdef va_start
|
||||
/*
|
||||
* Linked list mapping format strings for JS_{Convert,Push}Arguments{,VA} to
|
||||
* formatter functions. Elements are sorted in non-increasing format string
|
||||
* length order.
|
||||
*/
|
||||
struct JSArgumentFormatMap {
|
||||
const char *format;
|
||||
size_t length;
|
||||
JSArgumentFormatter formatter;
|
||||
JSArgumentFormatMap *next;
|
||||
};
|
||||
#endif
|
||||
|
||||
struct JSContext {
|
||||
JSCList links;
|
||||
|
||||
|
@ -151,6 +165,9 @@ struct JSContext {
|
|||
/* State for object and array toSource conversion. */
|
||||
JSSharpObjectMap sharpObjectMap;
|
||||
|
||||
/* Argument formatter support for JS_{Convert,Push}Arguments{,VA}. */
|
||||
JSArgumentFormatMap *argumentFormatMap;
|
||||
|
||||
/* Last message string and trace file for debugging. */
|
||||
char *lastMessage;
|
||||
#ifdef DEBUG
|
||||
|
|
|
@ -41,33 +41,34 @@ typedef uint8 jssrcnote;
|
|||
typedef uint32 jsatomid;
|
||||
|
||||
/* Struct typedefs. */
|
||||
typedef struct JSCodeGenerator JSCodeGenerator;
|
||||
typedef struct JSGCThing JSGCThing;
|
||||
typedef struct JSParseNode JSParseNode;
|
||||
typedef struct JSSharpObjectMap JSSharpObjectMap;
|
||||
typedef struct JSToken JSToken;
|
||||
typedef struct JSTokenPos JSTokenPos;
|
||||
typedef struct JSTokenPtr JSTokenPtr;
|
||||
typedef struct JSTokenStream JSTokenStream;
|
||||
typedef struct JSTreeContext JSTreeContext;
|
||||
typedef struct JSTryNote JSTryNote;
|
||||
typedef struct JSArgumentFormatMap JSArgumentFormatMap;
|
||||
typedef struct JSCodeGenerator JSCodeGenerator;
|
||||
typedef struct JSGCThing JSGCThing;
|
||||
typedef struct JSParseNode JSParseNode;
|
||||
typedef struct JSSharpObjectMap JSSharpObjectMap;
|
||||
typedef struct JSToken JSToken;
|
||||
typedef struct JSTokenPos JSTokenPos;
|
||||
typedef struct JSTokenPtr JSTokenPtr;
|
||||
typedef struct JSTokenStream JSTokenStream;
|
||||
typedef struct JSTreeContext JSTreeContext;
|
||||
typedef struct JSTryNote JSTryNote;
|
||||
|
||||
/* Friend "Advanced API" typedefs. */
|
||||
typedef struct JSAtom JSAtom;
|
||||
typedef struct JSAtomList JSAtomList;
|
||||
typedef struct JSAtomListElement JSAtomListElement;
|
||||
typedef struct JSAtomMap JSAtomMap;
|
||||
typedef struct JSAtomState JSAtomState;
|
||||
typedef struct JSCodeSpec JSCodeSpec;
|
||||
typedef struct JSPrinter JSPrinter;
|
||||
typedef struct JSRegExp JSRegExp;
|
||||
typedef struct JSRegExpStatics JSRegExpStatics;
|
||||
typedef struct JSScope JSScope;
|
||||
typedef struct JSScopeOps JSScopeOps;
|
||||
typedef struct JSScopeProperty JSScopeProperty;
|
||||
typedef struct JSStackFrame JSStackFrame;
|
||||
typedef struct JSSubString JSSubString;
|
||||
typedef struct JSSymbol JSSymbol;
|
||||
typedef struct JSAtom JSAtom;
|
||||
typedef struct JSAtomList JSAtomList;
|
||||
typedef struct JSAtomListElement JSAtomListElement;
|
||||
typedef struct JSAtomMap JSAtomMap;
|
||||
typedef struct JSAtomState JSAtomState;
|
||||
typedef struct JSCodeSpec JSCodeSpec;
|
||||
typedef struct JSPrinter JSPrinter;
|
||||
typedef struct JSRegExp JSRegExp;
|
||||
typedef struct JSRegExpStatics JSRegExpStatics;
|
||||
typedef struct JSScope JSScope;
|
||||
typedef struct JSScopeOps JSScopeOps;
|
||||
typedef struct JSScopeProperty JSScopeProperty;
|
||||
typedef struct JSStackFrame JSStackFrame;
|
||||
typedef struct JSSubString JSSubString;
|
||||
typedef struct JSSymbol JSSymbol;
|
||||
|
||||
/* "Friend" types used by jscntxt.h and jsdbgapi.h. */
|
||||
typedef enum JSTrapStatus {
|
||||
|
|
|
@ -238,6 +238,12 @@ typedef const JSErrorFormatString *
|
|||
(* CRT_CALL JSErrorCallback)(void *userRef, const char *locale,
|
||||
const uintN errorNumber);
|
||||
|
||||
#ifdef va_start
|
||||
typedef JSBool
|
||||
(* CRT_CALL JSArgumentFormatter)(JSContext *cx, const char *format,
|
||||
JSBool fromJS, jsval **vpp, va_list *app);
|
||||
#endif
|
||||
|
||||
JS_END_EXTERN_C
|
||||
|
||||
#endif /* jspubtd_h___ */
|
||||
|
|
Загрузка…
Ссылка в новой задаче