util.c
changeset 0 65cbecad22b4
child 72 d049c92d0809
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/util.c	Sun Feb 22 23:14:24 2009 +0200
@@ -0,0 +1,132 @@
+
+#include <glib.h>	// g_ascii_strcasecmp
+#include <lua.h>
+#include <lauxlib.h>
+
+#include "util.h"
+
+enum_value_t string2enum (const char *string, const string2enum_t *set)
+{
+	while (set->string) {
+		if (!g_ascii_strcasecmp (string, set->string))
+			return set->value;
+		++set;
+	}
+	return set->value;
+}
+
+const char *enum2string (enum_value_t value, const string2enum_t *set)
+{
+	while (set->string) {
+		if (value == set->value)
+			return set->string;
+		++set;
+	}
+	return NULL;
+}
+
+/// argument enum field
+/// String that will be converted to number or just plain number, that will be passed as is.
+/// Note, that if enum name is not recognized no error will be raised and default vale will be used.
+enum_value_t luaL_checkenum (lua_State *L, int index, const string2enum_t *set)
+{
+	if (lua_type (L, index) == LUA_TNUMBER)
+		return lua_tointeger (L, index);
+	else
+		return string2enum (luaL_checkstring (L, index), set);
+}
+
+/// return enum field
+/// String. If no string found, plain number will be returned.
+void luaL_pushenum (lua_State *L, enum_value_t value, const string2enum_t *set)
+{
+	const char *string = enum2string (value, set);
+	if (string != NULL)
+		lua_pushstring (L, string);
+	else
+		lua_pushinteger (L, value);
+}
+
+/// argument flags field
+/// Can be just plain number, then it is passed as is.
+/// Can be a string, then it is recognized as a single enabled flag.
+/// Or can be a table of the following format:
+/// * integer keys should have string values, that will be used as enabled flag names or numerical values, that will be just ORed;
+/// * string keys should be flag names, that will be enabled, if corresponding value contains true value.
+enum_value_t luaL_checkenum_multi (lua_State *L, int index, const string2enum_t *set)
+{
+	int type = lua_type (L, index);
+	if (type == LUA_TNUMBER)
+		return lua_tointeger (L, index);
+	else if (type == LUA_TSTRING)
+		return string2enum (lua_tostring (L, index), set);
+	else if (type == LUA_TTABLE) {
+		enum_value_t retval = 0;
+		lua_pushnil (L);
+		while (lua_next (L, index) != 0) {
+			type = lua_type (L, -2);
+			if (type == LUA_TNUMBER) {
+				type = lua_type (L, -1);
+				if (type == LUA_TNUMBER)
+					retval |= lua_tointeger (L, -1);
+				else if (type == LUA_TSTRING)
+					retval |= string2enum (lua_tostring (L, -1), set);
+				else
+					luaL_argerror (L, index, "wrong value type of flag");
+			} else if (type == LUA_TSTRING) {
+				if (lua_toboolean (L, -1))
+					retval |= string2enum (lua_tostring (L, -2), set);
+			} else
+				luaL_argerror (L, index, "wrong key type of flags table");
+			lua_pop (L, 1);
+		}
+	} else
+		luaL_argerror (L, index, "integer, string, or table of ones expected");
+	return 0; // never happens
+}
+
+/// returned flags field
+/// Is always a table with present flag names as keys with true values.
+/// Not present flags are not present in table either.
+/// Not recognized values, if present, will be stored as a number in a first sequential table member (table[1]).
+void luaL_pushenum_multi (lua_State *L, enum_value_t value, const string2enum_t *set)
+{
+	enum_value_t matched = 0;
+	lua_newtable (L);
+	while (set->string) {
+		if (value & set->value) {
+			matched |= set->value & value;
+			lua_pushstring (L, set->string);
+			lua_pushboolean (L, 1);
+			lua_settable (L, -3);
+		}
+		++set;
+	}
+	if (value ^ matched) {
+		lua_pushinteger (L, 1);
+		lua_pushinteger (L, value ^ matched);
+		lua_settable (L, -3);
+	}
+}
+
+void *luaL_malloc (lua_State *L, size_t size)
+{
+	void      *ud;
+	lua_Alloc  allocf = lua_getallocf (L, &ud);
+	return (*allocf) (ud, NULL, 0, size);
+}
+
+void *luaL_realloc (lua_State *L, void *ptr, size_t osize, size_t nsize)
+{
+	void      *ud;
+	lua_Alloc  allocf = lua_getallocf (L, &ud);
+	return (*allocf) (ud, ptr, osize, nsize);
+}
+
+void  luaL_free (lua_State *L, void *ptr)
+{
+	void      *ud;
+	lua_Alloc  allocf = lua_getallocf (L, &ud);
+	(*allocf) (ud, ptr, 1, 0);
+}
+