File lua_bindings.patch of Package genders

diff --git a/config/ac_lua_extensions.m4 b/config/ac_lua_extensions.m4
new file mode 100644
index 0000000..9421588
--- /dev/null
+++ b/config/ac_lua_extensions.m4
@@ -0,0 +1,21 @@
+
+AC_DEFUN([AC_LUA_EXTENSIONS],
+[
+  AC_MSG_CHECKING(for --with-lua-extensions)
+  AC_ARG_WITH(lua-extensions,
+     AC_HELP_STRING([--with-lua-extensions=], 
+                    [enable or disable lua extensions build]),
+     [ case "$withval" in
+     yes)
+         ac_with_lua_extensions=yes
+         ;;
+     no)
+         ac_with_lua_extensions=no
+         ;;
+     *)
+         ac_with_lua_extensions=yes
+         ;;
+     esac ]
+  )
+  AC_MSG_RESULT(${ac_with_lua_extensions=no})
+])
diff --git a/config/x_ac_lua.m4 b/config/x_ac_lua.m4
new file mode 100644
index 0000000..2f5f587
--- /dev/null
+++ b/config/x_ac_lua.m4
@@ -0,0 +1,60 @@
+##*****************************************************************************
+#  AUTHOR:
+#    Mark Grondona <mgrondona@llnl.gov>
+#
+#  SYNOPSIS:
+#    AC_LUA
+#
+#  DESCRIPTION:
+#    Check for presence of lua libs and headers
+##*****************************************************************************
+
+
+AC_DEFUN([X_AC_LUA],
+[
+	x_ac_lua_pkg_name="lua"
+	#check for 5.3 then 5.2 then 5.1
+	PKG_CHECK_EXISTS([lua5.3], [x_ac_lua_pkg_name=lua5.3],
+		[PKG_CHECK_EXISTS([lua-5.3], [x_ac_lua_pkg_name=lua-5.3],
+		[PKG_CHECK_EXISTS([lua5.2], [x_ac_lua_pkg_name=lua5.2],
+		[PKG_CHECK_EXISTS([lua-5.2], [x_ac_lua_pkg_name=lua-5.2],
+		[PKG_CHECK_EXISTS([lua5.1], [x_ac_lua_pkg_name=lua5.1],
+		[PKG_CHECK_EXISTS([lua-5.1], [x_ac_lua_pkg_name=lua-5.1],
+	        [x_ac_lua_pkg_name="lua >= 5.1"])])])])])])
+	PKG_CHECK_MODULES([lua], ${x_ac_lua_pkg_name},
+                [x_ac_have_lua="yes"],
+                [x_ac_have_lua="no"])
+
+	if test "x$x_ac_have_lua" = "xyes"; then
+	  saved_CFLAGS="$CFLAGS"
+	  saved_LIBS="$LIBS"
+	  lua_CFLAGS="$lua_CFLAGS"
+	  CFLAGS="$CFLAGS $lua_CFLAGS"
+	  LIBS="$LIBS $lua_LIBS"
+	  AC_MSG_CHECKING([for whether we can link to liblua])
+	  AC_TRY_LINK(
+		[#include <lua.h>
+                 #include <lauxlib.h>
+		 #include <lualib.h>
+		],
+		[lua_State *L = luaL_newstate (); luaL_openlibs(L);
+		],
+		[], [x_ac_have_lua="no"])
+
+	  AC_MSG_RESULT([$x_ac_have_lua $x_ac_lua_pkg_name])
+	  if test "x$x_ac_have_lua" = "xno"; then
+	    AC_MSG_WARN([unable to link against lua libraries])
+	  else
+	    AC_DEFINE(HAVE_LUA, 1, [Define to 1 if we have the Lua library])
+	    # We can not define something here to determine version for systems
+	    # that use just liblua we will not know what version we are using.
+	    # Use LUA_VERSION_NUM as in lua.h it will always be right.
+	  fi
+	  CFLAGS="$saved_CFLAGS"
+	  LIBS="$saved_LIBS"
+	else
+	  AC_MSG_WARN([unable to locate lua package])
+	fi
+
+	AM_CONDITIONAL(HAVE_LUA, test "x$x_ac_have_lua" = "xyes")
+])
diff --git a/configure.ac b/configure.ac
index 07496ea..58c6684 100644
--- a/configure.ac
+++ b/configure.ac
@@ -68,6 +68,7 @@ PYTHONGENDERS_MINOR=2
 PYTHONGENDERS_VERSION=$PYTHONGENDERS_MAJOR.$PYTHONGENDERS_MINOR
 AC_SUBST([PYTHONGENDERS_VERSION])
 
+
 ##
 # Checks for programs.
 ##
@@ -86,6 +87,7 @@ AC_PATH_PROG([JAVAH], [javah])
 AC_PATH_PROG([JAVA], [java])
 AC_PATH_PROG([JAR], [jar])
 AC_PATH_PROG([JAVADOC], [javadoc])
+AC_PATH_PROG([JAVADOC], [lua])
 AC_DEBUG
 
 ##
@@ -206,6 +208,24 @@ AM_CONDITIONAL(WITH_CPLUSPLUS_EXTENSIONS, [test "$ac_with_cplusplus_extensions"
 AC_JAVA_EXTENSIONS
 AM_CONDITIONAL(WITH_JAVA_EXTENSIONS, [test "$ac_with_java_extensions" = "yes"])
 
+#
+# Check for lua, which means create commanline conditional
+#
+AC_LUA_EXTENSIONS
+AM_CONDITIONAL(WITH_LUA_EXTENSIONS, [test "$ac_with_lua_extensions" = "yes"])
+#
+# expand lua
+#
+if test "x$ac_with_lua_extensions" = "xyes" ; then
+# beware, the ACTION-IF-NOT-FOUND is not working
+AX_PROG_LUA([5.3],,,:)
+# The test of headers fail, if LUA_VERSION is empty
+if test LUA_VERSION ; then
+AX_LUA_HEADERS
+AX_LUA_LIBS
+fi
+fi
+
 ##
 # Checks for typedefs, structures, and compiler characteristics.
 ##
@@ -246,6 +266,7 @@ AC_CONFIG_FILES( \
   src/extensions/perl/Genders/Makefile \
   src/extensions/perl/Genders/Genders.pm \
   src/extensions/python/Makefile \
+  src/extensions/lua/Makefile \
   src/extensions/python/genderssetup.py \
   src/extensions/java/Makefile \
   src/testsuite/Makefile \
diff --git a/genders.spec b/genders.spec
new file mode 100644
index 0000000..cd09930
--- /dev/null
+++ b/genders.spec
@@ -0,0 +1,110 @@
+Name:    genders 
+Version: 1.26
+Release: 1
+Summary: Static cluster configuration database
+URL: https://github.com/chaos/genders
+Group: System Environment/Base
+License: GPL
+Source: %{name}-%{version}.tar.gz
+Requires: perl
+BuildRequires: bison flex
+BuildRequires: perl(ExtUtils::MakeMaker)
+BuildRequires: python
+BuildRequires: python-devel
+BuildRequires: libtool
+BuildRoot: %{_tmppath}/%{name}-%{version}
+
+%description
+Genders is a static cluster configuration database used for cluster
+configuration management.  It is used by a variety of tools and
+scripts for management of large clusters.  The genders database is
+typically replicated on every node of the cluster. It describes the
+layout and configuration of the cluster so that tools and scripts can
+sense the variations of cluster nodes. By abstracting this information
+into a plain text file, it becomes possible to change the
+configuration of a cluster by modifying only one file.
+
+%package compat
+Summary: Compatibility library 
+Group: System Environment/Base
+%description compat
+genders API that is compatible with earlier releases of genders
+
+%{!?_with_perl_extensions: %{!?_without_perl_extensions: %define _with_perl_extensions --with-perl-extensions}}
+%{!?_with_python_extensions: %{!?_without_python_extensions: %define _with_python_extensions --with-python-extensions}}
+%{!?_with_cplusplus_extensions: %{!?_without_cplusplus_extensions: %define _with_cplusplus_extensions --with-cplusplus-extensions}}
+%{!?_with_java_extensions: %{!?_without_java_extensions: %define _without_java_extensions --without-java-extensions}}
+%{!?_with_lua_extensions: %{!?_without_lua_extensions: %define _without_lua_extensions --without-lua-extensions}}
+
+# choose vendor arch by default
+%{!?_with_perl_site_arch: %{!?_with_perl_vendor_arch: %define _with_perl_vendor_arch --with-perl-vendor-arch}}
+
+%prep
+%setup  -q -n %{name}-%{version}
+
+%build
+%configure --program-prefix=%{?_program_prefix:%{_program_prefix}} \
+    --with-extension-destdir="$RPM_BUILD_ROOT" \
+    %{?_with_perl_extensions} \
+    %{?_without_perl_extensions} \
+    %{?_with_perl_site_arch} \
+    %{?_without_perl_site_arch} \
+    %{?_with_perl_vendor_arch} \
+    %{?_without_perl_vendor_arch} \
+    %{?_with_python_extensions} \
+    %{?_without_python_extensions} \
+    %{?_with_cplusplus_extensions} \
+    %{?_without_cplusplus_extensions} \
+    %{?_with_java_extensions} \
+    %{?_without_java_extensions}\
+    %{?_with_lua_extensions} \
+    %{?_without_lua_extension}
+make 
+
+%install
+rm -rf $RPM_BUILD_ROOT
+DESTDIR="$RPM_BUILD_ROOT" make install 
+
+%files
+%defattr(-,root,root)
+%doc README NEWS ChangeLog DISCLAIMER DISCLAIMER.UC COPYING TUTORIAL genders.sample
+%if %{?_with_java_extensions:1}%{!?_with_java_extensions:0}
+%dir %{_datadir}/doc/%{name}-%{version}-javadoc/
+%doc %{_datadir}/doc/%{name}-%{version}-javadoc/*
+%endif
+# It doesn't matter if the user chooses a 32bit or 64bit target.  The
+# packaging must work off whatever Perl is installed.  
+%if %{?_with_perl_site_arch:1}%{!?_with_perl_site_arch:0}
+%define _perldir %(perl -e 'use Config; $T=$Config{installsitearch}; $P=$Config{siteprefix}; $T=~/$P\\/(.*)/; print "%{_prefix}/$1\\n"')
+%endif
+%if %{?_with_perl_vendor_arch:1}%{!?_with_perl_vendor_arch:0}
+%define _perldir %(perl -e 'use Config; $T=$Config{installvendorarch}; $P=$Config{vendorprefix}; $T=~/$P\\/(.*)/; print "%{_prefix}/$1\\n"')
+%endif
+%{_mandir}/man1/*
+%{_mandir}/man3/genders*
+%{_mandir}/man3/libgenders* 
+%{_includedir}/*
+%{_bindir}/*
+%{_libdir}/libgenders.*
+%if %{?_with_perl_extensions:1}%{!?_with_perl_extensions:0}
+%{_mandir}/man3/Libgenders*
+%{_mandir}/man3/Genders*
+%{_perldir}/*
+%endif
+%if %{?_with_python_extensions:1}%{!?_with_python_extensions:0}
+%{_exec_prefix}/lib*/python*
+%endif
+%if %{?_with_cplusplus_extensions:1}%{!?_with_cplusplus_extensions:0}
+%{_libdir}/libgendersplusplus.*
+%endif
+%if %{?_with_java_extensions:1}%{!?_with_java_extensions:0}
+%{_javadir}/*
+%{_libdir}/libGendersjni.*
+%endif
+
+%files compat
+%defattr(-,root,root)
+%{_mandir}/man3/gendlib*
+%{_prefix}/lib/genders/*
+
+
diff --git a/src/extensions/Makefile.am b/src/extensions/Makefile.am
index ec963c4..e85f6c2 100644
--- a/src/extensions/Makefile.am
+++ b/src/extensions/Makefile.am
@@ -4,4 +4,4 @@
 ## Process this file with automake to produce Makefile.in.
 ##*****************************************************************************
 
-SUBDIRS = cplusplus java perl python
+SUBDIRS = cplusplus java perl python lua
diff --git a/src/extensions/lua/GendersTest/GendersTest.lua b/src/extensions/lua/GendersTest/GendersTest.lua
new file mode 100755
index 0000000..7e28473
--- /dev/null
+++ b/src/extensions/lua/GendersTest/GendersTest.lua
@@ -0,0 +1,134 @@
+#!/usr/bin/lua
+
+db_file = "testgenders"
+
+genders_lib = require("genders")
+genders_handle = nil
+
+-- wrapper to for using pcall
+function wrapper_new() 
+  genders_handle = genders_lib.new(db_file)
+end
+
+str_err = ""
+str_out = ""
+
+no_load = nil
+error_status = 0
+
+getter_funcs = {"getnumattrs","getnumnodes","getnodes"}
+list_nodes = {"foobar","hype355","null"}
+list_attr = {"foobar","mgmt"}
+-- attr <-> value mismatch as this is dict!
+list_attrval = {["foobaar"] = "cfhost", ["hypei"] = "cfhost"}
+list_query = { "mgmt","mgmt||login","mhmt&&login","~mgmt"}
+
+local open_lib, genders_handle = pcall(genders_lib.new,db_file,genders_lib)
+if open_lib then
+  print("Loaded database \""..db_file.."\"")
+  for _, func_name in ipairs(getter_funcs) do 
+    local str = "return function(handle) return pcall(handle."..func_name..",handle) end"
+    local wrap_func = assert(load(str))
+    local func = wrap_func()
+    local ok,ret_val = func(genders_handle) 
+    if ok then 
+      if type(ret_val) ~= "table" then 
+        print(func_name.." :: "..ret_val)
+      else
+        local tmp_str = func_name.." :: "
+        for _,val in ipairs(ret_val) do
+          tmp_str = tmp_str..val..", "
+        end
+        print(tmp_str)
+      end
+    else
+      error_status = 1
+      str_err = "Could not call "..func_name..": "..ret_val
+    end
+  end
+  local ok, ret_val = pcall(genders_handle.getnodes,genders_handle,"mgmt")
+  if ok then 
+      local tmp_str = "getnodes(\"mgmt\") :: " for _,val in ipairs(ret_val) do tmp_str = tmp_str..val..", " end
+      print(tmp_str)
+  else
+    error_status = 1
+    str_err = "Could not call: getnodes(\"mgmt\")"..ret_val
+  end
+  local ok, ret_val = pcall(genders_handle.getnodes,genders_handle,"foobarlalala")
+  if ok then 
+      local tmp_str = "getnodes(\"foobarlalala\") :: " for _,val in ipairs(ret_val) do tmp_str = tmp_str..val..", " end
+      print(tmp_str)
+  else
+    error_status = 1
+    str_err = "Could not call: getnodes(\"foobarlalala\")"..ret_val
+  end
+  local ok, ret_val = pcall(genders_handle.getnodes,genders_handle,"cfhost","foobar")
+  if ok then 
+      local tmp_str = "getnodes(\"cfhost\",\"foobar\") :: " for _,val in ipairs(ret_val) do tmp_str = tmp_str..val..", " end
+      print(tmp_str)
+  else
+    error_status = 1
+    str_err = "Could not call: getnodes(\"cfhost\",\"foobar\")"..ret_val
+  end
+  local ok, ret_val = pcall(genders_handle.getnodes,genders_handle,"cfhost","hypei")
+  if ok then 
+      local tmp_str = "getnodes(\"cfhost\",\"hypei\") :: " for _,val in ipairs(ret_val) do tmp_str = tmp_str..val..", " end
+      print(tmp_str)
+  else
+    error_status = 1
+    str_err = "Could not call: getnodes(\"cfhost\",\"hypei\")"..ret_val
+  end
+  local ok, ret_val = pcall(genders_handle.getattr,genders_handle,"hype355")
+  if ok then 
+      local tmp_str = "getattr(\"hype355\") :: " for key,value in pairs(ret_val) do tmp_str = tmp_str..key if value == "" then tmp_str = tmp_str..", " else tmp_str = tmp_str.."="..value.."," end  end
+      print(tmp_str)
+  else
+    error_status = 1
+    str_err = "Could not call: getattr(\"hype355\")"..ret_val
+  end
+  for _,node in ipairs(list_nodes) do
+    local ok, ret_val = pcall(genders_handle.isnode,genders_handle,node)
+    if ok then
+      if ret_val then print("isnode("..node..") = true") else print("isnode("..node..") = false") end
+    else
+      error_status = 1
+      str_err = "Could not call: isnode("..node..") "..ret_val
+    end
+  end
+  for _,attr in ipairs(list_attr) do
+    local ok, ret_val = pcall(genders_handle.isattr,genders_handle,attr)
+    if ok then
+      if ret_val then print("isattr("..attr..") = true") else print("isattr("..attr..") = false") end
+    else
+      error_status = 1
+      str_err = "Could not call: isattr("..attr..") "..ret_val
+    end
+  end
+  for value,attr in pairs(list_attrval) do
+    local ok, ret_val = pcall(genders_handle.isattrval,genders_handle,attr,value)
+    if ok then
+      if ret_val then print("isattrval("..attr..","..value..") = true") else print("isattrval("..attr..","..value..") = false") end
+    else
+      error_status = 1
+      str_err = "Could not call: isattr("..attr..") "..ret_val
+    end
+  end
+  for _,qry in ipairs(list_query) do
+    local ok, ret_val = pcall(genders_handle.query,genders_handle,qry)
+    if ok then
+      local tmp_str = "query("..qry..") :: " for _,val in pairs(ret_val) do tmp_str = tmp_str..val..", " end
+      print(tmp_str)
+    else
+      error_status = 1
+      str_err = "Could not call: query("..qry..")"..ret_val
+    end
+  end
+else
+  str_err = "Failure in loading database \""..db_file.."\""
+  error_status = 1
+end
+if error_status == 0 then
+  print("No errors")
+else
+  print("Collected errors are: "..str_err)
+end
diff --git a/src/extensions/lua/GendersTest/testgenders b/src/extensions/lua/GendersTest/testgenders
new file mode 100644
index 0000000..4d17db1
--- /dev/null
+++ b/src/extensions/lua/GendersTest/testgenders
@@ -0,0 +1,21 @@
+##########################################################################
+# $URL: file:///var/svn/cfengine/clusters/hype/genders $
+# $Author: tdhooge $
+# $Date: 2012-06-29 17:05:40 -0700 (Fri, 29 Jun 2012) $
+# $Rev: 3594 $
+###########################################################################
+
+# Mgmt
+hype[137,355]		pdsh_all_skip,mgmt,dhcpd,sshd,tftp,named,nfs,ntpserv
+hype[137,355]		networker,crond,rsshd
+
+hype355			primgmt,opensmd,powerman,conman,sendmail,sysloghost,moab
+hype355			passwdhost=hype:hypei,sshkeyhost,cfhost=hypei,mysqld
+hype355			skummee,perfmgr,httpd,logarch
+hype137			httpd
+hype137			altmgmt
+
+# Login
+hype[136,356]		login,cups,iptables,ksshd,ksshd_client,bluenet,atd
+hype136			ipforw,skummee,mysqld
+hype[136,356]		crond,rsshd,psacct
diff --git a/src/extensions/lua/Makefile.am b/src/extensions/lua/Makefile.am
new file mode 100644
index 0000000..4512cee
--- /dev/null
+++ b/src/extensions/lua/Makefile.am
@@ -0,0 +1,21 @@
+# DESTDIR is usually set during make install time, not configure or
+# make time, so we work around it with the --with-extension-destdir
+# autoconf option.
+
+
+if WITH_LUA_EXTENSIONS
+
+luaexec_LTLIBRARIES = genders.la
+
+genders_la_SOURCES = genderslua.c
+
+genders_la_CFLAGS =  @LUA_INCLUDE@ -I../../libgenders/
+
+genders_la_LDFLAGS = -module -avoid-version
+
+genders_la_LIBADD = ../../libgenders/libgenders.la $(OTHER_FLAGS) @LUA_LIB@
+
+
+endif
+
+EXTRA_DIST = genderslua.c
diff --git a/src/extensions/lua/genderslua.c b/src/extensions/lua/genderslua.c
new file mode 100644
index 0000000..f2364af
--- /dev/null
+++ b/src/extensions/lua/genderslua.c
@@ -0,0 +1,322 @@
+/*****************************************************************************
+ *  Copyright (C) 2018 SUSE LLC
+ *  Written by Christian Goll <cgoll@suse.com>
+ *
+ *  This file is part of Genders, a cluster configuration database.
+ *  For details, see <http://www.llnl.gov/linux/genders/>.
+ *
+ *  Genders is free software; you can redistribute it and/or modify it under
+ *  the terms of the GNU General Public License as published by the Free
+ *  Software Foundation; either version 2 of the License, or (at your option)
+ *  any later version.
+ *
+ *  Genders is distributed in the hope that it will be useful, but WITHOUT ANY
+ *  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ *  FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
+ *  details.
+ *
+ *  You should have received a copy of the GNU General Public License along
+ *  with Genders.  If not, see <http://www.gnu.org/licenses/>.
+\*****************************************************************************/
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif /* HAVE_CONFIG_H */
+#include <stdlib.h>
+#include <string.h>
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+#include <genders.h>
+
+typedef struct {
+	/* genders_t itself is a pointer */
+	genders_t handle;
+	char      *db_name;
+ } lgenders_userdata_t;
+
+static int lgenders_new(lua_State *L) {
+	lgenders_userdata_t *dbh;
+	const char *db_name, *g_error;
+	/* check for argument vailidy */
+	db_name = luaL_checkstring(L,1); 
+	if (db_name == NULL)
+		luaL_error(L,"database name could not be empty");
+	/* Create the user data pushing it onto the stack. We also pre-initialize
+	 * the member of the userdata in case initialization fails in some way. If
+	 * that happens we want the userdata to be in a consistent state for __gc. 
+	 */
+	dbh = (lgenders_userdata_t *)lua_newuserdata(L, sizeof(*dbh));
+	dbh->handle = NULL;
+	dbh->db_name = NULL; 
+	/* Add the metatable to the stack. */
+	luaL_getmetatable(L, "LGenders");
+	/* Set the metatable on the userdata. */
+	lua_setmetatable(L, -2);
+	/* Create the handle */
+	dbh->handle =  genders_handle_create(); 
+	dbh->db_name = strdup(db_name);
+	if(genders_load_data(dbh->handle,dbh->db_name) != 0) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	return 1;
+}
+static int lgenders_reload(lua_State *L) {
+	lgenders_userdata_t *dbh;
+	const char *db_name, *g_error;
+	dbh = (lgenders_userdata_t *)luaL_checkudata(L, 1, "LGenders");
+	/* check for argument vailidy */
+	db_name = luaL_checkstring(L,2); 
+	if (db_name == NULL)
+		db_name = strdup(dbh->db_name);
+	if (dbh->handle != NULL)
+		genders_handle_destroy(dbh->handle);
+	dbh->db_name = NULL; 
+	/* Create the handle */
+	dbh->handle =  genders_handle_create(); 
+	dbh->db_name = strdup(db_name);
+	if(genders_load_data(dbh->handle,dbh->db_name) != 0) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	return 0;
+}
+static int lgenders_destroy(lua_State *L) {
+	lgenders_userdata_t *dbh;
+	dbh = (lgenders_userdata_t *)luaL_checkudata(L, 1, "LGenders");
+	/* pass return value to lus */
+	if (dbh->handle != NULL)
+		genders_handle_destroy(dbh->handle);
+
+	if (dbh->db_name != NULL)
+		free(dbh->db_name);
+	dbh->db_name = NULL;
+	return 0;
+}
+
+static int lgenders_getnumnodes(lua_State *L) {
+	lgenders_userdata_t *dbh;
+	dbh = (lgenders_userdata_t *)luaL_checkudata(L, 1, "LGenders");
+	lua_pushinteger(L,genders_getnumnodes(dbh->handle));
+	return 1;
+}
+
+static int lgenders_getnumattrs(lua_State *L) {
+	lgenders_userdata_t *dbh;
+	dbh = (lgenders_userdata_t *)luaL_checkudata(L, 1, "LGenders");
+	lua_pushinteger(L,genders_getnumattrs(dbh->handle));
+	return 1;
+}
+
+static int lgenders_getnodes(lua_State *L) {
+	char** nodelist;
+	const char *g_error, *attr, *val;
+	int size, nr_nodes, i, nr_args = 0;
+	lgenders_userdata_t *dbh;
+	dbh = (lgenders_userdata_t *)luaL_checkudata(L, 1, "LGenders");
+	/* create space for the genders stuff */
+	size = genders_nodelist_create(dbh->handle,&nodelist);
+	if(size == -1) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	attr = NULL; val = NULL;
+	/* check for attr and val */
+	nr_args = lua_gettop(L);
+	if(nr_args > 1)
+		attr = luaL_checkstring(L,2); 
+	if(nr_args > 2)
+		val = luaL_checkstring(L,3); 
+	if(nr_args > 3)
+		luaL_error(L,"getnodes accepts none,one or two arguments");
+	nr_nodes = genders_getnodes(dbh->handle,nodelist,size,attr,val);
+	lua_newtable(L);
+	for(i = 0; i < nr_nodes; i++) {
+		lua_pushstring(L,nodelist[i]);
+		lua_rawseti(L,-2,i+1);
+	}
+	/* destroy list of nodes */
+	if(genders_nodelist_destroy(dbh->handle,nodelist) == -1) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	return 1;
+}
+
+static int lgenders_query(lua_State *L) {
+	char** nodelist;
+	const char *g_error, *query;
+	int size, nr_nodes, i, nr_args = 0;
+	lgenders_userdata_t *dbh;
+	dbh = (lgenders_userdata_t *)luaL_checkudata(L, 1, "LGenders");
+	/* create space for the genders stuff */
+	size = genders_nodelist_create(dbh->handle,&nodelist);
+	if(size == -1) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	nr_args = lua_gettop(L);
+	if(nr_args == 2)
+		query = luaL_checkstring(L,2); 
+	else
+		luaL_error(L,"query must be called with one argument");
+	nr_nodes = genders_query(dbh->handle,nodelist,size,query);
+	lua_newtable(L);
+	for(i = 0; i < nr_nodes; i++) {
+		lua_pushstring(L,nodelist[i]);
+		lua_rawseti(L,-2,i+1);
+	}
+	/* destroy list of nodes */
+	if(genders_nodelist_destroy(dbh->handle,nodelist) == -1) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	return 1;
+}
+static int lgenders_getattr(lua_State *L) {
+	char **attr_list, **val_list;
+	const char *node, *g_error;
+	int ret_code, nr_args, size_attr, i = 0;
+	lgenders_userdata_t *dbh;
+	dbh = (lgenders_userdata_t *)luaL_checkudata(L, 1, "LGenders");
+	nr_args = lua_gettop(L);
+	if(nr_args == 2)
+		node = luaL_checkstring(L,2); 
+	else
+		luaL_error(L,"query must be called with one argument");
+	/* create space for the lists */
+	ret_code = genders_attrlist_create(dbh->handle,&attr_list);
+	if(ret_code == -1) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	ret_code = genders_vallist_create(dbh->handle,&val_list);
+	if(ret_code == -1) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	/* hopefully size (which is in ret_code) of attr_list and val_list are the same */
+	size_attr = genders_getattr(dbh->handle,attr_list,val_list,ret_code,node);
+	if(size_attr == -1) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	lua_newtable(L);
+	for(i = 0; i < size_attr; i++) {
+		lua_pushstring(L, attr_list[i]);
+		lua_pushstring(L, val_list[i]);
+		lua_settable(L, -3);
+	}
+	/* destroy list of nodes */
+	if(genders_vallist_destroy(dbh->handle,val_list) == -1) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	if(genders_attrlist_destroy(dbh->handle,attr_list) == -1) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	return 1;
+}
+
+static int lgenders_isnode(lua_State *L) {
+	const char *node, *g_error;
+	int ret_code, nr_args;
+	lgenders_userdata_t *dbh;
+	dbh = (lgenders_userdata_t *)luaL_checkudata(L, 1, "LGenders");
+	nr_args = lua_gettop(L);
+	if(nr_args == 2)
+		node = luaL_checkstring(L,2); 
+	else
+		luaL_error(L,"isnode must be called with one argument");
+	ret_code = genders_isnode(dbh->handle,node);
+	if(ret_code == -1) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	lua_pushboolean(L,ret_code);
+	return 1;
+}
+
+static int lgenders_isattr(lua_State *L) {
+	const char *attr, *g_error;
+	int ret_code, nr_args;
+	lgenders_userdata_t *dbh;
+	dbh = (lgenders_userdata_t *)luaL_checkudata(L, 1, "LGenders");
+	nr_args = lua_gettop(L);
+	if(nr_args == 2)
+		attr = luaL_checkstring(L,2); 
+	else
+		luaL_error(L,"isattr must be called with one argument");
+	ret_code = genders_isattr(dbh->handle,attr);
+	if(ret_code == -1) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	lua_pushboolean(L,ret_code);
+	return 1;
+}
+
+static int lgenders_isattrval(lua_State *L) {
+	const char *attr, *val, *g_error;
+	int ret_code, nr_args;
+	lgenders_userdata_t *dbh;
+	dbh = (lgenders_userdata_t *)luaL_checkudata(L, 1, "LGenders");
+	nr_args = lua_gettop(L);
+	if(nr_args == 3) {
+		attr = luaL_checkstring(L,2); 
+		val = luaL_checkstring(L,3); 
+	}
+	else
+		luaL_error(L,"isattrval must be called with two arguments");
+	ret_code = genders_isattrval(dbh->handle,attr,val);
+	if(ret_code == -1) {
+		g_error = strdup(genders_errormsg(dbh->handle));
+		luaL_error(L,g_error);
+	}
+	lua_pushboolean(L,ret_code);
+	return 1;
+}
+
+static const struct luaL_Reg genders_methods[] = {
+	{"getnumattrs",lgenders_getnumattrs},
+	{"getnumnodes",lgenders_getnumnodes},
+	{"getnodes",lgenders_getnodes},
+	{"getattr",lgenders_getattr},
+	{"query",lgenders_query},
+	{"isnode",lgenders_isnode},
+	{"isattr",lgenders_isattr},
+	{"isattrval",lgenders_isattrval},
+	{"reload",lgenders_reload},
+	{"__gc",lgenders_destroy},
+	{NULL,NULL},
+};
+
+static const struct luaL_Reg genders_functions[] = {
+	{ "new", lgenders_new },
+	{ NULL,  NULL}
+};
+
+
+int luaopen_genders(lua_State *L) {
+	/* Create the metatable and put it on the stack. */
+	luaL_newmetatable(L, "LGenders");
+	/* Duplicate the metatable on the stack (We know have 2). */
+	lua_pushvalue(L, -1);
+	/* Pop the first metatable off the stack and assign it to __index
+	* of the second one. We set the metatable for the table to itself.
+	* This is equivalent to the following in lua:
+	* metatable = {}
+	* metatable.__index = metatable
+	*/
+	lua_setfield(L, -2, "__index");
+
+	/* Set the methods to the metatable that should be accessed via object:func */
+	luaL_setfuncs(L, genders_methods, 0);
+
+	/* Register the object.func functions into the table that is at the top of the
+	* stack. */
+	luaL_newlib(L, genders_functions);
+
+	return 1;
+}
openSUSE Build Service is sponsored by