grafthistory: support curl
[elinks/elinks-j605.git] / src / ecmascript / spidermonkey.c
blob9580ed3d8015aca5d42955c9c0b89acc45faa0f1
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? */
60 /*** The ELinks interface */
62 static JSRuntime *jsrt;
64 static void
65 error_reporter(JSContext *ctx, const char *message, JSErrorReport *report)
67 struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx);
68 struct terminal *term;
69 unsigned char *strict, *exception, *warning, *error;
70 struct string msg;
72 assert(interpreter && interpreter->vs && interpreter->vs->doc_view
73 && interpreter->vs->doc_view->session
74 && interpreter->vs->doc_view->session->tab);
75 if_assert_failed goto reported;
77 term = interpreter->vs->doc_view->session->tab->term;
79 #ifdef CONFIG_LEDS
80 set_led_value(interpreter->vs->doc_view->session->status.ecmascript_led, 'J');
81 #endif
83 if (!get_opt_bool("ecmascript.error_reporting")
84 || !init_string(&msg))
85 goto reported;
87 strict = JSREPORT_IS_STRICT(report->flags) ? " strict" : "";
88 exception = JSREPORT_IS_EXCEPTION(report->flags) ? " exception" : "";
89 warning = JSREPORT_IS_WARNING(report->flags) ? " warning" : "";
90 error = !report->flags ? " error" : "";
92 add_format_to_string(&msg, _("A script embedded in the current "
93 "document raised the following%s%s%s%s", term),
94 strict, exception, warning, error);
96 add_to_string(&msg, ":\n\n");
97 add_to_string(&msg, message);
99 if (report->linebuf && report->tokenptr) {
100 int pos = report->tokenptr - report->linebuf;
102 add_format_to_string(&msg, "\n\n%s\n.%*s^%*s.",
103 report->linebuf,
104 pos - 2, " ",
105 strlen(report->linebuf) - pos - 1, " ");
108 info_box(term, MSGBOX_FREE_TEXT, N_("JavaScript Error"), ALIGN_CENTER,
109 msg.source);
111 reported:
112 /* Im clu'les. --pasky */
113 JS_ClearPendingException(ctx);
116 static JSBool
117 safeguard(JSContext *ctx, JSScript *script)
119 struct ecmascript_interpreter *interpreter = JS_GetContextPrivate(ctx);
120 int max_exec_time = get_opt_int("ecmascript.max_exec_time");
122 if (time(NULL) - interpreter->exec_start > max_exec_time) {
123 struct terminal *term = interpreter->vs->doc_view->session->tab->term;
125 /* A killer script! Alert! */
126 info_box(term, MSGBOX_FREE_TEXT,
127 N_("JavaScript Emergency"), ALIGN_LEFT,
128 msg_text(term,
129 N_("A script embedded in the current document was running\n"
130 "for more than %d seconds. This probably means there is\n"
131 "a bug in the script and it could have halted the whole\n"
132 "ELinks, so the script execution was interrupted."),
133 max_exec_time));
134 return JS_FALSE;
136 return JS_TRUE;
139 static void
140 setup_safeguard(struct ecmascript_interpreter *interpreter,
141 JSContext *ctx)
143 interpreter->exec_start = time(NULL);
144 JS_SetBranchCallback(ctx, safeguard);
148 void
149 spidermonkey_init(void)
151 jsrt = JS_NewRuntime(0x400000UL);
152 /* XXX: This is a hack to avoid a crash on exit. SMJS will crash
153 * on JS_DestroyRuntime if the given runtime has never had any context
154 * created, which will be the case if one closes ELinks without having
155 * loaded any documents. */
156 JS_DestroyContext(JS_NewContext(jsrt, 0));
159 void
160 spidermonkey_done(void)
162 JS_DestroyRuntime(jsrt);
163 JS_ShutDown();
167 void *
168 spidermonkey_get_interpreter(struct ecmascript_interpreter *interpreter)
170 JSContext *ctx;
171 JSObject *window_obj, *document_obj, *forms_obj, *history_obj, *location_obj,
172 *statusbar_obj, *menubar_obj, *navigator_obj;
174 assert(interpreter);
176 ctx = JS_NewContext(jsrt, 8192 /* Stack allocation chunk size */);
177 if (!ctx)
178 return NULL;
179 interpreter->backend_data = ctx;
180 JS_SetContextPrivate(ctx, interpreter);
181 /* TODO: Make JSOPTION_STRICT and JSOPTION_WERROR configurable. */
182 #ifndef JSOPTION_COMPILE_N_GO
183 #define JSOPTION_COMPILE_N_GO 0 /* Older SM versions don't have it. */
184 #endif
185 /* XXX: JSOPTION_COMPILE_N_GO will go (will it?) when we implement
186 * some kind of bytecode cache. (If we will ever do that.) */
187 JS_SetOptions(ctx, JSOPTION_VAROBJFIX | JSOPTION_COMPILE_N_GO);
188 JS_SetErrorReporter(ctx, error_reporter);
190 window_obj = JS_NewObject(ctx, (JSClass *) &window_class, NULL, NULL);
191 if (!window_obj) {
192 spidermonkey_put_interpreter(interpreter);
193 return NULL;
195 JS_InitStandardClasses(ctx, window_obj);
196 JS_DefineProperties(ctx, window_obj, (JSPropertySpec *) window_props);
197 spidermonkey_DefineFunctions(ctx, window_obj, window_funcs);
198 JS_SetPrivate(ctx, window_obj, interpreter->vs); /* to @window_class */
200 document_obj = spidermonkey_InitClass(ctx, window_obj, NULL,
201 (JSClass *) &document_class, NULL, 0,
202 (JSPropertySpec *) document_props,
203 document_funcs,
204 NULL, NULL);
206 forms_obj = spidermonkey_InitClass(ctx, document_obj, NULL,
207 (JSClass *) &forms_class, NULL, 0,
208 (JSPropertySpec *) forms_props,
209 forms_funcs,
210 NULL, NULL);
212 history_obj = spidermonkey_InitClass(ctx, window_obj, NULL,
213 (JSClass *) &history_class, NULL, 0,
214 (JSPropertySpec *) NULL,
215 history_funcs,
216 NULL, NULL);
218 location_obj = spidermonkey_InitClass(ctx, window_obj, NULL,
219 (JSClass *) &location_class, NULL, 0,
220 (JSPropertySpec *) location_props,
221 location_funcs,
222 NULL, NULL);
224 menubar_obj = JS_InitClass(ctx, window_obj, NULL,
225 (JSClass *) &menubar_class, NULL, 0,
226 (JSPropertySpec *) unibar_props, NULL,
227 NULL, NULL);
228 JS_SetPrivate(ctx, menubar_obj, "t"); /* to @menubar_class */
230 statusbar_obj = JS_InitClass(ctx, window_obj, NULL,
231 (JSClass *) &statusbar_class, NULL, 0,
232 (JSPropertySpec *) unibar_props, NULL,
233 NULL, NULL);
234 JS_SetPrivate(ctx, statusbar_obj, "s"); /* to @statusbar_class */
236 navigator_obj = JS_InitClass(ctx, window_obj, NULL,
237 (JSClass *) &navigator_class, NULL, 0,
238 (JSPropertySpec *) navigator_props, NULL,
239 NULL, NULL);
241 return ctx;
244 void
245 spidermonkey_put_interpreter(struct ecmascript_interpreter *interpreter)
247 JSContext *ctx;
249 assert(interpreter);
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)
260 JSContext *ctx;
261 jsval rval;
263 assert(interpreter);
264 ctx = interpreter->backend_data;
265 setup_safeguard(interpreter, ctx);
266 JS_EvaluateScript(ctx, JS_GetGlobalObject(ctx),
267 code->source, code->length, "", 0, &rval);
271 unsigned char *
272 spidermonkey_eval_stringback(struct ecmascript_interpreter *interpreter,
273 struct string *code)
275 JSContext *ctx;
276 jsval rval;
278 assert(interpreter);
279 ctx = interpreter->backend_data;
280 setup_safeguard(interpreter, ctx);
281 if (JS_EvaluateScript(ctx, JS_GetGlobalObject(ctx),
282 code->source, code->length, "", 0, &rval)
283 == JS_FALSE) {
284 return NULL;
286 if (JSVAL_IS_VOID(rval)) {
287 /* Undefined value. */
288 return NULL;
291 return stracpy(jsval_to_string(ctx, &rval));
296 spidermonkey_eval_boolback(struct ecmascript_interpreter *interpreter,
297 struct string *code)
299 JSContext *ctx;
300 jsval rval;
301 int ret;
303 assert(interpreter);
304 ctx = interpreter->backend_data;
305 setup_safeguard(interpreter, ctx);
306 ret = JS_EvaluateScript(ctx, JS_GetGlobalObject(ctx),
307 code->source, code->length, "", 0, &rval);
308 if (ret == 2) { /* onClick="history.back()" */
309 return 0;
311 if (ret == JS_FALSE) {
312 return -1;
314 if (JSVAL_IS_VOID(rval)) {
315 /* Undefined value. */
316 return -1;
319 return jsval_to_boolean(ctx, &rval);