2 * Copyright (c) 2004 Scott Ullrich <GeekGod@GeekGod.com>
3 * Portions Copyright (c) 2004 Chris Pressey <cpressey@catseye.mine.nu>
5 * Copyright (c) 2004 The DragonFly Project.
8 * This code is derived from software contributed to The DragonFly Project
9 * by Scott Ullrich and Chris Pressey (see above for e-mail addresses).
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
18 * 2. Redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in
20 * the documentation and/or other materials provided with the
23 * 3. Neither the name of The DragonFly Project nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific, prior written permission.
27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
30 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
31 * COPYRIGHT HOLDERS, CONTRIBUTORS OR VOICES IN THE AUTHOR'S HEAD
32 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY
33 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
34 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
36 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
37 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
38 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
40 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
41 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
42 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
43 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * dfui.c - libdfui Bindings for Lua
51 * $Id: dfui.c,v 1.64 2005/04/04 13:56:37 den Exp $
58 #include "dfui/dfui.h"
59 #include "dfui/dump.h"
60 #include "dfui/system.h"
62 #include "lua50/lua.h"
63 #include "lua50/lauxlib.h"
64 #include "lua50/lualib.h"
68 LUA_CHECK_FUNCTION(dfui_connection, "DFUIConnection", struct dfui_connection *)
69 LUA_PUSH_FUNCTION(dfui_connection, "DFUIConnection", struct dfui_connection *)
71 #define DFUI_OBJ_FORM 1
72 #define DFUI_OBJ_FIELD 2
73 #define DFUI_OBJ_ACTION 3
76 dfui_field_options_from_lua_table(lua_State *L, struct dfui_field *fi)
79 while (lua_next(L, -2) != 0) {
80 if (lua_isstring(L, -1)) {
81 dfui_field_option_add(fi, lua_tostring(L, -1));
88 set_dfui_properties_from_lua_table(lua_State *L, int table_idx,
89 int dfui_obj_type, void *dfui_obj)
91 const char *key, *value;
94 * Traverse the table, looking for key->value pairs that we can use
95 * to modify the field.
96 * For each entry, if it is standard (id, name, short_desc, long_desc)
97 * ignore it; if it is anything else, assume it is a property.
100 while (lua_next(L, table_idx) != 0) {
101 if (lua_isstring(L, -2) && lua_isstring(L, -1)) {
102 key = lua_tostring(L, -2);
103 value = lua_tostring(L, -1);
105 if (strcmp(key, "id") == 0 ||
106 strcmp(key, "name") == 0 ||
107 strcmp(key, "short_desc") == 0 ||
108 strcmp(key, "long_desc") == 0) {
110 * Skip it, we've already done it.
112 } else if (strcmp(key, "multiple") == 0 &&
113 dfui_obj_type == DFUI_OBJ_FORM) {
114 dfui_form_set_multiple(
115 (struct dfui_form *)dfui_obj,
116 strcmp(value, "true") == 0
118 } else if (strcmp(key, "extensible") == 0 &&
119 dfui_obj_type == DFUI_OBJ_FORM) {
120 dfui_form_set_extensible(
121 (struct dfui_form *)dfui_obj,
122 strcmp(value, "true") == 0
128 switch (dfui_obj_type) {
130 dfui_form_property_set(
131 (struct dfui_form *)dfui_obj,
135 dfui_field_property_set(
136 (struct dfui_field *)dfui_obj,
139 case DFUI_OBJ_ACTION:
140 dfui_action_property_set(
141 (struct dfui_action *)dfui_obj,
146 } else if (lua_isstring(L, -2) && lua_istable(L, -1)) {
147 key = lua_tostring(L, -2);
148 if (strcmp(key, "options") == 0 &&
149 dfui_obj_type == DFUI_OBJ_FIELD) {
150 dfui_field_options_from_lua_table(L,
151 (struct dfui_field *)dfui_obj
156 * Either the key or the value is not a string,
162 * Remove the value, but leave the key for the next iteration.
168 /*** TRANSLATORS ***/
171 * Pop a Lua table representing a DFUI action from the Lua stack,
172 * create a new DFUI action from it, and return it.
174 static struct dfui_action *
175 dfui_action_from_lua_table(lua_State *L, int table_idx)
177 struct dfui_action *a;
178 const char *id, *name, *short_desc, *long_desc;
181 * Get the basic properties of the action.
183 id = lua_access_table_string(L, table_idx, "id");
184 name = lua_access_table_string(L, table_idx, "name");
185 short_desc = lua_access_table_string(L, table_idx, "short_desc");
186 long_desc = lua_access_table_string(L, table_idx, "long_desc");
189 * Create the initial action.
191 a = dfui_action_new(id,
192 dfui_info_new(name, short_desc, long_desc));
194 set_dfui_properties_from_lua_table(L, table_idx, DFUI_OBJ_ACTION, a);
201 * Pop a Lua table representing a DFUI field from the Lua stack,
202 * create a new DFUI field from it, and return it.
204 static struct dfui_field *
205 dfui_field_from_lua_table(lua_State *L, int table_idx)
207 struct dfui_field *fi;
208 const char *id, *name, *short_desc, *long_desc;
211 * Get the basic properties of the field.
213 id = lua_access_table_string(L, table_idx, "id");
214 name = lua_access_table_string(L, table_idx, "name");
215 short_desc = lua_access_table_string(L, table_idx, "short_desc");
216 long_desc = lua_access_table_string(L, table_idx, "long_desc");
219 * Create the initial field.
221 fi = dfui_field_new(id,
222 dfui_info_new(name, short_desc, long_desc));
224 set_dfui_properties_from_lua_table(L, table_idx, DFUI_OBJ_FIELD, fi);
231 * Pop a Lua table representing a DFUI dataset from the Lua stack,
232 * create a new DFUI dataset from it, and return it.
234 static struct dfui_dataset *
235 dfui_dataset_from_lua_table(lua_State *L, int table_idx)
237 struct dfui_dataset *ds;
240 * Create the initial dataset.
242 ds = dfui_dataset_new();
245 * Traverse the table, looking for key->value pairs that we can use.
248 while (lua_next(L, table_idx) != 0) {
249 if (lua_isstring(L, -2) && lua_isstring(L, -1)) {
250 dfui_dataset_celldata_add(ds,
251 lua_tostring(L, -2), lua_tostring(L, -1)
254 /* Bogus, just skip it */
258 * Remove the value, but leave the key for the next iteration.
271 * Pop a Lua table representing a DFUI form from the Lua stack,
272 * create a new DFUI form from it, and return it.
274 static struct dfui_form *
275 dfui_form_from_lua_table(lua_State *L, int table_idx)
278 struct dfui_action *a;
279 struct dfui_field *fi;
280 struct dfui_dataset *ds;
281 const char *id, *name, *short_desc, *long_desc;
282 int list_idx, subtable_idx, counter, done;
285 * Get the basic properties of the form.
287 id = lua_access_table_string(L, table_idx, "id");
288 name = lua_access_table_string(L, table_idx, "name");
289 short_desc = lua_access_table_string(L, table_idx, "short_desc");
290 long_desc = lua_access_table_string(L, table_idx, "long_desc");
293 * Create the initial form.
295 f = dfui_form_new(id, dfui_info_new(name, short_desc, long_desc));
297 set_dfui_properties_from_lua_table(L, table_idx, DFUI_OBJ_FORM, f);
300 * Get the list of actions attached to the form.
302 lua_pushliteral(L, "actions");
303 lua_gettable(L, table_idx);
304 list_idx = lua_gettop(L);
305 if (lua_istable(L, list_idx)) {
307 * Loop through all entries in this table, creating
308 * and attaching a new action for each one.
313 lua_pushnumber(L, counter++);
314 lua_gettable(L, list_idx);
315 subtable_idx = lua_gettop(L);
316 if (lua_istable(L, subtable_idx)) {
317 a = dfui_action_from_lua_table(L, subtable_idx);
318 dfui_form_action_attach(f, a);
329 * Get the list of fields attached to the form.
331 lua_pushliteral(L, "fields");
332 lua_gettable(L, table_idx);
333 list_idx = lua_gettop(L);
334 if (lua_istable(L, list_idx)) {
336 * Loop through all entries in this table, creating
337 * and attaching a new field for each one.
342 lua_pushnumber(L, counter++);
343 lua_gettable(L, list_idx);
344 subtable_idx = lua_gettop(L);
345 if (lua_istable(L, subtable_idx)) {
346 fi = dfui_field_from_lua_table(L, subtable_idx);
347 dfui_form_field_attach(f, fi);
358 * Get the list of datasets attached to the form.
360 lua_pushliteral(L, "datasets");
361 lua_gettable(L, table_idx);
362 list_idx = lua_gettop(L);
363 if (lua_istable(L, list_idx)) {
365 * Loop through all entries in this table, creating
366 * and attaching a new dataset for each one.
371 lua_pushnumber(L, counter++);
372 lua_gettable(L, list_idx);
373 subtable_idx = lua_gettop(L);
374 if (lua_istable(L, subtable_idx)) {
375 ds = dfui_dataset_from_lua_table(L, subtable_idx);
376 dfui_form_dataset_add(f, ds);
387 * Finally, delete the table representing the form by
388 * popping it from the top of the stack.
396 * Push a new Lua table representing the given DFUI response
397 * onto the Lua stack.
400 lua_table_from_dfui_response(lua_State *L, struct dfui_response *r)
402 int table_idx, list_idx, subtable_idx;
403 struct dfui_dataset *ds;
404 struct dfui_celldata *cd;
407 const char *f_id, *a_id;
410 table_idx = lua_gettop(L);
413 * Add response id's to the table.
415 f_id = dfui_response_get_form_id(r);
416 a_id = dfui_response_get_action_id(r);
418 lua_pushliteral(L, "form_id");
419 lua_pushlstring(L, f_id, strlen(f_id));
420 lua_settable(L, table_idx);
422 lua_pushliteral(L, "action_id");
423 lua_pushlstring(L, a_id, strlen(a_id));
424 lua_settable(L, table_idx);
427 * Create 'datasets' lists to the table.
429 lua_pushliteral(L, "datasets");
431 list_idx = lua_gettop(L);
434 * Add response datasets to the 'datasets' list.
436 for (ds = dfui_response_dataset_get_first(r); ds != NULL;
437 ds = dfui_dataset_get_next(ds)) {
438 lua_pushnumber(L, counter++);
440 subtable_idx = lua_gettop(L);
442 * Populate this subtable with the celldatas...
444 for (cd = dfui_dataset_celldata_get_first(ds); cd != NULL;
445 cd = dfui_celldata_get_next(cd)) {
446 f_id = dfui_celldata_get_field_id(cd);
447 value = dfui_celldata_get_value(cd);
448 lua_pushlstring(L, f_id, strlen(f_id));
449 lua_pushlstring(L, value, strlen(value));
450 lua_settable(L, subtable_idx);
453 * Add this subtable to the list
455 lua_settable(L, list_idx);
459 * Add the 'datasets' list to the table.
461 lua_settable(L, table_idx);
466 /*** CONSTRUCTOR & DESTRUCTOR ***/
469 lua_dfui_connection_new(lua_State *L)
471 const char *transport_string, *rendezvous;
473 struct dfui_connection *c;
475 transport_string = luaL_checkstring(L, 1);
476 rendezvous = luaL_checkstring(L, 2);
477 if (! (transport = get_transport(transport_string)) > 0) {
481 c = dfui_connection_new(transport, rendezvous);
482 lua_push_dfui_connection(L, c);
487 lua_dfui_connection_destroy(lua_State *L)
489 struct dfui_connection *c;
491 c = (struct dfui_connection *)lua_unboxpointer(L, 1);
494 dfui_connection_free(c);
499 /*** BOUND METHODS ***/
502 lua_dfui_be_start(lua_State *L)
504 struct dfui_connection *c;
507 c = lua_check_dfui_connection(L, 1);
508 result = dfui_be_start(c);
509 lua_pushnumber(L, result);
515 lua_dfui_be_stop(lua_State *L)
517 struct dfui_connection *c;
520 c = lua_check_dfui_connection(L, 1);
521 result = dfui_be_stop(c);
522 lua_pushnumber(L, result);
528 lua_dfui_be_present(lua_State *L)
530 struct dfui_connection *c;
532 struct dfui_response *r;
533 int response_table_idx, actions_list_idx, action_table_idx;
534 const char *a_a_id, *r_a_id;
536 c = lua_check_dfui_connection(L, 1);
537 luaL_checktype(L, 2, LUA_TTABLE);
539 f = dfui_form_from_lua_table(L, 2);
541 if (dfui_be_present(c, f, &r)) {
542 response_table_idx = lua_table_from_dfui_response(L, r);
544 r_a_id = dfui_response_get_action_id(r);
547 * Handle the 'effect' key which may be given in
548 * any action table within a form table. When it
549 * is given, it should be a function which the
550 * user wishes to be executed automatically when
551 * the response is caused by that action. This lets
552 * the user write simpler Lua code (c:present(f) can
553 * execute things directly, instead of returning an
554 * id code which the user must look up in a table etc.)
557 * First, look for an 'actions' list in the form table.
559 lua_pushliteral(L, "actions");
561 actions_list_idx = lua_gettop(L);
562 if (lua_istable(L, actions_list_idx)) {
567 * Look in the 'actions' list for
571 lua_rawgeti(L, actions_list_idx, i);
572 action_table_idx = lua_gettop(L);
573 if (lua_istable(L, action_table_idx)) {
575 * See if this action's 'id'
576 * is the response's action_id
577 * (which we saved above.)
579 a_a_id = lua_access_table_string(L,
580 action_table_idx, "id");
581 if (strcmp(r_a_id, a_a_id) == 0) {
583 * It is. So, see if action
584 * table has an 'effect' key.
586 lua_pushliteral(L, "result");
587 lua_pushliteral(L, "effect");
588 lua_gettable(L, action_table_idx);
589 if (lua_isfunction(L, lua_gettop(L))) {
591 * It is, and it's a function.
595 lua_rawset(L, response_table_idx);
604 lua_pop(L, 1); /* remove the action table */
608 lua_pop(L, 1); /* remove the 'actions' list */
613 dfui_response_free(r);
618 /**** Binding Tables ****/
620 const luaL_reg dfui_connection_methods[] = {
621 {"new", lua_dfui_connection_new },
622 {"start", lua_dfui_be_start },
623 {"stop", lua_dfui_be_stop },
624 {"present", lua_dfui_be_present },
628 const luaL_reg dfui_connection_meta_methods[] = {
629 {"__gc", lua_dfui_connection_destroy },
634 /*** REGISTRATION ***/
637 lua_dfui_register(lua_State *L)
639 luaL_openlib(L, "DFUIConnection",
640 dfui_connection_methods, 0); /* fill methods table */
641 luaL_openlib(L, "DFUIConnectionMeta",
642 dfui_connection_meta_methods, 0); /* fill metatable */
645 lua_set_instance_handler(L,
646 "DFUIConnection", "DFUIConnectionMeta");