+LUA_CLASS_DEFINE(Pref,PREF,NOP);
+LUA_CLASS_DEFINE(Prefs,PREFS,NOP);
+LUA_CLASS_DEFINE(Proto,PROTO,NOP);
+
+static int new_pref(lua_State* L, pref_type_t type) {
+ const gchar* label = luaL_optstring(L,1,NULL);
+ const gchar* descr = luaL_optstring(L,3,"");
+
+ Pref pref = g_malloc(sizeof(eth_pref_t));
+ pref->name = NULL;
+ pref->label = label ? g_strdup(label) : NULL;
+ pref->desc = g_strdup(descr);
+ pref->type = type;
+ pref->next = NULL;
+ pref->proto = NULL;
+
+ switch(type) {
+ case PREF_BOOL: {
+ gboolean def = lua_toboolean(L,2);
+ pref->value.b = def;
+ break;
+ }
+ case PREF_UINT: {
+ guint32 def = (guint32)luaL_optnumber(L,2,0);
+ pref->value.u = def;
+ break;
+ }
+ case PREF_STRING: {
+ gchar* def = g_strdup(luaL_optstring(L,2,""));
+ pref->value.s = def;
+ break;
+ }
+ default:
+ g_assert_not_reached();
+ break;
+
+ }
+
+ pushPref(L,pref);
+ return 1;
+
+}
+
+static int Pref_bool(lua_State* L) {
+ return new_pref(L,PREF_BOOL);
+}
+
+static int Pref_uint(lua_State* L) {
+ return new_pref(L,PREF_UINT);
+}
+
+static int Pref_string(lua_State* L) {
+ return new_pref(L,PREF_STRING);
+}
+
+static int Pref_gc(lua_State* L) {
+ Pref pref = checkPref(L,1);
+
+ if (pref && ! pref->name) {
+ if (pref->label) g_free(pref->label);
+ if (pref->desc) g_free(pref->desc);
+ if (pref->type == PREF_STRING) g_free((void*)pref->value.s);
+ g_free(pref);
+ }
+
+ return 0;
+}
+
+static const luaL_reg Pref_methods[] = {
+ {"bool", Pref_bool},
+ {"uint", Pref_uint},
+ {"string", Pref_string},
+ {0,0}
+};
+
+static const luaL_reg Pref_meta[] = {
+ {"__gc", Pref_gc},
+ {0,0}
+};
+
+
+static int Pref_register(lua_State* L) {
+ luaL_openlib(L, PREF, Pref_methods, 0);
+ luaL_newmetatable(L, PREF);
+ luaL_openlib(L, 0, Pref_meta, 0);
+ lua_pushliteral(L, "__index");
+ lua_pushvalue(L, -3);
+ lua_rawset(L, -3);
+ lua_pushliteral(L, "__metatable");
+ lua_pushvalue(L, -3);
+ lua_rawset(L, -3);
+ lua_pop(L, 1);
+
+ return 1;
+};
+
+
+static int Prefs_newindex(lua_State* L) {
+ Pref prefs = checkPrefs(L,1);
+ const gchar* name = luaL_checkstring(L,2);
+ Pref pref = checkPref(L,3);
+ Pref p;
+ if (! ( name && prefs && pref) ) return 0;
+
+ if (pref->name) {
+ luaL_error(L,"this preference has already been registered to another protocol");
+ return 0;
+ }
+
+ p = prefs;
+
+ do {
+ if ( p->name && g_str_equal(p->name,name) ) {
+ luaL_error(L,"a preference named %s exists already",name);
+ return 0;
+ }
+
+ if ( ! p->next) {
+ p->next = pref;
+
+ pref->name = g_strdup(name);
+
+ if (!pref->label)
+ pref->label = g_strdup(name);
+
+ if (!prefs->proto->prefs_module) {
+ prefs->proto->prefs_module = prefs_register_protocol(prefs->proto->hfid, NULL);
+
+ }
+
+ switch(pref->type) {
+ case PREF_BOOL:
+ prefs_register_bool_preference(prefs->proto->prefs_module,
+ pref->name,
+ pref->label,
+ pref->desc,
+ &(pref->value.b));
+ break;
+ case PREF_UINT:
+ prefs_register_uint_preference(prefs->proto->prefs_module,
+ pref->name,
+ pref->label,
+ pref->desc,
+ BASE_DEC,
+ &(pref->value.u));
+ break;
+ case PREF_STRING:
+ prefs_register_string_preference(prefs->proto->prefs_module,
+ pref->name,
+ pref->label,
+ pref->desc,
+ &(pref->value.s));
+ break;
+ default:
+ g_assert_not_reached();
+ break;
+ }
+
+ pref->proto = p->proto;
+
+ return 0;
+ }
+ } while (( p = p->next ));
+
+ g_assert_not_reached();
+
+ return 0;
+}
+
+static int Prefs_index(lua_State* L) {
+ Pref prefs = checkPrefs(L,1);
+ const gchar* name = luaL_checkstring(L,2);
+
+ if (! ( name && prefs ) ) return 0;
+
+ prefs = prefs->next;
+
+ do {
+ if ( g_str_equal(prefs->name,name) ) {
+ switch (prefs->type) {
+ case PREF_BOOL: lua_pushboolean(L, prefs->value.b); break;
+ case PREF_UINT: lua_pushnumber(L,(lua_Number)prefs->value.u); break;
+ case PREF_STRING: lua_pushstring(L,prefs->value.s); break;
+ default: g_assert_not_reached(); break;
+ }
+ return 1;
+ }
+ } while (( prefs = prefs->next ));
+
+ luaL_error(L,"no such preference `%s'",name);
+ lua_pushnil(L);
+ return 1;
+}
+
+static const luaL_reg Prefs_meta[] = {
+ {"__newindex", Prefs_newindex},
+ {"__index", Prefs_index},
+ {0,0}
+};
+
+static int Prefs_register(lua_State* L) {
+ luaL_newmetatable(L, PREFS);
+ luaL_openlib(L, NULL, Prefs_meta, 0);
+
+ return 1;
+};
+