void IGUIObject::RegisterScriptHandler(const CStr& Action, const CStr& Code, CGUI* pGUI) { if(!GetGUI()) throw PSERROR_GUI_OperationNeedsGUIObject(); JSContext* cx = pGUI->GetScriptInterface()->GetContext(); JSAutoRequest rq(cx); JS::RootedValue globalVal(cx, pGUI->GetGlobalObject()); JS::RootedObject globalObj(cx, &globalVal.toObject()); const int paramCount = 1; const char* paramNames[paramCount] = { "mouse" }; // Location to report errors from CStr CodeName = GetName()+" "+Action; // Generate a unique name static int x = 0; char buf[64]; sprintf_s(buf, ARRAY_SIZE(buf), "__eventhandler%d (%s)", x++, Action.c_str()); JS::CompileOptions options(cx); options.setFileAndLine(CodeName.c_str(), 0); options.setCompileAndGo(true); JS::RootedFunction func(cx, JS_CompileFunction(cx, globalObj, buf, paramCount, paramNames, Code.c_str(), Code.length(), options)); if (!func) return; // JS will report an error message JS::RootedObject funcObj(cx, JS_GetFunctionObject(func)); SetScriptHandler(Action, funcObj); }
//--------------------------------------------------------------------------- inline JSBool ejs_throw_error(JSContext *cx, JSObject *obj, const char *msg) { JSString *jsstr; // if we get errors during error reporting we report those if (((jsstr = JS_NewStringCopyZ(cx, msg))) && (JS_AddNamedRoot(cx, &jsstr, "jsstr"))) { jsval dummy; // We can't use JS_EvaluateScript since the stack would be wrong JSFunction *func; JSObject *fobj; const char *fbody = "throw new Error(msg);"; const char *argnames[] = { "msg" }; if ((func = JS_CompileFunction(cx, obj, NULL, 1, argnames, fbody, strlen(fbody), NULL, 0))) { // root function if (((fobj = JS_GetFunctionObject(func))) && (JS_AddNamedRoot(cx, &fobj, "fobj"))) { jsval args[] = { STRING_TO_JSVAL(jsstr) }; JS_CallFunction(cx, obj, func, 1, args, &dummy); JS_RemoveRoot(cx, &fobj); } } JS_RemoveRoot(cx, &jsstr); } return JS_FALSE; }//---------------------------------------------------------------------------
int spidermonkey_eval_boolback(struct ecmascript_interpreter *interpreter, struct string *code) { JSContext *ctx; JSFunction *fun; jsval rval; int ret; assert(interpreter); if (!js_module_init_ok) return 0; ctx = interpreter->backend_data; interpreter->ret = NULL; fun = JS_CompileFunction(ctx, NULL, "", 0, NULL, code->source, code->length, "", 0); if (!fun) return -1; #if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT) interpreter->heartbeat = add_heartbeat(interpreter); #elif defined(HAVE_JS_SETBRANCHCALLBACK) setup_safeguard(interpreter, ctx); #endif ret = JS_CallFunction(ctx, NULL, fun, 0, NULL, &rval); #if defined(CONFIG_ECMASCRIPT_SMJS_HEARTBEAT) done_heartbeat(interpreter->heartbeat); #endif if (ret == 2) { /* onClick="history.back()" */ return 0; } if (ret == JS_FALSE) { return -1; } if (JSVAL_IS_VOID(rval)) { /* Undefined value. */ return -1; } return jsval_to_boolean(ctx, &rval); }
/* * See: * https://bugzilla.mozilla.org/show_bug.cgi?id=166436 * https://bugzilla.mozilla.org/show_bug.cgi?id=215173 * * Very surprisingly, jsapi.h lacks any way to "throw new Error()" * * So here is an awful hack inspired by * http://egachine.berlios.de/embedding-sm-best-practice/embedding-sm-best-practice.html#error-handling */ static void gjs_throw_valist(JSContext *context, const char *format, va_list args) { char *s; jsval retval; jsval argv[1]; JSFunction *func; const char *body; JSBool result; const char *names[] = { "message" }; guint options; s = g_strdup_vprintf(format, args); JS_BeginRequest(context); if (JS_IsExceptionPending(context)) { /* Often it's unclear whether a given jsapi.h function * will throw an exception, so we will throw ourselves * "just in case"; in those cases, we don't want to * overwrite an exception that already exists. * (Do log in case our second exception adds more info, * but don't log as topic ERROR because if the exception is * caught we don't want an ERROR in the logs.) */ gjs_debug(GJS_DEBUG_CONTEXT, "Ignoring second exception: '%s'", s); g_free(s); return; } result = JS_FALSE; JS_EnterLocalRootScope(context); if (!gjs_string_from_utf8(context, s, -1, &argv[0])) { JS_ReportError(context, "Failed to copy exception string"); goto out; } body = "throw new Error(message);"; func = JS_CompileFunction(context, JS_GetGlobalObject(context), /* parent object (scope chain) */ NULL, /* name of function if we wanted to define it in parent */ 1, /* nargs */ &names[0], /* array of arg names if we had args */ body, strlen(body), "gjs_throw", /* file */ 0); /* line */ if (func == NULL) { JS_ReportError(context, "Failed to compile function"); goto out; } /* we need JS_CallFunctionValue() to leave the exception set */ options = JS_GetOptions(context); if (!(options & JSOPTION_DONT_REPORT_UNCAUGHT)) { JS_SetOptions(context, options | JSOPTION_DONT_REPORT_UNCAUGHT); } retval = JSVAL_VOID; /* note the return value is whether function succeeded, which it shouldn't, since it * throws... */ JS_CallFunctionValue(context, JS_GetGlobalObject(context), OBJECT_TO_JSVAL(JS_GetFunctionObject(func)), 1, &argv[0], &retval); if (!(options & JSOPTION_DONT_REPORT_UNCAUGHT)) { JS_SetOptions(context, options); } if (!JS_IsExceptionPending(context)) { JS_ReportError(context, "Failed to set exception by calling our exception-setting function"); goto out; } result = JS_TRUE; out: JS_LeaveLocalRootScope(context); if (!result) { /* try just reporting it to error handler? should not * happen though pretty much */ JS_ReportError(context, "Failed to throw exception '%s'", s); } g_free(s); JS_EndRequest(context); }
JSFunction * _compileFunction( const char * raw , JSObject * assoc , const char *& gcName ) { if ( ! assoc ) assoc = JS_GetGlobalObject( _context ); while (isspace(*raw)) { raw++; } stringstream fname; fname << "cf_"; static int fnum = 1; fname << "_" << fnum++ << "_"; if ( ! hasFunctionIdentifier( raw ) ) { string s = raw; if ( isSimpleStatement( s ) ) { s = "return " + s; } gcName = "cf anon"; fname << "anon"; return JS_CompileFunction( _context , assoc , fname.str().c_str() , 0 , 0 , s.c_str() , strlen( s.c_str() ) , "nofile_a" , 0 ); } string code = raw; size_t start = code.find( '(' ); assert( start != string::npos ); fname << "_f_" << trim( code.substr( 9 , start - 9 ) ); code = code.substr( start + 1 ); size_t end = code.find( ')' ); assert( end != string::npos ); string paramString = trim( code.substr( 0 , end ) ); code = code.substr( end + 1 ); vector<string> params; while ( paramString.size() ) { size_t c = paramString.find( ',' ); if ( c == string::npos ) { params.push_back( paramString ); break; } params.push_back( trim( paramString.substr( 0 , c ) ) ); paramString = trim( paramString.substr( c + 1 ) ); paramString = trim( paramString ); } boost::scoped_array<const char *> paramArray (new const char*[params.size()]); for ( size_t i=0; i<params.size(); i++ ) paramArray[i] = params[i].c_str(); JSFunction * func = JS_CompileFunction( _context , assoc , fname.str().c_str() , params.size() , paramArray.get() , code.c_str() , strlen( code.c_str() ) , "nofile_b" , 0 ); if ( ! func ) { cout << "compile failed for: " << raw << endl; return 0; } gcName = "cf normal"; return func; }