gam-resource-manager: adjust to updated proxied call callback signature.
[profile/ivi/murphy.git] / src / core / scripting.c
1 /*
2  * Copyright (c) 2012, Intel Corporation
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *   * Redistributions of source code must retain the above copyright notice,
9  *     this list of conditions and the following disclaimer.
10  *   * Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution.
13  *   * Neither the name of Intel Corporation nor the names of its contributors
14  *     may be used to endorse or promote products derived from this software
15  *     without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <stdio.h>
31 #include <stdarg.h>
32 #include <stddef.h>
33 #include <string.h>
34 #include <errno.h>
35
36 #include <murphy/common/macros.h>
37 #include <murphy/common/debug.h>
38 #include <murphy/common/mm.h>
39 #include <murphy/common/list.h>
40 #include <murphy/common/hashtbl.h>
41 #include <murphy/common/utils.h>
42
43 #include <murphy/core/scripting.h>
44
45 static MRP_LIST_HOOK(interpreters);                /* registered interpreters */
46 static const char *default_interpreter = "simple"; /* the default interpreter */
47
48
49 /*
50  * a context variable
51  */
52
53 typedef struct {
54     const char        *name;             /* variable name */
55     mrp_script_type_t  type;             /* type if declared */
56     int                id;               /* variable id */
57 } context_var_t;
58
59
60 /*
61  * a context frame (a set of context variable values)
62  */
63
64 typedef struct context_value_s context_value_t;
65 struct context_value_s {
66     int                 id;              /* variable id */
67     mrp_script_value_t  value;           /* value for this variable */
68     context_value_t    *next;            /* next value in this frame */
69 };
70
71 typedef struct context_frame_s context_frame_t;
72 struct context_frame_s {
73     context_value_t *values;             /* hook to more value */
74     context_frame_t *prev;               /* previous frame */
75 };
76
77
78 /*
79  * table of context variables and context frames
80  */
81
82 struct mrp_context_tbl_s {
83     context_var_t   *variables;          /* known/declared context variables */
84     int              nvariable;          /* number of variables */
85     mrp_htbl_t      *names;              /* variable name to id mapping */
86     context_frame_t *frame;              /* active frame */
87 };
88
89
90
91 int mrp_register_interpreter(mrp_interpreter_t *i)
92 {
93     MRP_UNUSED(default_interpreter);
94
95     mrp_list_init(&i->hook);
96     mrp_list_append(&interpreters, &i->hook);
97
98     return TRUE;
99 }
100
101
102 static void unregister_interpreter(mrp_interpreter_t *i)
103 {
104     mrp_list_delete(&i->hook);
105     mrp_list_init(&i->hook);
106 }
107
108
109 int mrp_unregister_interpreter(const char *name)
110 {
111     mrp_interpreter_t *i;
112
113     i = mrp_lookup_interpreter(name);
114
115     if (i != NULL) {
116         unregister_interpreter(i);
117
118         return TRUE;
119     }
120     else
121         return FALSE;
122
123 }
124
125
126 mrp_interpreter_t *mrp_lookup_interpreter(const char *name)
127 {
128     mrp_list_hook_t   *p, *n;
129     mrp_interpreter_t *i;
130
131     mrp_list_foreach(&interpreters, p, n) {
132         i = mrp_list_entry(p, typeof(*i), hook);
133         if (!strcmp(i->name, name))
134             return i;
135     }
136
137     return NULL;
138 }
139
140
141 mrp_scriptlet_t *mrp_create_script(const char *type, const char *source)
142 {
143     mrp_interpreter_t *i;
144     mrp_scriptlet_t   *s;
145
146     s = NULL;
147     i = mrp_lookup_interpreter(type);
148
149     if (i != NULL) {
150         s = mrp_allocz(sizeof(*s));
151
152         if (s != NULL) {
153             s->interpreter = i;
154             s->source      = mrp_strdup(source);
155
156             if (s->source != NULL)
157                 return s;
158             else {
159                 mrp_free(s);
160                 s = NULL;
161             }
162         }
163     }
164     else
165         errno = ENOENT;
166
167     return NULL;
168 }
169
170
171 void mrp_destroy_script(mrp_scriptlet_t *script)
172 {
173     if (script != NULL) {
174         if (script->interpreter && script->interpreter->cleanup)
175             script->interpreter->cleanup(script);
176
177         mrp_free(script->source);
178         mrp_free(script);
179     }
180 }
181
182
183 int mrp_compile_script(mrp_scriptlet_t *s)
184 {
185     if (s != NULL)
186         return s->interpreter->compile(s);
187     else
188         return 0;
189 }
190
191
192 int mrp_prepare_script(mrp_scriptlet_t *s)
193 {
194     if (s != NULL && s->interpreter->prepare != NULL)
195         return s->interpreter->prepare(s);
196     else
197         return 0;
198 }
199
200
201 int mrp_execute_script(mrp_scriptlet_t *s, mrp_context_tbl_t *ctbl)
202 {
203     if (s != NULL)
204         return s->interpreter->execute(s, ctbl);
205     else
206         return TRUE;
207 }
208
209
210 char *mrp_print_value(char *buf, size_t size, mrp_script_value_t *value)
211 {
212 #define HANDLE_TYPE(type, fmt, val)                     \
213         case MRP_SCRIPT_TYPE_##type:                    \
214             snprintf(buf, size, fmt, val);              \
215             break
216
217     switch (value->type) {
218         HANDLE_TYPE(UNKNOWN, "%s"     , "<unknown/invalid type>");
219         HANDLE_TYPE(STRING , "'%s'"   , value->str);
220         HANDLE_TYPE(BOOL   , "%s"     , value->bln ? "true" : "false");
221         HANDLE_TYPE(UINT8  , "%uU8"   , value->u8);
222         HANDLE_TYPE(SINT8  , "%dS8"   , value->s8);
223         HANDLE_TYPE(UINT16 , "%uU16"  , value->u16);
224         HANDLE_TYPE(SINT16 , "%dS16"  , value->s16);
225         HANDLE_TYPE(UINT32 , "%uU32"  , value->u32);
226         HANDLE_TYPE(SINT32 , "%dS32"  , value->s32);
227         HANDLE_TYPE(UINT64 , "%lluU64", (unsigned long long)value->u64);
228         HANDLE_TYPE(SINT64 , "%lldS64", (  signed long long)value->s64);
229         HANDLE_TYPE(DOUBLE , "%f"     , value->dbl);
230     default:
231         snprintf(buf, size, "<invalid type 0x%x>", value->type);
232     }
233
234 #undef HANDLE_TYPE
235
236     return buf;
237 }
238
239
240 mrp_context_tbl_t *mrp_create_context_table(void)
241 {
242     mrp_context_tbl_t *tbl;
243     mrp_htbl_config_t  hcfg;
244
245     tbl = mrp_allocz(sizeof(*tbl));
246
247     if (tbl != NULL) {
248         mrp_clear(&hcfg);
249         hcfg.comp = mrp_string_comp;
250         hcfg.hash = mrp_string_hash;
251         hcfg.free = NULL;
252
253         tbl->frame = NULL;
254         tbl->names = mrp_htbl_create(&hcfg);
255
256         if (tbl->names != NULL)
257             return tbl;
258
259         mrp_free(tbl);
260     }
261
262     return NULL;
263 }
264
265
266 void mrp_destroy_context_table(mrp_context_tbl_t *tbl)
267 {
268     if (tbl != NULL) {
269         while (mrp_pop_context_frame(tbl) == 0)
270             ;
271
272         mrp_htbl_destroy(tbl->names, FALSE);
273         mrp_free(tbl);
274     }
275 }
276
277
278 static context_var_t *lookup_context_var(mrp_context_tbl_t *tbl,
279                                          const char *name)
280 {
281     int id;
282
283     id = (int)(ptrdiff_t)mrp_htbl_lookup(tbl->names, (void *)name);
284
285     if (0 < id && id <= tbl->nvariable)
286         return tbl->variables + id - 1;
287     else
288         return NULL;
289 }
290
291
292 int mrp_declare_context_variable(mrp_context_tbl_t *tbl, const char *name,
293                                  mrp_script_type_t type)
294 {
295     context_var_t *var;
296
297     var = lookup_context_var(tbl, name);
298
299     if (var != NULL) {
300         if (!var->type) {
301             var->type = type;
302             return var->id;
303         }
304
305         if (!type || var->type == type)
306             return var->id;
307
308         errno = EEXIST;
309         return -1;
310     }
311     else {
312         size_t o, n;
313
314         o = sizeof(*tbl->variables) * tbl->nvariable;
315         n = sizeof(*tbl->variables) * (tbl->nvariable + 1);
316
317         if (!mrp_reallocz(tbl->variables, o, n))
318             return -1;
319
320         var = tbl->variables + tbl->nvariable++;
321
322         var->name = mrp_strdup(name);
323         var->type = type;
324         var->id   = tbl->nvariable;        /* this is a 1-based index... */
325
326         if (var->name != NULL) {
327             if (mrp_htbl_insert(tbl->names, (void *)var->name,
328                                 (void *)(ptrdiff_t)var->id))
329                 return var->id;
330         }
331
332         return -1;
333     }
334 }
335
336
337 int mrp_push_context_frame(mrp_context_tbl_t *tbl)
338 {
339     context_frame_t *f;
340
341     f = mrp_allocz(sizeof(*f));
342
343     if (f != NULL) {
344         f->values  = NULL;
345         f->prev    = tbl->frame;
346         tbl->frame = f;
347
348         mrp_debug("pushed new context frame...");
349
350         return 0;
351     }
352     else
353         return -1;
354 }
355
356
357 int mrp_pop_context_frame(mrp_context_tbl_t *tbl)
358 {
359     context_frame_t *f;
360     context_value_t *v, *n;
361
362     f = tbl->frame;
363
364     if (f != NULL) {
365         for (v = f->values; v != NULL; v = n) {
366             n = v->next;
367
368             if (v->value.type == MRP_SCRIPT_TYPE_STRING)
369                 mrp_free(v->value.str);
370
371             mrp_debug("popped variable <%d>", v->id);
372             mrp_free(v);
373         }
374
375         tbl->frame = f->prev;
376         mrp_free(f);
377
378         mrp_debug("popped context frame");
379
380         return 0;
381     }
382     else {
383         errno = ENOENT;
384         return -1;
385     }
386 }
387
388
389 int get_context_id(mrp_context_tbl_t *tbl, const char *name)
390 {
391     return (int)(ptrdiff_t)mrp_htbl_lookup(tbl->names, (void *)name);
392 }
393
394
395 int get_context_value(mrp_context_tbl_t *tbl, int id, mrp_script_value_t *value)
396 {
397     context_frame_t *f;
398     context_value_t *v;
399
400     if (0 < id && id <= tbl->nvariable) {
401         for (f = tbl->frame; f != NULL; f = f->prev) {
402             for (v = f->values; v != NULL; v = v->next) {
403                 if (v->id == id) {
404                     *value = v->value;
405                     return 0;
406                 }
407             }
408         }
409     }
410
411     value->type = MRP_SCRIPT_TYPE_INVALID;
412     errno       = ENOENT;
413
414     return -1;
415 }
416
417
418 int set_context_value(mrp_context_tbl_t *tbl, int id, mrp_script_value_t *value)
419 {
420     context_frame_t *f;
421     context_var_t   *var;
422     context_value_t *val;
423     char             vbuf[64];
424
425     if (!(0 < id && id <= tbl->nvariable)) {
426         errno = ENOENT;
427         return -1;
428     }
429
430     var = tbl->variables + id - 1;
431     if (var->type != MRP_SCRIPT_TYPE_INVALID && var->type != value->type) {
432         errno = EINVAL;
433         return -1;
434     }
435
436     f = tbl->frame;
437     if (f != NULL) {
438         val = mrp_allocz(sizeof(*val));
439
440         if (val != NULL) {
441             val->id    = id;
442             val->value = *value;
443
444             if (val->value.type != MRP_SCRIPT_TYPE_STRING ||
445                 ((val->value.str = mrp_strdup(val->value.str)) != NULL)) {
446                 val->next = f->values;
447                 f->values = val;
448
449                 mrp_debug("set &%s=%s", var->name,
450                           mrp_print_value(vbuf, sizeof(vbuf), value));
451
452                 return 0;
453             }
454             else
455                 mrp_free(val);
456         }
457     }
458     else
459         errno = ENOSPC;
460
461     return -1;
462 }
463
464
465 int set_context_values(mrp_context_tbl_t *tbl, int *ids,
466                        mrp_script_value_t *values, int nid)
467 {
468     int i;
469
470     for (i = 0; i < nid; i++) {
471         if (set_context_value(tbl, ids[i], values + i) < 0)
472             return -1;
473     }
474
475     return 0;
476 }
477
478
479 int mrp_get_context_id(mrp_context_tbl_t *tbl, const char *name)
480 {
481     int id;
482
483     id = get_context_id(tbl, name);
484
485     if (id <= 0)
486         id = mrp_declare_context_variable(tbl, name, MRP_SCRIPT_TYPE_UNKNOWN);
487
488     return id;
489 }
490
491 int mrp_get_context_value(mrp_context_tbl_t *tbl, int id,
492                           mrp_script_value_t *value)
493 {
494     return get_context_value(tbl, id, value);
495
496 }
497
498 int mrp_set_context_value(mrp_context_tbl_t *tbl, int id,
499                           mrp_script_value_t *value)
500 {
501     return set_context_value(tbl, id, value);
502 }
503
504
505 int mrp_get_context_value_by_name(mrp_context_tbl_t *tbl, const char *name,
506                                   mrp_script_value_t *value)
507 {
508     return get_context_value(tbl, get_context_id(tbl, name), value);
509 }
510
511
512 int mrp_set_context_value_by_name(mrp_context_tbl_t *tbl, const char *name,
513                                   mrp_script_value_t *value)
514 {
515     int id;
516
517     id = get_context_id(tbl, name);
518
519     if (id <= 0)            /* auto-declare as an untyped variable */
520         id = mrp_declare_context_variable(tbl, name, MRP_SCRIPT_TYPE_UNKNOWN);
521
522     return set_context_value(tbl, id, value);
523 }