MINOR: lua: add sample and args type converters

These function are used for converting LUA value in HAProxy values.
This is helpful with sample-fetch and converter wrappers.
diff --git a/src/hlua.c b/src/hlua.c
index a3aa05b..cb30b75 100644
--- a/src/hlua.c
+++ b/src/hlua.c
@@ -9,6 +9,7 @@
 #include <types/hlua.h>
 #include <types/proxy.h>
 
+#include <proto/arg.h>
 #include <proto/task.h>
 
 /* Lua uses longjmp to perform yield or throwing errors. This
@@ -45,6 +46,17 @@
  */
 static int class_core_ref;
 
+/* These functions converts types between HAProxy internal args or
+ * sample and LUA types. Another function permits to check if the
+ * LUA stack contains arguments according with an required ARG_T
+ * format.
+ */
+static int hlua_arg2lua(lua_State *L, const struct arg *arg);
+static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg);
+__LJMP static int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp, unsigned int mask);
+static int hlua_smp2lua(lua_State *L, const struct sample *smp);
+static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp);
+
 /* Used to check an Lua function type in the stack. It creates and
  * returns a reference of the function. This function throws an
  * error if the rgument is not a "function".
@@ -201,6 +213,231 @@
 	}
 }
 
+/* This functions is used with sample fetch and converters. It
+ * converts the HAProxy configuration argument in a lua stack
+ * values.
+ *
+ * It takes an array of "arg", and each entry of the array is
+ * converted and pushed in the LUA stack.
+ */
+static int hlua_arg2lua(lua_State *L, const struct arg *arg)
+{
+	switch (arg->type) {
+	case ARGT_SINT:
+		lua_pushinteger(L, arg->data.sint);
+		break;
+
+	case ARGT_UINT:
+	case ARGT_TIME:
+	case ARGT_SIZE:
+		lua_pushunsigned(L, arg->data.sint);
+		break;
+
+	case ARGT_STR:
+		lua_pushlstring(L, arg->data.str.str, arg->data.str.len);
+		break;
+
+	case ARGT_IPV4:
+	case ARGT_IPV6:
+	case ARGT_MSK4:
+	case ARGT_MSK6:
+	case ARGT_FE:
+	case ARGT_BE:
+	case ARGT_TAB:
+	case ARGT_SRV:
+	case ARGT_USR:
+	case ARGT_MAP:
+	default:
+		lua_pushnil(L);
+		break;
+	}
+	return 1;
+}
+
+/* This function take one entrie in an LUA stack at the index "ud",
+ * and try to convert it in an HAProxy argument entry. This is useful
+ * with sample fetch wrappers. The input arguments are gived to the
+ * lua wrapper and converted as arg list by thi function.
+ */
+static int hlua_lua2arg(lua_State *L, int ud, struct arg *arg)
+{
+	switch (lua_type(L, ud)) {
+
+	case LUA_TNUMBER:
+	case LUA_TBOOLEAN:
+		arg->type = ARGT_SINT;
+		arg->data.sint = lua_tointeger(L, ud);
+		break;
+
+	case LUA_TSTRING:
+		arg->type = ARGT_STR;
+		arg->data.str.str = (char *)lua_tolstring(L, ud, (size_t *)&arg->data.str.len);
+		break;
+
+	case LUA_TUSERDATA:
+	case LUA_TNIL:
+	case LUA_TTABLE:
+	case LUA_TFUNCTION:
+	case LUA_TTHREAD:
+	case LUA_TLIGHTUSERDATA:
+		arg->type = ARGT_SINT;
+		arg->data.uint = 0;
+		break;
+	}
+	return 1;
+}
+
+/* the following functions are used to convert a struct sample
+ * in Lua type. This useful to convert the return of the
+ * fetchs or converters.
+ */
+static int hlua_smp2lua(lua_State *L, const struct sample *smp)
+{
+	switch (smp->type) {
+	case SMP_T_SINT:
+		lua_pushinteger(L, smp->data.sint);
+		break;
+
+	case SMP_T_BOOL:
+	case SMP_T_UINT:
+		lua_pushunsigned(L, smp->data.uint);
+		break;
+
+	case SMP_T_BIN:
+	case SMP_T_STR:
+		lua_pushlstring(L, smp->data.str.str, smp->data.str.len);
+		break;
+
+	case SMP_T_METH:
+		switch (smp->data.meth.meth) {
+		case HTTP_METH_OPTIONS: lua_pushstring(L, "OPTIONS"); break;
+		case HTTP_METH_GET:     lua_pushstring(L, "GET");     break;
+		case HTTP_METH_HEAD:    lua_pushstring(L, "HEAD");    break;
+		case HTTP_METH_POST:    lua_pushstring(L, "POST");    break;
+		case HTTP_METH_PUT:     lua_pushstring(L, "PUT");     break;
+		case HTTP_METH_DELETE:  lua_pushstring(L, "DELETE");  break;
+		case HTTP_METH_TRACE:   lua_pushstring(L, "TRACE");   break;
+		case HTTP_METH_CONNECT: lua_pushstring(L, "CONNECT"); break;
+		case HTTP_METH_OTHER:
+			lua_pushlstring(L, smp->data.meth.str.str, smp->data.meth.str.len);
+			break;
+		default:
+			lua_pushnil(L);
+			break;
+		}
+		break;
+
+	case SMP_T_IPV4:
+	case SMP_T_IPV6:
+	case SMP_T_ADDR: /* This type is never used to qualify a sample. */
+	default:
+		lua_pushnil(L);
+		break;
+	}
+	return 1;
+}
+
+/* the following functions are used to convert an Lua type in a
+ * struct sample. This is useful to provide data from a converter
+ * to the LUA code.
+ */
+static int hlua_lua2smp(lua_State *L, int ud, struct sample *smp)
+{
+	switch (lua_type(L, ud)) {
+
+	case LUA_TNUMBER:
+		smp->type = SMP_T_SINT;
+		smp->data.sint = lua_tointeger(L, ud);
+		break;
+
+
+	case LUA_TBOOLEAN:
+		smp->type = SMP_T_BOOL;
+		smp->data.uint = lua_toboolean(L, ud);
+		break;
+
+	case LUA_TSTRING:
+		smp->type = SMP_T_STR;
+		smp->flags |= SMP_F_CONST;
+		smp->data.str.str = (char *)lua_tolstring(L, ud, (size_t *)&smp->data.str.len);
+		break;
+
+	case LUA_TUSERDATA:
+	case LUA_TNIL:
+	case LUA_TTABLE:
+	case LUA_TFUNCTION:
+	case LUA_TTHREAD:
+	case LUA_TLIGHTUSERDATA:
+		smp->type = SMP_T_BOOL;
+		smp->data.uint = 0;
+		break;
+	}
+	return 1;
+}
+
+/* This function check the "argp" builded by another conversion function
+ * is in accord with the expected argp defined by the "mask". The fucntion
+ * returns true or false. It can be adjust the types if there compatibles.
+ */
+__LJMP int hlua_lua2arg_check(lua_State *L, int first, struct arg *argp, unsigned int mask)
+{
+	int min_arg;
+	int idx;
+
+	idx = 0;
+	min_arg = ARGM(mask);
+	mask >>= ARGM_BITS;
+
+	while (1) {
+
+		/* Check oversize. */
+		if (idx >= ARGM_NBARGS && argp[idx].type != ARGT_STOP) {
+			WILL_LJMP(luaL_argerror(L, first + idx, "Malformad argument mask"));
+		}
+
+		/* Check for mandatory arguments. */
+		if (argp[idx].type == ARGT_STOP) {
+			if (idx + 1 < min_arg)
+				WILL_LJMP(luaL_argerror(L, first + idx, "Mandatory argument expected"));
+			return 0;
+		}
+
+		/* Check for exceed the number of requiered argument. */
+		if ((mask & ARGT_MASK) == ARGT_STOP &&
+		    argp[idx].type != ARGT_STOP) {
+			WILL_LJMP(luaL_argerror(L, first + idx, "Last argument expected"));
+		}
+
+		if ((mask & ARGT_MASK) == ARGT_STOP &&
+		    argp[idx].type == ARGT_STOP) {
+			return 0;
+		}
+
+		/* Compatibility mask. */
+		switch (argp[idx].type) {
+		case ARGT_SINT:
+			switch (mask & ARGT_MASK) {
+			case ARGT_UINT: argp[idx].type = mask & ARGT_MASK; break;
+			case ARGT_TIME: argp[idx].type = mask & ARGT_MASK; break;
+			case ARGT_SIZE: argp[idx].type = mask & ARGT_MASK; break;
+			}
+			break;
+		}
+
+		/* Check for type of argument. */
+		if ((mask & ARGT_MASK) != argp[idx].type) {
+			const char *msg = lua_pushfstring(L, "'%s' expected, got '%s'",
+			                                  arg_type_names[(mask & ARGT_MASK)],
+			                                  arg_type_names[argp[idx].type & ARGT_MASK]);
+			WILL_LJMP(luaL_argerror(L, first + idx, msg));
+		}
+
+		/* Next argument. */
+		mask >>= ARGT_BITS;
+		idx++;
+	}
+}
+
 /*
  * The following functions are used to make correspondance between the the
  * executed lua pointer and the "struct hlua *" that contain the context.