Debian bug 534835: Check some SpiderMonkey return values
[elinks.git] / src / ecmascript / spidermonkey.c
blob78c3bcaec84336fc5a04a8e6b372be0621cd003d
1 /* The SpiderMonkey ECMAScript backend. */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
11 #include "elinks.h"
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;
60 static void
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;
66 struct string msg;
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;
75 #ifdef CONFIG_LEDS
76 set_led_value(interpreter->vs->doc_view->session->status.ecmascript_led, 'J');
77 #endif
79 if (!get_opt_bool("ecmascript.error_reporting")
80 || !init_string(&msg))
81 goto reported;
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.",
99 report->linebuf,
100 pos - 2, " ",
101 strlen(report->linebuf) - pos - 1, " ");
104 info_box(term, MSGBOX_FREE_TEXT, N_("JavaScript Error"), ALIGN_CENTER,
105 msg.source);
107 reported:
108 /* Im clu'les. --pasky */
109 JS_ClearPendingException(ctx);
112 static JSBool
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);
123 return JS_FALSE;
125 return JS_TRUE;
128 static void
129 setup_safeguard(struct ecmascript_interpreter *interpreter,
130 JSContext *ctx)
132 interpreter->exec_start = time(NULL);
133 JS_SetBranchCallback(ctx, safeguard);
137 static void
138 spidermonkey_init(struct module *xxx)
140 js_module_init_ok = spidermonkey_runtime_addref();
143 static void
144 spidermonkey_done(struct module *xxx)
146 if (js_module_init_ok)
147 spidermonkey_runtime_release();
151 void *
152 spidermonkey_get_interpreter(struct ecmascript_interpreter *interpreter)
154 JSContext *ctx;
155 JSObject *window_obj, *document_obj, *forms_obj, *history_obj, *location_obj,
156 *statusbar_obj, *menubar_obj, *navigator_obj;
158 assert(interpreter);
159 if (!js_module_init_ok) return NULL;
161 ctx = JS_NewContext(spidermonkey_runtime,
162 8192 /* Stack allocation chunk size */);
163 if (!ctx)
164 return NULL;
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. */
170 #endif
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,
189 document_funcs,
190 NULL, NULL);
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,
196 forms_funcs,
197 NULL, NULL);
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,
203 history_funcs,
204 NULL, 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,
210 location_funcs,
211 NULL, NULL);
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,
217 NULL, 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,
225 NULL, 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,
233 NULL, NULL);
234 if (!navigator_obj) goto release_and_fail;
236 return ctx;
238 release_and_fail:
239 spidermonkey_put_interpreter(interpreter);
240 return NULL;
243 void
244 spidermonkey_put_interpreter(struct ecmascript_interpreter *interpreter)
246 JSContext *ctx;
248 assert(interpreter);
249 if (!js_module_init_ok) return;
250 ctx = interpreter->backend_data;
251 JS_DestroyContext(ctx);
252 interpreter->backend_data = NULL;
256 void
257 spidermonkey_eval(struct ecmascript_interpreter *interpreter,
258 struct string *code, struct string *ret)
260 JSContext *ctx;
261 jsval rval;
263 assert(interpreter);
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);
273 unsigned char *
274 spidermonkey_eval_stringback(struct ecmascript_interpreter *interpreter,
275 struct string *code)
277 JSContext *ctx;
278 jsval rval;
280 assert(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)
287 == JS_FALSE) {
288 return NULL;
290 if (JSVAL_IS_VOID(rval)) {
291 /* Undefined value. */
292 return NULL;
295 return stracpy(jsval_to_string(ctx, &rval));
300 spidermonkey_eval_boolback(struct ecmascript_interpreter *interpreter,
301 struct string *code)
303 JSContext *ctx;
304 JSFunction *fun;
305 jsval rval;
306 int ret;
308 assert(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);
315 if (!fun)
316 return -1;
318 ret = JS_CallFunction(ctx, NULL, fun, 0, NULL, &rval);
319 if (ret == 2) { /* onClick="history.back()" */
320 return 0;
322 if (ret == JS_FALSE) {
323 return -1;
325 if (JSVAL_IS_VOID(rval)) {
326 /* Undefined value. */
327 return -1;
330 return jsval_to_boolean(ctx, &rval);
333 struct module spidermonkey_module = struct_module(
334 /* name: */ N_("SpiderMonkey"),
335 /* options: */ NULL,
336 /* events: */ NULL,
337 /* submodules: */ NULL,
338 /* data: */ NULL,
339 /* init: */ spidermonkey_init,
340 /* done: */ spidermonkey_done