1 /* The SpiderMonkey ECMAScript backend. */
13 #include "ecmascript/spidermonkey/util.h"
15 #include "bfu/dialog.h"
16 #include "cache/cache.h"
17 #include "cookies/cookies.h"
18 #include "dialogs/menu.h"
19 #include "dialogs/status.h"
20 #include "document/html/frames.h"
21 #include "document/document.h"
22 #include "document/forms.h"
23 #include "document/view.h"
24 #include "ecmascript/ecmascript.h"
25 #include "ecmascript/spidermonkey.h"
26 #include "ecmascript/spidermonkey/document.h"
27 #include "ecmascript/spidermonkey/form.h"
28 #include "ecmascript/spidermonkey/location.h"
29 #include "ecmascript/spidermonkey/navigator.h"
30 #include "ecmascript/spidermonkey/unibar.h"
31 #include "ecmascript/spidermonkey/window.h"
32 #include "intl/gettext/libintl.h"
33 #include "main/select.h"
34 #include "osdep/newwin.h"
35 #include "osdep/sysname.h"
36 #include "protocol/http/http.h"
37 #include "protocol/uri.h"
38 #include "session/history.h"
39 #include "session/location.h"
40 #include "session/session.h"
41 #include "session/task.h"
42 #include "terminal/tab.h"
43 #include "terminal/terminal.h"
44 #include "util/conv.h"
45 #include "util/string.h"
46 #include "viewer/text/draw.h"
47 #include "viewer/text/form.h"
48 #include "viewer/text/link.h"
49 #include "viewer/text/vs.h"
53 /*** Global methods */
56 /* TODO? Are there any which need to be implemented? */
58 static int js_module_init_ok
;
61 error_reporter(JSContext
*ctx
, const char *message
, JSErrorReport
*report
)
63 struct ecmascript_interpreter
*interpreter
= JS_GetContextPrivate(ctx
);
64 struct terminal
*term
;
65 unsigned char *strict
, *exception
, *warning
, *error
;
68 assert(interpreter
&& interpreter
->vs
&& interpreter
->vs
->doc_view
69 && interpreter
->vs
->doc_view
->session
70 && interpreter
->vs
->doc_view
->session
->tab
);
71 if_assert_failed
goto reported
;
73 term
= interpreter
->vs
->doc_view
->session
->tab
->term
;
76 set_led_value(interpreter
->vs
->doc_view
->session
->status
.ecmascript_led
, 'J');
79 if (!get_opt_bool("ecmascript.error_reporting")
80 || !init_string(&msg
))
83 strict
= JSREPORT_IS_STRICT(report
->flags
) ? " strict" : "";
84 exception
= JSREPORT_IS_EXCEPTION(report
->flags
) ? " exception" : "";
85 warning
= JSREPORT_IS_WARNING(report
->flags
) ? " warning" : "";
86 error
= !report
->flags
? " error" : "";
88 add_format_to_string(&msg
, _("A script embedded in the current "
89 "document raised the following%s%s%s%s", term
),
90 strict
, exception
, warning
, error
);
92 add_to_string(&msg
, ":\n\n");
93 add_to_string(&msg
, message
);
95 if (report
->linebuf
&& report
->tokenptr
) {
96 int pos
= report
->tokenptr
- report
->linebuf
;
98 add_format_to_string(&msg
, "\n\n%s\n.%*s^%*s.",
101 strlen(report
->linebuf
) - pos
- 1, " ");
104 info_box(term
, MSGBOX_FREE_TEXT
, N_("JavaScript Error"), ALIGN_CENTER
,
108 /* Im clu'les. --pasky */
109 JS_ClearPendingException(ctx
);
113 safeguard(JSContext
*ctx
, JSScript
*script
)
115 struct ecmascript_interpreter
*interpreter
= JS_GetContextPrivate(ctx
);
116 int max_exec_time
= get_opt_int("ecmascript.max_exec_time");
118 if (time(NULL
) - interpreter
->exec_start
> max_exec_time
) {
119 struct terminal
*term
= interpreter
->vs
->doc_view
->session
->tab
->term
;
121 /* A killer script! Alert! */
122 ecmascript_timeout_dialog(term
, max_exec_time
);
129 setup_safeguard(struct ecmascript_interpreter
*interpreter
,
132 interpreter
->exec_start
= time(NULL
);
133 JS_SetBranchCallback(ctx
, safeguard
);
138 spidermonkey_init(struct module
*xxx
)
140 js_module_init_ok
= spidermonkey_runtime_addref();
144 spidermonkey_done(struct module
*xxx
)
146 if (js_module_init_ok
)
147 spidermonkey_runtime_release();
152 spidermonkey_get_interpreter(struct ecmascript_interpreter
*interpreter
)
155 JSObject
*window_obj
, *document_obj
, *forms_obj
, *history_obj
, *location_obj
,
156 *statusbar_obj
, *menubar_obj
, *navigator_obj
;
159 if (!js_module_init_ok
) return NULL
;
161 ctx
= JS_NewContext(spidermonkey_runtime
,
162 8192 /* Stack allocation chunk size */);
165 interpreter
->backend_data
= ctx
;
166 JS_SetContextPrivate(ctx
, interpreter
);
167 /* TODO: Make JSOPTION_STRICT and JSOPTION_WERROR configurable. */
168 #ifndef JSOPTION_COMPILE_N_GO
169 #define JSOPTION_COMPILE_N_GO 0 /* Older SM versions don't have it. */
171 /* XXX: JSOPTION_COMPILE_N_GO will go (will it?) when we implement
172 * some kind of bytecode cache. (If we will ever do that.) */
173 JS_SetOptions(ctx
, JSOPTION_VAROBJFIX
| JSOPTION_COMPILE_N_GO
);
174 JS_SetErrorReporter(ctx
, error_reporter
);
176 window_obj
= JS_NewObject(ctx
, (JSClass
*) &window_class
, NULL
, NULL
);
177 if (!window_obj
) goto release_and_fail
;
178 if (!JS_InitStandardClasses(ctx
, window_obj
)) goto release_and_fail
;
179 if (!JS_DefineProperties(ctx
, window_obj
, (JSPropertySpec
*) window_props
))
180 goto release_and_fail
;
181 if (!spidermonkey_DefineFunctions(ctx
, window_obj
, window_funcs
))
182 goto release_and_fail
;
183 if (!JS_SetPrivate(ctx
, window_obj
, interpreter
->vs
)) /* to @window_class */
184 goto release_and_fail
;
186 document_obj
= spidermonkey_InitClass(ctx
, window_obj
, NULL
,
187 (JSClass
*) &document_class
, NULL
, 0,
188 (JSPropertySpec
*) document_props
,
191 if (!document_obj
) goto release_and_fail
;
193 forms_obj
= spidermonkey_InitClass(ctx
, document_obj
, NULL
,
194 (JSClass
*) &forms_class
, NULL
, 0,
195 (JSPropertySpec
*) forms_props
,
198 if (!forms_obj
) goto release_and_fail
;
200 history_obj
= spidermonkey_InitClass(ctx
, window_obj
, NULL
,
201 (JSClass
*) &history_class
, NULL
, 0,
202 (JSPropertySpec
*) NULL
,
205 if (!history_obj
) goto release_and_fail
;
207 location_obj
= spidermonkey_InitClass(ctx
, window_obj
, NULL
,
208 (JSClass
*) &location_class
, NULL
, 0,
209 (JSPropertySpec
*) location_props
,
212 if (!location_obj
) goto release_and_fail
;
214 menubar_obj
= JS_InitClass(ctx
, window_obj
, NULL
,
215 (JSClass
*) &menubar_class
, NULL
, 0,
216 (JSPropertySpec
*) unibar_props
, NULL
,
218 if (!menubar_obj
) goto release_and_fail
;
219 if (!JS_SetPrivate(ctx
, menubar_obj
, "t")) /* to @menubar_class */
220 goto release_and_fail
;
222 statusbar_obj
= JS_InitClass(ctx
, window_obj
, NULL
,
223 (JSClass
*) &statusbar_class
, NULL
, 0,
224 (JSPropertySpec
*) unibar_props
, NULL
,
226 if (!statusbar_obj
) goto release_and_fail
;
227 if (!JS_SetPrivate(ctx
, statusbar_obj
, "s")) /* to @statusbar_class */
228 goto release_and_fail
;
230 navigator_obj
= JS_InitClass(ctx
, window_obj
, NULL
,
231 (JSClass
*) &navigator_class
, NULL
, 0,
232 (JSPropertySpec
*) navigator_props
, NULL
,
234 if (!navigator_obj
) goto release_and_fail
;
239 spidermonkey_put_interpreter(interpreter
);
244 spidermonkey_put_interpreter(struct ecmascript_interpreter
*interpreter
)
249 if (!js_module_init_ok
) return;
250 ctx
= interpreter
->backend_data
;
251 JS_DestroyContext(ctx
);
252 interpreter
->backend_data
= NULL
;
257 spidermonkey_eval(struct ecmascript_interpreter
*interpreter
,
258 struct string
*code
, struct string
*ret
)
264 if (!js_module_init_ok
) return;
265 ctx
= interpreter
->backend_data
;
266 setup_safeguard(interpreter
, ctx
);
267 interpreter
->ret
= ret
;
268 JS_EvaluateScript(ctx
, JS_GetGlobalObject(ctx
),
269 code
->source
, code
->length
, "", 0, &rval
);
274 spidermonkey_eval_stringback(struct ecmascript_interpreter
*interpreter
,
281 if (!js_module_init_ok
) return NULL
;
282 ctx
= interpreter
->backend_data
;
283 setup_safeguard(interpreter
, ctx
);
284 interpreter
->ret
= NULL
;
285 if (JS_EvaluateScript(ctx
, JS_GetGlobalObject(ctx
),
286 code
->source
, code
->length
, "", 0, &rval
)
290 if (JSVAL_IS_VOID(rval
)) {
291 /* Undefined value. */
295 return stracpy(jsval_to_string(ctx
, &rval
));
300 spidermonkey_eval_boolback(struct ecmascript_interpreter
*interpreter
,
309 if (!js_module_init_ok
) return 0;
310 ctx
= interpreter
->backend_data
;
311 setup_safeguard(interpreter
, ctx
);
312 interpreter
->ret
= NULL
;
313 fun
= JS_CompileFunction(ctx
, NULL
, "", 0, NULL
, code
->source
,
314 code
->length
, "", 0);
318 ret
= JS_CallFunction(ctx
, NULL
, fun
, 0, NULL
, &rval
);
319 if (ret
== 2) { /* onClick="history.back()" */
322 if (ret
== JS_FALSE
) {
325 if (JSVAL_IS_VOID(rval
)) {
326 /* Undefined value. */
330 return jsval_to_boolean(ctx
, &rval
);
333 struct module spidermonkey_module
= struct_module(
334 /* name: */ N_("SpiderMonkey"),
337 /* submodules: */ NULL
,
339 /* init: */ spidermonkey_init
,
340 /* done: */ spidermonkey_done