1 /* morla - Copyright (C) 2005-2007 bakunin - Andrea Marchesini
2 * <bakunin@morlardf.net>
3 *
4 * This source code is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Public License as published
6 * by the Free Software Foundation; either version 2 of the License,
7 * or (at your option) any later version.
8 *
9 * This source code is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 * Please refer to the GNU Public License for more details.
13 *
14 * You should have received a copy of the GNU Public License along with
15 * this source code; if not, write to:
16 * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #else
22 # error Use configure; make; make install
23 #endif
24
25 #include "editor.h"
26
27 #ifdef USE_JS
28
29 #ifdef USE_NGS_JS
30 static int js_stderr (void *context, unsigned char *buffer,
31 unsigned int amount);
32
33 static JSMethodResult js_alert (void *context, JSInterpPtr interp, int argc,
34 JSType * argv, JSType * result_return,
35 char *error_return);
36 static JSMethodResult js_confirm (void *context, JSInterpPtr interp, int argc,
37 JSType * argv, JSType * result_return,
38 char *error_return);
39 static JSMethodResult js_get_value (void *context, JSInterpPtr interp,
40 int argc, JSType * argv,
41 JSType * result_return,
42 char *error_return);
43 static JSMethodResult js_set_value (void *context, JSInterpPtr interp,
44 int argc, JSType * argv,
45 JSType * result_return,
46 char *error_return);
47 static gchar *js_set_value_real (JSType * var);
48 static JSMethodResult js_morla_version (void *context, JSInterpPtr interp,
49 int argc, JSType * argv,
50 JSType * result_return,
51 char *error_return);
52
53 #elif USE_MOZILLA_JS
54 static void js_stderr (JSContext * context, const char *message,
55 JSErrorReport * report);
56
57 static JSBool js_alert (JSContext * cx, JSObject * obj, uintN argc,
58 jsval * argv, jsval * rval);
59 static JSBool js_confirm (JSContext * cx, JSObject * obj, uintN argc,
60 jsval * argv, jsval * rval);
61 static JSBool js_get_value (JSContext * cx, JSObject * obj, uintN argc,
62 jsval * argv, jsval * rval);
63 static JSBool js_set_value (JSContext * cx, JSObject * obj, uintN argc,
64 jsval * argv, jsval * rval);
65 static JSBool js_version (JSContext * cx, JSObject * obj, uintN argc,
66 jsval * argv, jsval * rval);
67
68 static JSClass globalClass = {
69 "Global", 0, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
70 JS_PropertyStub, JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
71 JS_FinalizeStub
72 };
73
74 static JSFunctionSpec functions[] = {
75 {"morla_alert", js_alert, 0},
76 {"morla_confirm", js_confirm, 0},
77 {"morla_get_value", js_get_value, 0},
78 {"morla_set_value", js_set_value, 0},
79 {"morla_version", js_version, 0},
80 {0}
81 };
82 #endif
83
84 /* Javascript engine init: */
85 struct js_t *
js_new(void)86 js_new (void)
87 {
88 struct js_t *js;
89
90 #ifdef USE_NGS_JS
91 JSInterpPtr interp;
92 JSInterpOptions options;
93
94 JSType var;
95
96 js_init_default_options (&options);
97
98 options.s_stderr = js_stderr;
99 options.s_context = NULL;
100
101 interp = js_create_interp (&options);
102
103 js = g_malloc0 (sizeof (struct js_t));
104 js->interp = interp;
105
106 /* Variables: */
107 var.type = JS_TYPE_BOOLEAN;
108 var.u.i = JS_MORLA_OK;
109 js_set_var (interp, "MORLA_OK", &var);
110
111 var.type = JS_TYPE_BOOLEAN;
112 var.u.i = JS_MORLA_FAILURE;
113 js_set_var (interp, "MORLA_FAILURE", &var);
114
115 var.type = JS_TYPE_INTEGER;
116 var.u.i = 0;
117 js_set_var (interp, "MORLA_VALUE", &var);
118
119 var.type = JS_TYPE_INTEGER;
120 var.u.i = 1;
121 js_set_var (interp, "MORLA_LANGUAGE", &var);
122
123 var.type = JS_TYPE_INTEGER;
124 var.u.i = 2;
125 js_set_var (interp, "MORLA_DATATYPE", &var);
126
127 var.type = JS_TYPE_INTEGER;
128 var.u.i = 3;
129 js_set_var (interp, "MORLA_TYPE", &var);
130
131 var.type = JS_TYPE_INTEGER;
132 var.u.i = RDF_OBJECT_BLANK;
133 js_set_var (interp, "MORLA_RDF_BLANKNODE", &var);
134
135 var.type = JS_TYPE_INTEGER;
136 var.u.i = RDF_OBJECT_LITERAL;
137 js_set_var (interp, "MORLA_RDF_LITERAL", &var);
138
139 var.type = JS_TYPE_INTEGER;
140 var.u.i = RDF_OBJECT_RESOURCE;
141 js_set_var (interp, "MORLA_RDF_RESOURCE", &var);
142
143 /* Functions: */
144 js_create_global_method (interp, "morla_alert", js_alert, js, NULL);
145 js_create_global_method (interp, "morla_confirm", js_confirm, js, NULL);
146 js_create_global_method (interp, "morla_get_value", js_get_value, js, NULL);
147 js_create_global_method (interp, "morla_set_value", js_set_value, js, NULL);
148 js_create_global_method (interp, "morla_version", js_morla_version, js,
149 NULL);
150
151 #elif USE_MOZILLA_JS
152 JSRuntime *rt;
153 JSContext *cx;
154 JSObject *global;
155
156 GString *str;
157 gchar *buffer;
158 jsval rval;
159
160 rt = JS_NewRuntime (0x400000L);
161 cx = JS_NewContext (rt, 0x1000);
162
163 global = JS_NewObject (cx, &globalClass, NULL, NULL);
164
165 JS_InitStandardClasses (cx, global);
166 JS_DefineFunctions (cx, global, functions);
167
168 str = g_string_new (NULL);
169 g_string_append_printf (str, "var MORLA_OK=%d;\n", JS_MORLA_OK);
170 g_string_append_printf (str, "var MORLA_FAILURE=%d;\n", JS_MORLA_FAILURE);
171 g_string_append_printf (str, "var MORLA_VALUE=0;\n");
172 g_string_append_printf (str, "var MORLA_LANGUAGE=1;\n");
173 g_string_append_printf (str, "var MORLA_DATATYPE=2;\n");
174 g_string_append_printf (str, "var MORLA_TYPE=3;\n");
175 g_string_append_printf (str, "var MORLA_RDF_BLANKNODE=%d;\n",
176 RDF_OBJECT_BLANK);
177 g_string_append_printf (str, "var MORLA_RDF_LITERAL=%d;\n",
178 RDF_OBJECT_LITERAL);
179 g_string_append_printf (str, "var MORLA_RDF_RESOURCE=%d;\n",
180 RDF_OBJECT_RESOURCE);
181 g_string_append_printf (str, "var morla_status=0;\n");
182
183 buffer = g_string_free (str, FALSE);
184 JS_EvaluateScript (cx, global, buffer, strlen (buffer), "script", 0, &rval);
185 g_free (buffer);
186
187 JS_SetErrorReporter (cx, js_stderr);
188
189 js = g_malloc0 (sizeof (struct js_t));
190 js->rt = rt;
191 js->cx = cx;
192 js->global = global;
193
194 JS_SetContextPrivate (cx, js);
195 #endif
196
197 return js;
198 }
199
200 /* Destroy everything: */
201 void
js_destroy(struct js_t * js)202 js_destroy (struct js_t *js)
203 {
204 if (!js)
205 return;
206
207 #ifdef USE_NGS_JS
208 js_destroy_interp (js->interp);
209
210 #elif USE_MOZILLA_JS
211 JS_DestroyContext (js->cx);
212 JS_DestroyRuntime (js->rt);
213 #endif
214
215 g_free (js);
216 }
217
218 /* Change the current widget: */
219 void
js_current_widget(struct js_t * js,GtkWidget * widget)220 js_current_widget (struct js_t *js, GtkWidget * widget)
221 {
222 if (js && widget)
223 js->widget = widget;
224 }
225
226 /* Evaluate a js script. The script is ok if the morla_status variabile will be
227 * setted to: MORLA_OK: */
228 gboolean
js_evaluate(struct js_t * js,gchar * buffer)229 js_evaluate (struct js_t *js, gchar * buffer)
230 {
231 #ifdef USE_NGS_JS
232 JSType type;
233
234 type.type = JS_TYPE_BOOLEAN;
235 type.u.i = 0;
236
237 js_set_var (js->interp, "morla_status", &type);
238
239 js_eval (js->interp, buffer);
240
241 js_get_var (js->interp, "morla_status", &type);
242
243 if (type.type == JS_TYPE_BOOLEAN || type.type == JS_TYPE_INTEGER)
244 return type.u.i == JS_MORLA_OK ? JS_MORLA_OK : JS_MORLA_FAILURE;
245
246 return JS_MORLA_FAILURE;
247 #elif USE_MOZILLA_JS
248 jsval rval;
249 gchar *str;
250
251 str = "morla_status=0;\n";
252 if (JS_EvaluateScript
253 (js->cx, js->global, str, strlen (str), "script", 0, &rval) == JS_FALSE)
254 return JS_MORLA_FAILURE;
255
256 if (JS_EvaluateScript
257 (js->cx, js->global, buffer, strlen (buffer), NULL, 0,
258 &rval) == JS_FALSE)
259 return JS_MORLA_FAILURE;
260
261 str = "morla_status;\n";
262 if (JS_EvaluateScript
263 (js->cx, js->global, str, strlen (str), "script", 0, &rval) == JS_FALSE)
264 return JS_MORLA_FAILURE;
265
266 return !JSVAL_TO_DOUBLE (rval) ? JS_MORLA_OK : JS_MORLA_FAILURE;
267 #endif
268 }
269
270 #ifdef USE_NGS_JS
271 static int
js_stderr(void * context,unsigned char * buffer,unsigned int amount)272 js_stderr (void *context, unsigned char *buffer, unsigned int amount)
273 {
274 return fwrite (buffer, 1, amount, stderr);
275 }
276 #elif USE_MOZILLA_JS
277 static void
js_stderr(JSContext * context,const char * message,JSErrorReport * report)278 js_stderr (JSContext * context, const char *message, JSErrorReport * report)
279 {
280 if (!report)
281 {
282 g_fprintf (stderr, "%s", message);
283 return;
284 }
285
286 g_fprintf (stderr, "Line %d: %s\n", report->lineno, message);
287 }
288 #endif
289
290 /* FUNCTIONS ********************************************************************/
291
292 #ifdef USE_NGS_JS
293 /* Alert: */
294 static gchar *
js_alert_real(int argc,JSType * argv)295 js_alert_real (int argc, JSType * argv)
296 {
297 GString *str = g_string_new (NULL);
298 gint i;
299
300 for (i = 0; i < argc; i++)
301 {
302 JSType *arg = &argv[i];
303
304 switch (arg->type)
305 {
306 case JS_TYPE_STRING:
307 if (i > 0)
308 str = g_string_append (str, " ");
309
310 if (arg->u.s && arg->u.s->data)
311 str =
312 g_string_append_len (str, (const gchar *) arg->u.s->data,
313 arg->u.s->len);
314 break;
315
316 case JS_TYPE_INTEGER:
317 case JS_TYPE_BOOLEAN:
318 if (i > 0)
319 str = g_string_append (str, " ");
320
321 g_string_append_printf (str, "%ld", arg->u.i);
322 break;
323
324 case JS_TYPE_DOUBLE:
325 if (i > 0)
326 str = g_string_append (str, " ");
327
328 g_string_append_printf (str, "%f", arg->u.d);
329 break;
330
331 case JS_TYPE_ARRAY:
332 if (i > 0)
333 str = g_string_append (str, " ");
334
335 g_string_append_printf (str, "Array");
336 break;
337
338 default:
339 return NULL;
340 break;
341 }
342 }
343
344 return g_string_free (str, FALSE);
345 }
346
347 static JSMethodResult
js_alert(void * context,JSInterpPtr interp,int argc,JSType * argv,JSType * result_return,char * error_return)348 js_alert (void *context, JSInterpPtr interp, int argc, JSType * argv,
349 JSType * result_return, char *error_return)
350 {
351 gchar *buffer;
352
353 if (!(buffer = js_alert_real (argc, argv)))
354 {
355 sprintf (error_return, "morla_alert: illegal argument");
356 return JS_ERROR;
357 }
358
359
360 dialog_msg (buffer);
361 g_free (buffer);
362
363 result_return->type = JS_TYPE_NULL;
364 return JS_OK;
365 }
366
367 /* Confirm: */
368 static JSMethodResult
js_confirm(void * context,JSInterpPtr interp,int argc,JSType * argv,JSType * result_return,char * error_return)369 js_confirm (void *context, JSInterpPtr interp, int argc, JSType * argv,
370 JSType * result_return, char *error_return)
371 {
372 gchar *buffer;
373
374 if (!(buffer = js_alert_real (argc, argv)))
375 {
376 sprintf (error_return, "morla_confirm: illegal argument");
377 return JS_ERROR;
378 }
379
380 if (dialog_ask (buffer) == GTK_RESPONSE_OK)
381 result_return->u.i = 1;
382 else
383 result_return->u.i = 0;
384
385 g_free (buffer);
386
387 result_return->type = JS_TYPE_BOOLEAN;
388 return JS_OK;
389 }
390
391 static JSMethodResult
js_get_value(void * context,JSInterpPtr interp,int argc,JSType * argv,JSType * result_return,char * error_return)392 js_get_value (void *context, JSInterpPtr interp, int argc, JSType * argv,
393 JSType * result_return, char *error_return)
394 {
395 struct js_t *js = context;
396 struct template_value_t *value;
397
398 value = template_value_new (js->widget);
399
400 js_type_make_array (js->interp, result_return, 4);
401
402 if (value->value)
403 js_type_make_string (js->interp, &result_return->u.array->data[0],
404 (unsigned char *) value->value,
405 strlen (value->value));
406 else
407 js_type_make_string (js->interp, &result_return->u.array->data[0],
408 (unsigned char *) "", 0);
409
410 if (value->lang)
411 js_type_make_string (js->interp, &result_return->u.array->data[1],
412 (unsigned char *) value->lang, strlen (value->lang));
413 else
414 js_type_make_string (js->interp, &result_return->u.array->data[1],
415 (unsigned char *) "", 0);
416
417 if (value->datatype)
418 js_type_make_string (js->interp, &result_return->u.array->data[2],
419 (unsigned char *) value->datatype,
420 strlen (value->datatype));
421 else
422 js_type_make_string (js->interp, &result_return->u.array->data[2],
423 (unsigned char *) "", 0);
424
425 result_return->u.array->data[3].type = JS_TYPE_INTEGER;
426 result_return->u.array->data[3].u.i = value->type;
427
428 template_value_free (value);
429
430 return JS_OK;
431 }
432
433 static JSMethodResult
js_set_value(void * context,JSInterpPtr interp,int argc,JSType * argv,JSType * result_return,char * error_return)434 js_set_value (void *context, JSInterpPtr interp, int argc, JSType * argv,
435 JSType * result_return, char *error_return)
436 {
437 struct template_value_t *value;
438 struct js_t *js = context;
439
440 if (argc != 1)
441 {
442 sprintf (error_return, "morla_set_value: too many argument");
443 return JS_ERROR;
444 }
445
446 if (argv[0].type != JS_TYPE_ARRAY || !argv[0].u.array)
447 {
448 sprintf (error_return, "morla_set_value: the argument is not an array");
449 return JS_ERROR;
450 }
451
452 value = g_malloc0 (sizeof (struct template_value_t));
453
454 #define JS_SET_VALUE( x , y ) \
455 if (argv[0].u.array->length >= y + 1) \
456 value->x = js_set_value_real (argv[0].u.array->data + y); \
457 else \
458 value->x = NULL; \
459
460 JS_SET_VALUE (value, 0);
461 JS_SET_VALUE (lang, 1);
462 JS_SET_VALUE (datatype, 2);
463
464 if (argv[0].u.array->length >= 3 && argv[0].u.array->data + 3)
465 {
466 JSType *var = argv[0].u.array->data + 3;
467
468 if (var->type == JS_TYPE_INTEGER && var->u.i >= 0 && var->u.i <= 3)
469 value->type = var->u.i;
470 else
471 value->type = RDF_OBJECT_RESOURCE;
472
473 }
474
475 template_value_set (js->widget, value);
476 template_value_free (value);
477
478 result_return->type = JS_TYPE_NULL;
479 return JS_OK;
480 }
481
482 static gchar *
js_set_value_real(JSType * var)483 js_set_value_real (JSType * var)
484 {
485 if (var->type == JS_TYPE_INTEGER || var->type == JS_TYPE_BOOLEAN)
486 return g_strdup_printf ("%ld", var->u.i);
487
488 else if (var->type == JS_TYPE_STRING && var->u.s->len)
489 return g_strndup ((const gchar *) var->u.s->data, var->u.s->len);
490
491 else if (var->type == JS_TYPE_DOUBLE)
492 return g_strdup_printf ("%f", var->u.d);
493
494 return NULL;
495 }
496
497 static JSMethodResult
js_morla_version(void * context,JSInterpPtr interp,int argc,JSType * argv,JSType * result_return,char * error_return)498 js_morla_version (void *context, JSInterpPtr interp, int argc, JSType * argv,
499 JSType * result_return, char *error_return)
500 {
501 struct js_t *js = context;
502 js_type_make_string (js->interp, result_return, (unsigned char *) VERSION,
503 strlen (VERSION));
504 return JS_OK;
505 }
506
507 #elif USE_MOZILLA_JS
508 static JSBool
js_alert(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)509 js_alert (JSContext * cx, JSObject * obj, uintN argc, jsval * argv,
510 jsval * rval)
511 {
512 JSString *str;
513
514 if ((!JSVAL_IS_STRING (argv[0]) && !JSVAL_IS_NUMBER (argv[0]))
515 || !(str = JS_ValueToString (cx, argv[0])))
516 return JS_FALSE;
517
518 dialog_msg (JS_GetStringBytes (str));
519 return JS_TRUE;
520 }
521
522 static JSBool
js_confirm(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)523 js_confirm (JSContext * cx, JSObject * obj, uintN argc, jsval * argv,
524 jsval * rval)
525 {
526 JSString *str;
527
528 if ((!JSVAL_IS_STRING (argv[0]) && !JSVAL_IS_NUMBER (argv[0]))
529 || !(str = JS_ValueToString (cx, argv[0])))
530 return JS_FALSE;
531
532 if (dialog_ask (JS_GetStringBytes (str)) == GTK_RESPONSE_OK)
533 *rval = JSVAL_TRUE;
534 else
535 *rval = JSVAL_FALSE;
536
537 return JS_TRUE;
538 }
539
540 static JSBool
js_version(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)541 js_version (JSContext * cx, JSObject * obj, uintN argc, jsval * argv,
542 jsval * rval)
543 {
544 JSString *version = JS_NewStringCopyN (cx, VERSION, strlen (VERSION));
545 *rval = STRING_TO_JSVAL (version);
546 return JS_TRUE;
547 }
548
549 static JSBool
js_get_value(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)550 js_get_value (JSContext * cx, JSObject * obj, uintN argc, jsval * argv,
551 jsval * rval)
552 {
553 struct template_value_t *value;
554 struct js_t *js = JS_GetContextPrivate (cx);
555 JSObject *array = JS_NewArrayObject (cx, 0, NULL);
556
557 JSString *str;
558 jsval val;
559
560 value = template_value_new (js->widget);
561
562 if (value->value)
563 {
564 str = JS_NewStringCopyN (cx, value->value, strlen (value->value));
565 val = STRING_TO_JSVAL (str);
566 JS_SetElement (cx, array, 0, &val);
567 }
568 else
569 {
570 str = JS_NewStringCopyN (cx, "", 0);
571 val = STRING_TO_JSVAL (str);
572 JS_SetElement (cx, array, 0, &val);
573 }
574
575 if (value->lang)
576 {
577 str = JS_NewStringCopyN (cx, value->lang, strlen (value->lang));
578 val = STRING_TO_JSVAL (str);
579 JS_SetElement (cx, array, 1, &val);
580 }
581 else
582 {
583 str = JS_NewStringCopyN (cx, "", 0);
584 val = STRING_TO_JSVAL (str);
585 JS_SetElement (cx, array, 1, &val);
586 }
587
588 if (value->datatype)
589 {
590 str = JS_NewStringCopyN (cx, value->datatype, strlen (value->datatype));
591 val = STRING_TO_JSVAL (str);
592 JS_SetElement (cx, array, 2, &val);
593 }
594 else
595 {
596 str = JS_NewStringCopyN (cx, "", 0);
597 val = STRING_TO_JSVAL (str);
598 JS_SetElement (cx, array, 2, &val);
599 }
600
601 val = DOUBLE_TO_JSVAL (value->type);
602 JS_SetElement (cx, array, 3, &val);
603 template_value_free (value);
604
605 *rval = OBJECT_TO_JSVAL (array);
606 return JS_TRUE;
607 }
608
609 static JSBool
js_set_value(JSContext * cx,JSObject * obj,uintN argc,jsval * argv,jsval * rval)610 js_set_value (JSContext * cx, JSObject * obj, uintN argc, jsval * argv,
611 jsval * rval)
612 {
613 struct template_value_t *value;
614 struct js_t *js = JS_GetContextPrivate (cx);
615 JSObject *array;
616 JSString *str;
617 JSBool found;
618 jsval val;
619
620 if (!JS_IsArrayObject (cx, JSVAL_TO_OBJECT (argv[0])))
621 {
622 JS_ReportError (cx, "morla_set_value: the argument is not an array");
623 return JS_FALSE;
624 }
625
626 array = JSVAL_TO_OBJECT (argv[0]);
627 value = g_malloc0 (sizeof (struct template_value_t));
628
629 #define JS_SET_VALUE( x , y ) \
630 if (JS_HasElement(cx, array, y, &found) == JS_TRUE && \
631 found == JS_TRUE && \
632 JS_GetElement (cx, array, y, &val) && \
633 (JSVAL_IS_STRING (val) || JSVAL_IS_NUMBER (val)) && \
634 (str = JS_ValueToString (cx, val))) \
635 value->x = g_strdup (JS_GetStringBytes (str)); \
636 else \
637 value->x = NULL;
638
639 JS_SET_VALUE (value, 0);
640 JS_SET_VALUE (lang, 1);
641 JS_SET_VALUE (datatype, 2);
642
643 if (JS_HasElement (cx, array, 3, &found) == JS_TRUE && found == JS_TRUE
644 && JS_GetElement (cx, array, 3, &val) && JSVAL_IS_NUMBER (val))
645 value->type = (gint) JSVAL_TO_DOUBLE (val);
646
647 template_value_set (js->widget, value);
648 template_value_free (value);
649
650 return JS_TRUE;
651 }
652
653 #endif
654 #endif
655
656 /* EOF */
657