ce83b41eb8823aa70e76ac930e7f31e4463d4917
[profile/ivi/murphy.git] / src / resource / config-lua.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 <stdlib.h>
32 #include <string.h>
33 #include <errno.h>
34
35 #include <lualib.h>
36 #include <lauxlib.h>
37
38 #include <murphy/common.h>
39 #include <murphy/common/debug.h>
40 #include <murphy/core/lua-bindings/murphy.h>
41 #include <murphy/core/lua-utils/object.h>
42
43 #include "config-lua.h"
44 #include "resource-lua.h"
45 #include "config-api.h"
46 #include "client-api.h"
47 #include "manager-api.h"
48 #include "zone.h"
49 #include "application-class.h"
50 #include "resource.h"
51 #include "resource-set.h"
52 #include "attribute.h"
53
54 #define ZONE_CLASS             MRP_LUA_CLASS_SIMPLE(zone)
55 #define APPCLASS_CLASS         MRP_LUA_CLASS_SIMPLE(application_class)
56 #define ZONE_ATTR_CLASS        MRP_LUA_CLASS(zone, attributes)
57 #define RESCLASS_CLASS         MRP_LUA_CLASS(resource, class)
58 #define RESMETHOD_CLASS        MRP_LUA_CLASS_SIMPLE(resource)
59
60 #define ATTRIBUTE_CLASSID      MRP_LUA_CLASSID_ROOT "attribute"
61 #define RESOURCE_CLASSID       MRP_LUA_CLASSID_ROOT "resource.instance"
62
63 typedef enum   field_e         field_t;
64 typedef enum   attr_owner_e    attr_owner_t;
65 typedef struct appclass_s      appclass_t;
66 typedef struct zone_s          zone_t;
67 typedef struct resclass_s      resclass_t;
68 typedef struct resource_s      resource_t;
69 typedef struct attr_def_s      attr_def_t;
70 typedef struct attr_s          attr_t;
71
72 typedef bool (*attribute_access_t)(attr_t *, int, mrp_attr_t *);
73
74 enum field_e {
75     ATTRIBUTES = 1,
76     CLASS,
77     NAME,
78     PRIORITY,
79     SHAREABLE,
80     MANDATORY,
81     MODAL,
82     SHARE,
83     GRANT,
84     ORDER,
85     SHARED,
86     METHOD,
87     OWNERS,
88     VETO,
89     ID
90 };
91
92 enum attr_owner_e {
93     ZONE = 1,
94     RESOURCE
95 };
96
97 struct appclass_s {
98     const char *name;
99 };
100
101 struct zone_s {
102     uint32_t  id;
103     const char *name;
104     int attr_tbl;
105 };
106
107 struct resclass_s {
108     uint32_t id;
109     const char *name;
110     mrp_attr_def_t *attrs;
111 };
112
113 struct resource_s {
114     uint32_t rsetid;
115     uint32_t resid;
116     const char *name;
117     int attr_tbl;
118 };
119
120 struct attr_def_s {
121     int nattr;
122     mrp_attr_def_t *attrs;
123 };
124
125 struct attr_s {
126     struct {
127         attr_owner_t type;
128         void *data;
129     } owner;
130     attr_def_t *def;
131     attribute_access_t fetch;
132     attribute_access_t update;
133 };
134
135
136 static void attributes_class_create(lua_State *);
137 static void appclass_class_create(lua_State *);
138 static void zone_class_create(lua_State *);
139 static void resclass_class_create(lua_State *);
140 static void resource_class_create(lua_State *);
141 static void resource_methods_create(lua_State *);
142
143
144 static int  attributes_create(lua_State *, attr_owner_t, void *,
145                               attr_def_t *, attribute_access_t,
146                               attribute_access_t);
147 static int  attributes_getvalue(lua_State *);
148 static int  attributes_setvalue(lua_State *);
149 static int  attributes_getlength(lua_State *);
150 static attr_t *check_attributes(lua_State *, int);
151 static int  push_attributes(lua_State *, int);
152
153 static int  appclass_create(lua_State *);
154 static int  appclass_getfield(lua_State *);
155 static int  appclass_setfield(lua_State *);
156 static void appclass_destroy(void *);
157 /* static appclass_t *check_appclass(lua_State *, int); */
158 static appclass_t *to_appclass(lua_State *, int);
159
160 static int  zone_create(lua_State *);
161 static int  zone_getfield(lua_State *);
162 static int  zone_setfield(lua_State *);
163 static void zone_destroy(void *);
164 /* static zone_t *check_zone(lua_State *, int); */
165 static zone_t *to_zone(lua_State *, int);
166
167 static int  zone_attr_create(lua_State *);
168 static int  zone_attr_getfield(lua_State *);
169 static int  zone_attr_setfield(lua_State *);
170 static void zone_attr_destroy(void *);
171 /* static attr_def_t *check_zone_attr(lua_State *, int); */
172 /* static attr_def_t *to_zone_attr(lua_State *, int); */
173 static bool fetch_zone_attribute(attr_t *, int, mrp_attr_t *);
174 static bool update_zone_attribute(attr_t *, int, mrp_attr_t *);
175
176 static int  resclass_create_from_lua(lua_State *);
177 static int  resclass_getfield(lua_State *);
178 static int  resclass_setfield(lua_State *);
179 static void resclass_destroy(void *);
180 /* static resclass_t *check_resclass(lua_State *, int); */
181 static resclass_t *to_resclass(lua_State *, int);
182
183 static int  resource_getfield(lua_State *);
184 static int  resource_setfield(lua_State *);
185 static resource_t *check_resource(lua_State *, int);
186 static bool fetch_resource_attribute(attr_t *, int, mrp_attr_t *);
187 static bool update_resource_attribute(attr_t *, int, mrp_attr_t *);
188
189 static mrp_lua_resmethod_t *resmethod_create_from_c(lua_State *);
190 static int  resmethod_create_from_lua(lua_State *);
191 static int  resmethod_getfield(lua_State *);
192 static int  resmethod_setfield(lua_State *);
193 static void resmethod_destroy(void *);
194 static mrp_lua_resmethod_t *to_resmethod(lua_State *, int);
195
196 static mrp_attr_def_t *check_attrdefs(lua_State *, int, int *);
197 static void free_attrdefs(mrp_attr_def_t *);
198 static mrp_attr_t *check_attrs(lua_State *, int, attr_def_t *);
199 static void free_attrs(mrp_attr_t *);
200 static int check_attrindex(lua_State *, int, attr_def_t *);
201 static int check_boolean(lua_State *, int);
202 static mrp_resource_order_t check_order(lua_State *, int);
203 static int push_order(lua_State *, mrp_resource_order_t);
204 static field_t field_check(lua_State *, int, const char **);
205 static field_t field_name_to_type(const char *, size_t);
206
207
208 MRP_LUA_METHOD_LIST_TABLE (
209     zone_attr_methods,       /* methodlist name */
210     MRP_LUA_METHOD_CONSTRUCTOR  (zone_attr_create)
211 );
212
213 MRP_LUA_METHOD_LIST_TABLE (
214     resclass_methods,         /* methodlist name */
215     MRP_LUA_METHOD_CONSTRUCTOR  (resclass_create_from_lua)
216 );
217
218
219 MRP_LUA_METHOD_LIST_TABLE (
220     attributes_overrides,    /* methodlist name */
221     MRP_LUA_OVERRIDE_GETFIELD   (attributes_getvalue)
222     MRP_LUA_OVERRIDE_SETFIELD   (attributes_setvalue)
223     MRP_LUA_OVERRIDE_GETLENGTH  (attributes_getlength)
224 );
225
226 MRP_LUA_METHOD_LIST_TABLE (
227     zone_attr_overrides,     /* methodlist name */
228     MRP_LUA_OVERRIDE_CALL       (zone_attr_create)
229     MRP_LUA_OVERRIDE_GETFIELD   (zone_attr_getfield)
230     MRP_LUA_OVERRIDE_SETFIELD   (zone_attr_setfield)
231 );
232
233 MRP_LUA_METHOD_LIST_TABLE (
234     resclass_overrides,       /* methodlist name */
235     MRP_LUA_OVERRIDE_CALL       (resclass_create_from_lua)
236     MRP_LUA_OVERRIDE_GETFIELD   (resclass_getfield)
237     MRP_LUA_OVERRIDE_SETFIELD   (resclass_setfield)
238 );
239
240 MRP_LUA_METHOD_LIST_TABLE (
241     resource_overrides,       /* methodlist name */
242     MRP_LUA_OVERRIDE_GETFIELD   (resource_getfield)
243     MRP_LUA_OVERRIDE_SETFIELD   (resource_setfield)
244 );
245
246 MRP_LUA_CLASS_DEF_SIMPLE (
247     application_class,          /* main class & constructor name */
248     appclass_t,                 /* userdata type */
249     appclass_destroy,           /* userdata destructor */
250     MRP_LUA_METHOD_LIST (       /* main class methods */
251         MRP_LUA_METHOD_CONSTRUCTOR  (appclass_create)
252     ),
253     MRP_LUA_METHOD_LIST (       /* main class overrides */
254         MRP_LUA_OVERRIDE_CALL       (appclass_create)
255         MRP_LUA_OVERRIDE_GETFIELD   (appclass_getfield)
256         MRP_LUA_OVERRIDE_SETFIELD   (appclass_setfield)
257     )
258 );
259
260 MRP_LUA_CLASS_DEF_SIMPLE (
261     zone,                       /* main class & constructor name */
262     zone_t,                     /* userdata type */
263     zone_destroy,               /* userdata destructor */
264     MRP_LUA_METHOD_LIST (       /* main class methods */
265         MRP_LUA_METHOD_CONSTRUCTOR  (zone_create)
266     ),
267     MRP_LUA_METHOD_LIST (       /* main class overrides */
268         MRP_LUA_OVERRIDE_CALL       (zone_create)
269         MRP_LUA_OVERRIDE_GETFIELD   (zone_getfield)
270         MRP_LUA_OVERRIDE_SETFIELD   (zone_setfield)
271     )
272 );
273
274 MRP_LUA_CLASS_DEF (
275     zone,                       /* main class name */
276     attributes,                 /* constructor name */
277     attr_def_t,                 /* userdata type */
278     zone_attr_destroy,          /* userdata destructor */
279     zone_attr_methods,          /* class methods */
280     zone_attr_overrides         /* class overrides */
281 );
282
283 MRP_LUA_CLASS_DEF (
284     resource,                   /* main class name */
285     class,                      /* constructor name */
286     resclass_t,                 /* userdata type */
287     resclass_destroy,           /* userdata destructor */
288     resclass_methods,           /* class methods */
289     resclass_overrides          /* class overrides */
290 );
291
292
293 MRP_LUA_CLASS_DEF_SIMPLE (
294     resource,                   /* main class name */
295     mrp_lua_resmethod_t,        /* userdata type */
296     resmethod_destroy,          /* userdata destructor */
297     MRP_LUA_METHOD_LIST (
298         MRP_LUA_METHOD_CONSTRUCTOR  (resmethod_create_from_lua)
299     ),
300     MRP_LUA_METHOD_LIST (
301         MRP_LUA_OVERRIDE_CALL       (resmethod_create_from_lua)
302         MRP_LUA_OVERRIDE_GETFIELD   (resmethod_getfield)
303         MRP_LUA_OVERRIDE_SETFIELD   (resmethod_setfield)
304     )
305 );
306
307 attr_def_t           *zone_attr_defs;
308 attr_def_t           *resource_attr_defs[MRP_RESOURCE_MAX];
309 mrp_lua_resmethod_t  *resource_methods;
310
311
312 void mrp_resource_configuration_init(void)
313 {
314     static bool initialised = false;
315
316     lua_State *L;
317
318     if (!initialised && (L =  mrp_lua_get_lua_state())) {
319
320         appclass_class_create(L);
321         zone_class_create(L);
322         resclass_class_create(L);
323         resource_class_create(L);
324
325         mrp_resource_lua_init(L);
326
327         resource_methods_create(L);
328
329         mrp_debug("lua classes are ready for resource "
330                   "configuration and management");
331
332         initialised = true;
333     }
334 }
335
336
337 mrp_lua_resmethod_t *mrp_lua_get_resource_methods(void)
338 {
339     return resource_methods;
340 }
341
342 uint32_t mrp_lua_to_resource_id(lua_State *L, int t)
343 {
344     resclass_t *rc = to_resclass(L, t);
345
346     return rc ? rc->id : MRP_RESOURCE_ID_INVALID;
347 }
348
349 void mrp_lua_resclass_create_from_c(uint32_t id)
350 {
351     lua_State *L;
352     mrp_resource_def_t *rdef;
353     resclass_t *resclass;
354     attr_def_t *adef;
355     mrp_attr_def_t *attrs;
356     int nattr;
357
358     if ((L = mrp_lua_get_lua_state())) {
359
360         if (!(rdef = mrp_resource_definition_find_by_id(id)))
361             luaL_error(L, "invalid resource definition ID %d", id);
362
363         resclass = (resclass_t *)mrp_lua_create_object(L, RESCLASS_CLASS,
364                                                        rdef->name,0);
365         adef = mrp_allocz(sizeof(attr_def_t));
366         nattr = rdef->nattr;
367         attrs = mrp_allocz(sizeof(mrp_attr_def_t) * (nattr + 1));
368
369         if (!nattr)
370             mrp_attribute_copy_definitions(rdef->attrdefs, attrs);
371
372         if (!resclass)
373             luaL_error(L, "invalid or duplicate name '%s'", rdef->name);
374         if (!adef)
375             luaL_error(L,"can't to allocate memory for attribute definitions");
376
377         resclass->id = id;
378         resclass->name = mrp_strdup(rdef->name);
379         resclass->attrs = attrs;
380
381         adef->nattr = nattr;
382         adef->attrs = attrs;
383
384         resource_attr_defs[id] = adef;
385
386         lua_pop(L, 1);
387
388         mrp_log_info("resource class '%s' created", rdef->name);
389     }
390 }
391
392 int mrp_lua_resource_create(lua_State *L, mrp_resource_t *res)
393 {
394     mrp_resource_def_t *rdef;
395     attr_def_t *adef;
396     resource_t *r;
397
398     MRP_LUA_ENTER;
399
400     MRP_ASSERT(res, "invalid argument");
401
402     if (!(rdef = res->def))
403         lua_pushnil(L);
404     else {
405         adef = resource_attr_defs[rdef->id];
406
407         MRP_ASSERT(resource_attr_defs[rdef->id], "can't find attribute defs");
408
409         r = lua_newuserdata(L, sizeof(resource_t));
410
411         r->rsetid = res->rsetid;
412         r->resid = rdef->id;
413         r->name = rdef->name;
414         r->attr_tbl = attributes_create(L, RESOURCE,r, adef,
415                                         fetch_resource_attribute,
416                                         update_resource_attribute);
417
418         luaL_getmetatable(L, RESOURCE_CLASSID);
419         lua_setmetatable(L, -2);
420     }
421
422     MRP_LUA_LEAVE(1);
423 }
424
425
426 static void attributes_class_create(lua_State *L)
427 {
428     /* create a metatable for attributes */
429     luaL_newmetatable(L, ATTRIBUTE_CLASSID);
430     lua_pushliteral(L, "__index");
431     lua_pushvalue(L, -2);
432     lua_settable(L, -3);        /* metatable.__index = metatable */
433     luaL_openlib(L, NULL, attributes_overrides, 0);
434 }
435
436 static void appclass_class_create(lua_State *L)
437 {
438     mrp_lua_create_object_class(L, APPCLASS_CLASS);
439 }
440
441 static void zone_class_create(lua_State *L)
442 {
443     mrp_lua_create_object_class(L, ZONE_CLASS);
444     mrp_lua_create_object_class(L, ZONE_ATTR_CLASS);
445
446     attributes_class_create(L);
447
448     zone_attr_defs = mrp_lua_create_object(L, ZONE_ATTR_CLASS, NULL,0);
449     mrp_lua_set_object_name(L, ZONE_ATTR_CLASS, "attributes");
450     lua_pop(L, 1);
451 }
452
453 static void resclass_class_create(lua_State *L)
454 {
455     mrp_lua_create_object_class(L, RESCLASS_CLASS);
456 }
457
458 static void resource_class_create(lua_State *L)
459 {
460     /* create a metatable for resource instances */
461     luaL_newmetatable(L, RESOURCE_CLASSID);
462     lua_pushliteral(L, "__index");
463     lua_pushvalue(L, -2);
464     lua_settable(L, -3);        /* metatable.__index = metatable */
465     luaL_openlib(L, NULL, resource_overrides, 0);
466 }
467
468 static void resource_methods_create(lua_State *L)
469 {
470     mrp_lua_create_object_class(L, RESMETHOD_CLASS);
471     resource_methods = resmethod_create_from_c(L);
472 }
473
474
475 static int attributes_create(lua_State *L,
476                              attr_owner_t type, void *data,
477                              attr_def_t *def,
478                              attribute_access_t fetch,
479                              attribute_access_t update)
480 {
481     attr_t *attr;
482     int tblref;
483
484     MRP_LUA_ENTER;
485
486     attr = lua_newuserdata(L, sizeof(attr_t));
487
488     attr->owner.type = type;
489     attr->owner.data = data;
490     attr->def = def;
491     attr->fetch = fetch;
492     attr->update = update;
493
494     luaL_getmetatable(L, ATTRIBUTE_CLASSID);
495     lua_setmetatable(L, -2);
496
497     tblref = luaL_ref(L, LUA_REGISTRYINDEX);
498
499     MRP_LUA_LEAVE(tblref);
500 }
501
502 static int attributes_getvalue(lua_State *L)
503 {
504     attr_t *attr = check_attributes(L, 1);
505     int idx = check_attrindex(L, 2, attr->def);
506     mrp_attr_def_t *def = attr->def->attrs + idx;
507     mrp_attr_t av;
508
509     MRP_LUA_ENTER;
510
511     if (idx < 0) {
512         lua_pushnil(L);
513         return 1;
514     }
515
516     if (!(def->access & MRP_RESOURCE_READ)) {
517         luaL_error(L, "attempt to read a non-readable attribute %s",
518                    def->name);
519         MRP_LUA_LEAVE(0);
520     }
521
522     if (!attr->fetch(attr, idx, &av)) {
523         lua_pushnil(L);
524         MRP_LUA_LEAVE(1);
525     }
526
527     switch (def->type) {
528     case mqi_string:
529         if (av.value.string)
530             lua_pushstring(L, av.value.string);
531         else
532             lua_pushnil(L);
533         break;
534     case mqi_integer:
535     case mqi_unsignd:
536         lua_pushinteger(L, av.value.integer);
537         break;
538     case mqi_floating:
539         lua_pushnumber(L, av.value.floating);
540         break;
541     default:
542         lua_pushnil(L);
543         break;
544     }
545
546     MRP_LUA_LEAVE(1);
547 }
548
549 static int attributes_setvalue(lua_State *L)
550 {
551     attr_t *attr = check_attributes(L, 1);
552     int idx = check_attrindex(L, 2, attr->def);
553     mrp_attr_def_t *def = attr->def->attrs + idx;
554     mrp_attr_t av;
555
556     MRP_LUA_ENTER;
557
558     if (idx < 0)
559         luaL_error(L, "attribute %s dows not exist", def->name);
560
561     if (!(def->access & MRP_RESOURCE_WRITE))
562         luaL_error(L, "attempt to read a readonly attribute %s", def->name);
563
564     switch (def->type) {
565     case mqi_string:
566         av.value.string = luaL_checkstring(L, 3);
567         break;
568     case mqi_integer:
569         av.value.integer =  luaL_checkinteger(L, 3);
570         break;
571     case mqi_unsignd:
572         if ((av.value.integer = luaL_checkinteger(L, 3)) < 0) {
573             luaL_error(L, "attempt to update an unsigned attribute "
574                        "with negative value");
575         }
576         break;
577     case mqi_floating:
578         av.value.floating = luaL_checknumber(L, 3);
579         break;
580     default:
581         luaL_error(L, "internal error: invalid attribute type");
582         break;
583     }
584
585     if (!attr->update(attr, idx, &av))
586         luaL_error(L, "attribute update failed");
587
588     MRP_LUA_LEAVE(0);
589 }
590
591 static int attributes_getlength(lua_State *L)
592 {
593     attr_t *attr = check_attributes(L, 1);
594     attr_def_t *def = attr->def;
595
596     MRP_LUA_ENTER;
597
598     lua_pushinteger(L, def ? def->nattr : 0);
599
600     MRP_LUA_LEAVE(1);
601 }
602
603 static attr_t *check_attributes(lua_State *L, int idx)
604 {
605     return (attr_t *)luaL_checkudata(L, idx, ATTRIBUTE_CLASSID);
606 }
607
608 static int push_attributes(lua_State *L, int attr_tbl)
609 {
610     lua_rawgeti(L, LUA_REGISTRYINDEX, attr_tbl);
611     return 1;
612 }
613
614
615 static int appclass_create(lua_State *L)
616 {
617     appclass_t *appclass;
618     size_t fldnamlen;
619     const char *fldnam;
620     int priority = 0;
621     int modal = -1;
622     int share = -1;
623     mrp_resource_order_t order = 0;
624     const char *name = NULL;
625
626     MRP_LUA_ENTER;
627
628     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
629
630         switch (field_name_to_type(fldnam, fldnamlen)) {
631
632         case NAME:
633             name = mrp_strdup(luaL_checkstring(L, -1));
634             break;
635
636         case PRIORITY:
637             priority = luaL_checkint(L, -1);
638             break;
639
640         case MODAL:
641             modal = check_boolean(L, -1);
642             break;
643
644         case SHARE:
645             share = check_boolean(L, -1);
646             break;
647
648         case ORDER:
649             order = check_order(L, -1);
650             break;
651
652         default:
653             luaL_error(L, "unexpected field '%s'", fldnam);
654             break;
655         }
656     }
657
658     if (!name)
659         luaL_error(L, "missing or wrong name field");
660     if (modal < 0)
661         luaL_error(L, "missing or wrong modal field");
662     if (modal && share)
663         luaL_error(L, "modal class can't share");
664     if (share < 0)
665         luaL_error(L, "missing or wrong share field");
666     if (!order)
667         luaL_error(L, "missing or wrong order field");
668     if (priority < 0)
669         luaL_error(L, "negative priority");
670     if (!mrp_application_class_create(name, priority, modal, share, order))
671         luaL_error(L, "failed to create application class '%s'", name);
672
673     appclass = (appclass_t *)mrp_lua_create_object(L, APPCLASS_CLASS, name,0);
674
675     if (!appclass)
676         luaL_error(L, "invalid or duplicate name '%s'", name);
677     else {
678         appclass->name = name;
679         mrp_log_info("application class '%s' created", name);
680     }
681     MRP_LUA_LEAVE(1);
682 }
683
684 static int appclass_getfield(lua_State *L)
685 {
686     appclass_t *appclass = to_appclass(L, 1);
687     field_t fld = field_check(L, 2, NULL);
688     mrp_application_class_t *ac;
689
690     MRP_LUA_ENTER;
691
692     lua_pop(L, 1);
693
694     if (!appclass || !(ac = mrp_application_class_find(appclass->name)))
695         lua_pushnil(L);
696     else {
697         switch (fld) {
698         case NAME:       lua_pushstring(L, ac->name);         break;
699         case PRIORITY:   lua_pushinteger(L, ac->priority);    break;
700         case MODAL:      lua_pushboolean(L, ac->modal);       break;
701         case SHARE:      lua_pushboolean(L, ac->share);       break;
702         case ORDER:      push_order(L, ac->order);            break;
703         default:         lua_pushnil(L);                      break;
704         }
705     }
706
707     MRP_LUA_LEAVE(1);
708 }
709
710 static int appclass_setfield(lua_State *L)
711 {
712     MRP_LUA_ENTER;
713
714     luaL_error(L, "can't modify application classes after definition");
715
716     MRP_LUA_LEAVE(0);
717 }
718
719 static void appclass_destroy(void *data)
720 {
721     appclass_t *appclass = (appclass_t *)data;
722
723     MRP_LUA_ENTER;
724
725     mrp_free((void *)appclass->name);
726
727     MRP_LUA_LEAVE_NOARG;
728 }
729
730 #if 0
731 static appclass_t *check_appclass(lua_State *L, int idx)
732 {
733     return (appclass_t *)mrp_lua_check_object(L, APPCLASS_CLASS, idx);
734 }
735 #endif
736
737 static appclass_t *to_appclass(lua_State *L, int idx)
738 {
739     return (appclass_t *)mrp_lua_to_object(L, APPCLASS_CLASS, idx);
740 }
741
742
743 static int zone_create(lua_State *L)
744 {
745     zone_t *zone;
746     size_t fldnamlen;
747     const char *fldnam;
748     uint32_t id;
749     const char *name = NULL;
750     mrp_attr_t *attrs = NULL;
751
752     MRP_LUA_ENTER;
753
754     MRP_ASSERT(zone_attr_defs, "invocation prior to initialization");
755
756     if (!zone_attr_defs->attrs)
757         luaL_error(L, "attempt to create zone before defining attributes");
758
759     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
760
761         switch (field_name_to_type(fldnam, fldnamlen)) {
762
763         case NAME:
764             name = mrp_strdup(luaL_checkstring(L, -1));
765             break;
766
767         case ATTRIBUTES:
768             attrs = check_attrs(L, -1, zone_attr_defs);
769             break;
770
771         default:
772             luaL_error(L, "unexpected field '%s'", fldnam);
773             break;
774         }
775     }
776
777     if (!name)
778         luaL_error(L, "missing or wrong name field");
779     if ((id = mrp_zone_create(name,attrs)) == MRP_ZONE_ID_INVALID)
780         luaL_error(L, "failed to create zone");
781
782     free_attrs(attrs);
783
784     zone = (zone_t *)mrp_lua_create_object(L, ZONE_CLASS, name,0);
785
786     if (!zone)
787         luaL_error(L, "invalid or duplicate name '%s'", name);
788     else {
789         zone->id = id;
790         zone->name = name;
791         zone->attr_tbl = attributes_create(L, ZONE,zone, zone_attr_defs,
792                                            fetch_zone_attribute,
793                                            update_zone_attribute);
794
795         mrp_log_info("zone '%s' created", name);
796     }
797
798     MRP_LUA_LEAVE(1);
799 }
800
801 static int zone_getfield(lua_State *L)
802 {
803     zone_t  *zone = to_zone(L, 1);
804     field_t  fld  = field_check(L, 2, NULL);
805
806     MRP_LUA_ENTER;
807
808     lua_pop(L, 1);
809
810     if (!zone) {
811         /* attempt to access a zone definition field */
812         switch (fld) {
813         case ATTRIBUTES:    mrp_lua_push_object(L, zone_attr_defs);     break;
814         default:            lua_pushnil(L);                             break;
815         }
816     }
817     else {
818         /* attempt to access a zone instance field */
819         switch (fld) {
820         case ATTRIBUTES:     push_attributes(L, zone->attr_tbl);        break;
821         case ID:             lua_pushinteger(L, zone->id + 1);          break;
822         case NAME:           lua_pushstring(L, zone->name);             break;
823         default:             lua_pushnil(L);                            break;
824         }
825     }
826
827     MRP_LUA_LEAVE(1);
828 }
829
830 static int zone_setfield(lua_State *L)
831 {
832     zone_t *zone = to_zone(L, 1);
833     field_t fld  = field_check(L, 2, NULL);
834
835     MRP_LUA_ENTER;
836
837     if (zone || fld != ATTRIBUTES)
838         luaL_error(L, "zones can't be exetended after definition");
839
840     MRP_LUA_LEAVE(0);
841 }
842
843 static void zone_destroy(void *data)
844 {
845     /* zone_t *zone = (zone_t *)data; */
846
847     MRP_UNUSED(data);
848
849     MRP_LUA_ENTER;
850
851     MRP_LUA_LEAVE_NOARG;
852 }
853
854 #if 0
855 static zone_t *check_zone(lua_State *L, int idx)
856 {
857     return (zone_t *)mrp_lua_check_object(L, ZONE_CLASS, idx);
858 }
859 #endif
860
861 static zone_t *to_zone(lua_State *L, int idx)
862 {
863     return (zone_t *)mrp_lua_to_object(L, ZONE_CLASS, idx);
864 }
865
866 static int zone_attr_create(lua_State *L)
867 {
868     mrp_attr_def_t *attrs;
869     int nattr;
870
871     MRP_LUA_ENTER;
872
873     MRP_ASSERT(zone_attr_defs, "invocation prior to initialization");
874
875     if (zone_attr_defs->attrs)
876         luaL_error(L, "zone attributes already defined");
877     else {
878         attrs = check_attrdefs(L, 2, &nattr);
879
880         mrp_zone_definition_create(attrs);
881
882         zone_attr_defs->nattr = nattr;
883         zone_attr_defs->attrs = attrs;
884     }
885
886     mrp_lua_push_object(L, zone_attr_defs);
887
888     mrp_log_info("zone attributes defined");
889
890     MRP_LUA_LEAVE(1);
891 }
892
893 static int  zone_attr_getfield(lua_State *L)
894 {
895     zone_t *zone;
896     int idx;
897
898     MRP_LUA_ENTER;
899
900     MRP_ASSERT(zone_attr_defs, "invocation prior to initialization");
901
902     if (!(zone = to_zone(L, 1))) {
903         mrp_debug("zone attribute definition => attribute index");
904         if ((idx = check_attrindex(L, 2, zone_attr_defs)) < 0)
905             lua_pushnil(L);
906         else
907             lua_pushinteger(L, idx);
908     }
909     else {
910         mrp_debug("zone attribute => nil");
911         lua_pushnil(L);
912     }
913
914     MRP_LUA_LEAVE(1);
915 }
916
917 static int  zone_attr_setfield(lua_State *L)
918 {
919     MRP_UNUSED(L);
920
921     MRP_LUA_ENTER;
922
923     MRP_LUA_LEAVE(0);
924 }
925
926
927 static void zone_attr_destroy(void *data)
928 {
929     /* attr_def_t *attr = (attr_def_t *)data; */
930
931     MRP_UNUSED(data);
932
933     MRP_LUA_ENTER;
934
935     MRP_LUA_LEAVE_NOARG;
936 }
937
938 #if 0
939 static attr_def_t *check_zone_attr(lua_State *L, int idx)
940 {
941     return (attr_def_t *)mrp_lua_check_object(L, ZONE_ATTR_CLASS, idx);
942 }
943 #endif
944
945 #if 0
946 static attr_def_t *to_zone_attr(lua_State *L, int idx)
947 {
948     return (attr_def_t *)mrp_lua_to_object(L, ZONE_ATTR_CLASS, idx);
949 }
950 #endif
951
952 static bool fetch_zone_attribute(attr_t *attr, int idx, mrp_attr_t *retval)
953 {
954     mrp_zone_t *z;
955     zone_t *zone;
956
957     if (attr->owner.type == ZONE && (zone = (zone_t *)attr->owner.data)) {
958         if ((z = mrp_zone_find_by_id(zone->id))) {
959             if (mrp_zone_read_attribute(z, idx, retval))
960                 return true;
961         }
962     }
963
964     return false;
965 }
966
967 static bool update_zone_attribute(attr_t *attr, int idx, mrp_attr_t *value)
968 {
969     mrp_zone_t *z;
970     zone_t *zone;
971
972     MRP_UNUSED(idx);
973     MRP_UNUSED(value);
974
975     if (attr->owner.type == ZONE && (zone = (zone_t *)attr->owner.data)) {
976         if ((z = mrp_zone_find_by_id(zone->id))) {
977 #if 0
978             if (mrp_zone_write_attribute(z, idx, value))
979                 return true;
980 #endif
981         }
982     }
983
984     return false;
985 }
986
987 static int resclass_create_from_lua(lua_State *L)
988 {
989     resclass_t *resclass;
990     size_t fldnamlen;
991     const char *fldnam;
992     int nattr = 0;
993     uint32_t id;
994     const char *name = NULL;
995     mrp_attr_def_t *attrs = NULL;
996     bool shareable = false;
997     mrp_resource_mgr_ftbl_t *ftbl = NULL;
998     void *mgrdata = NULL;
999     attr_def_t *adef;
1000
1001     MRP_LUA_ENTER;
1002
1003     MRP_LUA_FOREACH_FIELD(L, 2, fldnam, fldnamlen) {
1004
1005         switch (field_name_to_type(fldnam, fldnamlen)) {
1006
1007         case NAME:
1008             name = mrp_strdup(luaL_checkstring(L, -1));
1009             break;
1010
1011         case SHAREABLE:
1012             luaL_argcheck(L, lua_isboolean(L,-1), 2, "attempt to assign "
1013                           "non-boolean value to 'shareable' field");
1014             shareable = lua_toboolean(L, -1);
1015             break;
1016
1017         case ATTRIBUTES:
1018             attrs = check_attrdefs(L, -1, &nattr);
1019             break;
1020
1021         default:
1022             luaL_error(L, "unexpected field '%s'", fldnam);
1023             break;
1024         }
1025     }
1026
1027     if (!name)
1028         luaL_error(L, "missing or wrong name field");
1029
1030     id = mrp_resource_definition_create(name, shareable, attrs,ftbl,mgrdata);
1031
1032     MRP_ASSERT(id < MRP_RESOURCE_MAX, "resource id is out of range");
1033
1034     if (id == MRP_RESOURCE_ID_INVALID)
1035         luaL_error(L, "failed to register resource class '%s'", name);
1036
1037     resclass = (resclass_t *)mrp_lua_create_object(L, RESCLASS_CLASS, name,0);
1038     adef = mrp_allocz(sizeof(attr_def_t));
1039
1040     if (!resclass)
1041         luaL_error(L, "invalid or duplicate name '%s'", name);
1042     if (!adef)
1043         luaL_error(L, "failed to allocate memory for attribute definitions");
1044
1045     resclass->id = id;
1046     resclass->name = name;
1047     resclass->attrs = attrs;
1048
1049     adef->nattr = nattr;
1050     adef->attrs = attrs;
1051
1052     resource_attr_defs[id] = adef;
1053
1054     mrp_log_info("resource class '%s' created", name);
1055
1056     MRP_LUA_LEAVE(1);
1057 }
1058
1059 static int resclass_getfield(lua_State *L)
1060 {
1061     resclass_t *rc = to_resclass(L, 1);
1062     field_t fld = field_check(L, 2, NULL);
1063     mrp_resource_def_t *rd;
1064
1065     MRP_LUA_ENTER;
1066
1067     lua_pop(L, 1);
1068
1069     if (!rc || !(rd = mrp_resource_definition_find_by_name(rc->name)))
1070         lua_pushnil(L);
1071     else {
1072         switch (fld) {
1073         case NAME:       lua_pushstring(L, rd->name);         break;
1074         case ID:         lua_pushinteger(L, rd->id + 1);      break;
1075         case SHAREABLE:  lua_pushboolean(L, rd->shareable);   break;
1076         default:         lua_pushnil(L);                      break;
1077         }
1078     }
1079
1080     MRP_LUA_LEAVE(1);
1081 }
1082
1083 static int resclass_setfield(lua_State *L)
1084 {
1085     MRP_LUA_ENTER;
1086
1087     luaL_error(L, "can't modify resource classes after definition");
1088
1089     MRP_LUA_LEAVE(1);
1090 }
1091
1092 static void resclass_destroy(void *data)
1093 {
1094     resclass_t *rc = (resclass_t *)data;
1095
1096     MRP_LUA_ENTER;
1097
1098     mrp_free((void *)rc->name);
1099     free_attrdefs(rc->attrs);
1100
1101     MRP_LUA_LEAVE_NOARG;
1102 }
1103
1104 #if 0
1105 static resclass_t *check_resclass(lua_State *L, int idx)
1106 {
1107     return (resclass_t *)mrp_lua_check_object(L, RESCLASS_CLASS, idx);
1108 }
1109 #endif
1110
1111 static resclass_t *to_resclass(lua_State *L, int idx)
1112 {
1113     return (resclass_t *)mrp_lua_to_object(L, RESCLASS_CLASS, idx);
1114 }
1115
1116 static int resource_getfield(lua_State *L)
1117 {
1118     const char *name;
1119     resource_t *res = check_resource(L, 1);
1120     field_t fld = field_check(L, 2, &name);
1121     mrp_resource_set_t *s;
1122     mrp_resource_t *r;
1123     mrp_resource_mask_t m;
1124
1125     MRP_LUA_ENTER;
1126
1127     switch (fld) {
1128
1129     case ATTRIBUTES:
1130         push_attributes(L, res->attr_tbl);
1131         break;
1132
1133     case SHARED:
1134     case SHARE:
1135         if (!(r = mrp_resource_set_find_resource(res->rsetid, res->name)))
1136             lua_pushnil(L);
1137         else
1138             lua_pushboolean(L, r->shared);
1139         break;
1140
1141     default:
1142         if (!(s = mrp_resource_set_find_by_id(res->rsetid)))
1143             m = 0;
1144         else
1145             m = ((mrp_resource_mask_t)1) << res->resid;
1146
1147         switch (fld) {
1148         case MANDATORY:
1149             lua_pushboolean(L, s->resource.mask.mandatory & m ? true : false);
1150             break;
1151         case GRANT:
1152             lua_pushboolean(L, s->resource.mask.grant & m ? true : false);
1153             break;
1154         default:
1155             lua_pushnil(L);
1156             break;
1157         }
1158
1159         break;
1160     }
1161
1162     MRP_LUA_LEAVE(1);
1163 }
1164
1165 static int resource_setfield(lua_State *L)
1166 {
1167     MRP_UNUSED(L);
1168
1169     MRP_LUA_ENTER;
1170
1171     MRP_LUA_LEAVE(0);
1172 }
1173
1174 static resource_t *check_resource(lua_State *L, int idx)
1175 {
1176     return (resource_t *)luaL_checkudata(L, idx, RESOURCE_CLASSID);
1177 }
1178
1179 static bool fetch_resource_attribute(attr_t *attr, int idx, mrp_attr_t *retval)
1180 {
1181     mrp_resource_set_t *rset;
1182     resource_t *resource;
1183     mrp_attr_t *a;
1184
1185     if (attr->owner.type == RESOURCE) {
1186         if ((resource = (resource_t *)attr->owner.data)) {
1187             if ((rset = mrp_resource_set_find_by_id(resource->rsetid))) {
1188                 a = mrp_resource_set_read_attribute(rset, resource->name,
1189                                                     idx, retval);
1190                 return a ? true : false;
1191             }
1192         }
1193     }
1194
1195     return false;
1196 }
1197
1198
1199 static bool update_resource_attribute(attr_t *attr, int idx, mrp_attr_t *value)
1200 {
1201     mrp_resource_set_t *rset;
1202     resource_t *resource;
1203     mrp_attr_t values[2];
1204     int sts;
1205
1206     MRP_UNUSED(idx);
1207
1208     if (attr->owner.type == RESOURCE) {
1209         if ((resource = (resource_t *)attr->owner.data)) {
1210             if ((rset = mrp_resource_set_find_by_id(resource->rsetid))) {
1211                 memcpy(values + 0, value, sizeof(mrp_attr_t));
1212                 memset(values + 1, 0,     sizeof(mrp_attr_t));
1213
1214                 sts = mrp_resource_set_write_attributes(rset, resource->name,
1215                                                         values);
1216                 return (sts < 0) ? false : true;
1217             }
1218         }
1219     }
1220
1221     return false;
1222 }
1223
1224 static mrp_lua_resmethod_t *resmethod_create_from_c(lua_State *L)
1225 {
1226     mrp_lua_resmethod_t *method = mrp_lua_create_object(L, RESMETHOD_CLASS,
1227                                                         "method",0);
1228
1229     if (!method)
1230         luaL_error(L, "invalid or duplicate name 'method'");
1231
1232     return method;
1233 }
1234
1235 static int resmethod_create_from_lua(lua_State *L)
1236 {
1237     MRP_LUA_ENTER;
1238
1239     luaL_error(L, "singleton object has already been created");
1240
1241     lua_pushnil(L);
1242
1243     MRP_LUA_LEAVE(1);
1244 }
1245
1246 static int resmethod_getfield(lua_State *L)
1247 {
1248     const char *name;
1249     mrp_lua_resmethod_t *method = to_resmethod(L, 1);
1250     field_t fld = field_check(L, 2, &name);
1251
1252     MRP_LUA_ENTER;
1253
1254     lua_pop(L, 1);
1255
1256     if (!method) {
1257         /* attempt to access a resclass or owners */
1258         switch (fld) {
1259         case METHOD:   mrp_lua_push_object(L, resource_methods);  break;
1260         case OWNERS:   lua_pushstring(L,name); lua_rawget(L,1);   break;
1261         default:       lua_pushnil(L);                            break;
1262         }
1263     }
1264     else {
1265         /* attempt to access a method member */
1266         if (!resource_methods)
1267             lua_pushnil(L);
1268         else {
1269             switch (fld) {
1270             case VETO:
1271                 lua_pushstring(L, name);
1272                 lua_rawget(L, 1);
1273                 break;
1274             default:
1275                 lua_pushnil(L);
1276                 break;
1277             }
1278         }
1279     }
1280
1281     MRP_LUA_LEAVE(1);
1282 }
1283
1284 static int resmethod_setfield(lua_State *L)
1285 {
1286     const char *name;
1287     mrp_lua_resmethod_t *method = to_resmethod(L, 1);
1288     field_t fld = field_check(L, 2, &name);
1289
1290     MRP_LUA_ENTER;
1291
1292     if (method) {
1293         switch (fld) {
1294         case VETO:
1295             lua_pushstring(L, name);
1296             lua_pushvalue(L, 3);
1297             method->veto = mrp_funcarray_check(L, -1);
1298             lua_rawset(L, 1);
1299             break;
1300         default:
1301             luaL_error(L, "invalid method '%s'", name);
1302             break;
1303         }
1304     }
1305
1306     MRP_LUA_LEAVE(0);
1307 }
1308
1309 static void resmethod_destroy(void *data)
1310 {
1311     mrp_lua_resmethod_t *method = (mrp_lua_resmethod_t *)data;
1312
1313     MRP_LUA_ENTER;
1314
1315     method->veto = NULL;
1316
1317     MRP_LUA_LEAVE_NOARG;
1318 }
1319
1320 static mrp_lua_resmethod_t *to_resmethod(lua_State *L, int idx)
1321 {
1322     return (mrp_lua_resmethod_t *)mrp_lua_to_object(L, RESMETHOD_CLASS, idx);
1323 }
1324
1325
1326 static mrp_attr_def_t *check_attrdefs(lua_State *L, int t, int *ret_len)
1327 {
1328     mrp_attr_def_t attrdefs[128];
1329     mrp_attr_def_t *ad, *end, *dup;
1330     size_t i;
1331     const char *name;
1332     const char *string;
1333     const char *access;
1334     bool value_set;
1335     int len;
1336     size_t size;
1337     size_t namlen;
1338
1339     t = (t < 0) ? lua_gettop(L) + t + 1 : t;
1340
1341     luaL_checktype(L, t, LUA_TTABLE);
1342
1343     end = (ad = attrdefs) + (MRP_ARRAY_SIZE(attrdefs) - 1);
1344
1345     MRP_LUA_FOREACH_FIELD(L, t, name, namlen) {
1346         if (!name[0])
1347             luaL_error(L, "invalid attribute definition");
1348         if (ad >= end)
1349             luaL_error(L, "too many attributes");
1350
1351         ad->name = mrp_strdup(name);
1352         ad->type = mqi_error;
1353         ad->access = MRP_RESOURCE_READ;
1354
1355         value_set = false;
1356
1357         luaL_checktype(L, -1, LUA_TTABLE);
1358
1359
1360         for (lua_pushnil(L);  lua_next(L, -2);  lua_pop(L, 1)) {
1361             if (lua_type(L, -2) != LUA_TNUMBER)
1362                 goto error;
1363
1364             i = lua_tointeger(L, -2);
1365
1366             switch (i) {
1367             case 1:
1368                 ad->type = lua_tointeger(L, -1);
1369                 break;
1370             case 2:
1371                 switch (ad->type) {
1372                 case mqi_string:
1373                     if ((string = lua_tostring(L, -1))) {
1374                         ad->value.string = mrp_strdup(string);
1375                         value_set = true;
1376                     }
1377                     break;
1378                 case mqi_integer:
1379                     ad->value.integer = lua_tointeger(L, -1);
1380                     value_set = true;
1381                     break;
1382                 case mqi_unsignd:
1383                     ad->value.integer = lua_tointeger(L, -1);
1384                     value_set = true;
1385                     break;
1386                 case mqi_floating:
1387                     ad->value.floating = lua_tonumber(L, -1);
1388                     value_set = true;
1389                     break;
1390                 default:
1391                     break;
1392                 }
1393                 break;
1394             case 3:
1395                 if (!(access = lua_tostring(L, -1)))
1396                     ad->type = mqi_error;
1397                 else {
1398                     if (!strcasecmp(access, "read"))
1399                         ad->access = MRP_RESOURCE_READ;
1400                     else if (!strcasecmp(access, "write"))
1401                         ad->access = MRP_RESOURCE_WRITE;
1402                     else if (!strcasecmp(access, "rw"))
1403                         ad->access = MRP_RESOURCE_RW;
1404                     else
1405                         ad->type = mqi_error;
1406                 }
1407                 break;
1408             default:
1409                 ad->type = mqi_error;
1410                 break;
1411             }
1412         } /* for */
1413
1414         if (!value_set ||
1415             (ad->type != mqi_string  &&
1416              ad->type != mqi_integer &&
1417              ad->type != mqi_unsignd &&
1418              ad->type != mqi_floating ))
1419             goto error;
1420
1421         ad++;
1422     } /* foreach */
1423
1424     memset(ad, 0, sizeof(mrp_attr_def_t));
1425
1426     len  = ad - attrdefs;
1427     size = sizeof(mrp_attr_def_t) * (len+1);
1428     dup  = mrp_alloc(size);
1429
1430     if (!dup)
1431         luaL_error(L, "failed to allocate %u byte memory", size);
1432
1433     memcpy(dup, attrdefs, size);
1434
1435     if (ret_len)
1436         *ret_len = len;
1437
1438     return dup;
1439
1440  error:
1441     luaL_argerror(L, t, "malformed attribute definition");
1442     return NULL;
1443 }
1444
1445
1446 static void free_attrdefs(mrp_attr_def_t *attrdefs)
1447 {
1448     mrp_attr_def_t *ad;
1449
1450     if (attrdefs) {
1451         for (ad = attrdefs;  ad->name;  ad++) {
1452             mrp_free((void *)ad->name);
1453             if (ad->type == mqi_string)
1454                 mrp_free((void *)ad->value.string);
1455         }
1456         mrp_free(attrdefs);
1457     }
1458 }
1459
1460 static int attr_name_to_index(const char *name, attr_def_t *def)
1461 {
1462     mrp_attr_def_t *attrs = def->attrs;
1463     int idx;
1464
1465     for (idx = 0;  idx < def->nattr;  idx++) {
1466         if (!strcmp(name, attrs[idx].name))
1467             return idx;
1468     }
1469
1470     return -1;
1471 }
1472
1473 static mrp_attr_t *check_attrs(lua_State *L, int t, attr_def_t *defs)
1474 {
1475     mrp_attr_t attr[128];
1476     mrp_attr_t *at, *end, *dup;
1477     const char *name;
1478     size_t namlen;
1479     size_t len;
1480     size_t size;
1481     int i;
1482
1483     t = (t < 0) ? lua_gettop(L) + t + 1 : t;
1484
1485     luaL_checktype(L, t, LUA_TTABLE);
1486
1487     end = (at = attr) + (MRP_ARRAY_SIZE(attr) - 1);
1488
1489     MRP_LUA_FOREACH_FIELD(L, t, name, namlen) {
1490         if (!name[0])
1491             luaL_error(L, "invalid attribute definition");
1492         if (at >= end)
1493             luaL_error(L, "too many attributes");
1494         if ((i = attr_name_to_index(name, defs)) < 0)
1495             luaL_error(L, "attribute %s do not exist", name);
1496
1497         at->name = mrp_strdup(name);
1498
1499         switch ((at->type = defs->attrs[i].type)) {
1500         case mqi_string:
1501             at->value.string = mrp_strdup(luaL_checkstring(L,-1));
1502             break;
1503         case mqi_integer:
1504             at->value.integer = luaL_checkinteger(L,-1);
1505             break;
1506         case mqi_unsignd:
1507             if ((at->value.integer = luaL_checkinteger(L,-1)) < 0)
1508                 luaL_error(L, "attempt to give negative value to an "
1509                            "unsigned integer");
1510             break;
1511         default:
1512             luaL_error(L, "Internal error: invalid type for attribute");
1513             break;
1514         }
1515
1516         at++;
1517     }
1518
1519     memset(at, 0, sizeof(mrp_attr_t));
1520
1521     len  = at - attr;
1522     size = sizeof(mrp_attr_t) * (len + 1);
1523
1524     dup = mrp_alloc(size);
1525     memcpy(dup, attr, size);
1526
1527     return dup;
1528 }
1529
1530
1531 static void free_attrs(mrp_attr_t *attrs)
1532 {
1533     mrp_attr_t *at;
1534
1535     if (attrs) {
1536         for (at = attrs;  at->name;  at++) {
1537             mrp_free((void *)at->name);
1538             if (at->type == mqi_string)
1539                 mrp_free((void *)at->value.string);
1540         }
1541         mrp_free(attrs);
1542     }
1543 }
1544
1545
1546 static int check_attrindex(lua_State *L, int arg, attr_def_t *def)
1547 {
1548     const char *name;
1549     int idx;
1550
1551     if (!def || !def->attrs)
1552         return -1;
1553
1554     switch (lua_type(L, arg)) {
1555     case LUA_TNUMBER:
1556         idx = lua_tointeger(L, arg);
1557         return (idx >= 0 && idx < def->nattr) ? idx : -1;
1558     case LUA_TSTRING:
1559         name = lua_tostring(L, arg);
1560         return attr_name_to_index(name, def);
1561     default:
1562         return -1;
1563     }
1564 }
1565
1566
1567 static int check_boolean(lua_State *L, int idx)
1568 {
1569     if (!lua_isboolean(L, idx))
1570         luaL_argerror(L, idx, "expected boolean");
1571     return lua_toboolean(L, idx) ? 1 : 0;
1572 }
1573
1574 static mrp_resource_order_t check_order(lua_State *L, int idx)
1575 {
1576     const char *str = luaL_checkstring(L, idx);
1577
1578     if (!strcasecmp(str, "fifo"))
1579         return MRP_RESOURCE_ORDER_FIFO;
1580
1581     if (!strcasecmp(str, "lifo"))
1582         return MRP_RESOURCE_ORDER_LIFO;
1583
1584     luaL_error(L, "invalid value for order ('fifo' or 'lifo' accepted only)");
1585
1586     return MRP_RESOURCE_ORDER_UNKNOWN;
1587 }
1588
1589 static int push_order(lua_State *L, mrp_resource_order_t order)
1590 {
1591     const char *str;
1592
1593     switch (order) {
1594     case MRP_RESOURCE_ORDER_FIFO:   str = "fifo";        break;
1595     case MRP_RESOURCE_ORDER_LIFO:   str = "lifo";        break;
1596     default:                        str = "<unknown>";   break;
1597     }
1598
1599     lua_pushstring(L, str);
1600
1601     return 1;
1602 }
1603
1604
1605 static field_t field_check(lua_State *L, int idx, const char **ret_fldnam)
1606 {
1607     const char *fldnam;
1608     size_t fldnamlen;
1609     field_t fldtyp;
1610
1611     if (!(fldnam = lua_tolstring(L, idx, &fldnamlen)))
1612         fldtyp = 0;
1613     else
1614         fldtyp = field_name_to_type(fldnam, fldnamlen);
1615
1616     if (ret_fldnam)
1617         *ret_fldnam = fldnam;
1618
1619     return fldtyp;
1620 }
1621
1622
1623 static field_t field_name_to_type(const char *name, size_t len)
1624 {
1625     switch (len) {
1626
1627     case 2:
1628         if (!strcmp(name, "id"))
1629             return ID;
1630         break;
1631
1632     case 4:
1633         if (!strcmp(name, "name"))
1634             return NAME;
1635         if (!strcmp(name, "veto"))
1636             return VETO;
1637         break;
1638
1639     case 5:
1640         if (!strcmp(name, "class"))
1641             return CLASS;
1642         if (!strcmp(name, "modal"))
1643             return MODAL;
1644         if (!strcmp(name, "share"))
1645             return SHARE;
1646         if (!strcmp(name, "grant"))
1647             return GRANT;
1648         if (!strcmp(name, "order"))
1649             return ORDER;
1650         break;
1651
1652     case 6:
1653         if (!strcmp(name, "method"))
1654             return METHOD;
1655         if (!strcmp(name, "owners"))
1656             return OWNERS;
1657         if (!strcmp(name, "shared"))
1658             return SHARED;
1659         break;
1660
1661     case 8:
1662         if (!strcmp(name, "priority"))
1663             return PRIORITY;
1664         break;
1665
1666     case 9:
1667         if (!strcmp(name, "mandatory"))
1668             return MANDATORY;
1669         if (!strcmp(name, "shareable"))
1670             return SHAREABLE;
1671         break;
1672
1673     case 10:
1674         if (!strcmp(name, "attributes"))
1675             return ATTRIBUTES;
1676         break;
1677
1678     default:
1679         break;
1680     }
1681
1682     return 0;
1683 }
1684
1685 /*
1686  * Local Variables:
1687  * c-basic-offset: 4
1688  * indent-tabs-mode: nil
1689  * End:
1690  *
1691  */