aboutsummaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/wdye/wdye.c206
1 files changed, 185 insertions, 21 deletions
diff --git a/tools/wdye/wdye.c b/tools/wdye/wdye.c
index 6ab903f..a827732 100644
--- a/tools/wdye/wdye.c
+++ b/tools/wdye/wdye.c
@@ -155,7 +155,6 @@ pty_fork (int *ptrfdm, char **slave_name,
static struct
{
lua_State *L; ///< Lua state
- struct poller poller; ///< Event loop
}
g;
@@ -183,6 +182,96 @@ xlua_getfield (lua_State *L, int idx, const char *name,
lua_typename (L, found), lua_typename (L, expected));
}
+static void
+xlua_newtablecopy (lua_State *L, int idx, int first, int last)
+{
+ int len = last - first + 1;
+ lua_createtable (L, len, 0);
+ if (idx < 0)
+ idx--;
+
+ for (lua_Integer i = 0; i < len; i++)
+ {
+ lua_rawgeti (L, idx, first + i);
+ lua_rawseti (L, -2, 1 + i);
+ }
+}
+
+// --- Patterns ----------------------------------------------------------------
+
+#define XLUA_PATTERN_METATABLE "pattern"
+
+enum pattern_kind
+{
+ PATTERN_RE, ///< Regular expression match
+ PATTERN_TIMEOUT, ///< Timeout
+ PATTERN_EOF, ///< EOF condition
+ PATTERN_DEFAULT, ///< Either timeout or EOF
+};
+
+struct pattern
+{
+ enum pattern_kind kind; ///< Tag
+ int ref_process; ///< Process for RE/EOF/DEFAULT
+ regex_t *re; ///< Regular expression for RE
+ int64_t timeout; ///< Timeout for TIMEOUT/DEFAULT
+ bool notransfer; ///< Do not consume process buffer
+ int ref_values; ///< Return values as a table reference
+
+ struct error *e; ///< Error buffer
+
+ // TODO(p):
+ // - ref_values is a LUA_TTABLE with arbitrary values.
+ // - https://www.lua.org/source/5.3/ltablib.c.html#unpack
+ // to then return everything as multiple values.
+ // - Function values will be executed and expanded.
+};
+
+static struct pattern *
+xlua_pattern_new (lua_State *L, enum pattern_kind kind)
+{
+ struct pattern *self = lua_newuserdata (L, sizeof *self);
+ luaL_setmetatable (L, XLUA_PATTERN_METATABLE);
+ memset (self, 0, sizeof *self);
+
+ self->kind = kind;
+ self->ref_process = LUA_NOREF;
+ self->timeout = -1;
+ self->ref_values = LUA_NOREF;
+ return self;
+}
+
+static int
+xlua_pattern_gc (lua_State *L)
+{
+ struct pattern *self = luaL_checkudata (L, 1, XLUA_PATTERN_METATABLE);
+ luaL_unref (L, LUA_REGISTRYINDEX, self->ref_process);
+ if (self->re)
+ regex_free (self->re);
+ luaL_unref (L, LUA_REGISTRYINDEX, self->ref_values);
+ if (self->e)
+ error_free (self->e);
+ return 0;
+}
+
+static bool
+xlua_pattern_readtimeout (struct pattern *self, lua_State *L, int idx)
+{
+ lua_rawgeti (L, idx, 1);
+ bool ok = lua_isinteger (L, -1);
+ lua_Integer v = lua_tointeger (L, -1);
+ lua_pop (L, 1);
+ if (ok)
+ self->timeout = v;
+ return ok;
+}
+
+static luaL_Reg xlua_pattern_table[] =
+{
+ { "__gc", xlua_pattern_gc },
+ { NULL, NULL }
+};
+
// --- Process -----------------------------------------------------------------
#define XLUA_PROCESS_METATABLE "process"
@@ -220,25 +309,13 @@ xlua_process_gc (lua_State *L)
}
static int
-xlua_process_expect (lua_State *L)
-{
- struct process *self = luaL_checkudata (L, 1, XLUA_PROCESS_METATABLE);
- // TODO(p): Arguments.
- // TODO(p): Keep reading input into a buffer,
- // until there's a match.
- // - It seems we need to keep the buffer within the process object,
- // because we can read too much.
- return 0;
-}
-
-static int
xlua_process_send (lua_State *L)
{
struct process *self = luaL_checkudata (L, 1, XLUA_PROCESS_METATABLE);
int nargs = lua_gettop (L);
for (int i = 2; i <= nargs; i++)
if (!lua_isstring (L, i))
- return luaL_error (L, "need string arguments");
+ return luaL_argerror (L, i, "need string arguments");
for (int i = 2; i <= nargs; i++)
{
@@ -254,11 +331,47 @@ xlua_process_send (lua_State *L)
return 1;
}
+static int
+xlua_process_re (lua_State *L)
+{
+ struct process *self = luaL_checkudata (L, 1, XLUA_PROCESS_METATABLE);
+ luaL_checktype (L, 2, LUA_TTABLE);
+ if (lua_gettop (L) != 2)
+ return luaL_error (L, "too many arguments");
+
+ struct pattern *pattern = xlua_pattern_new (L, PATTERN_RE);
+
+ lua_getfield (L, 2, "nocase");
+ int flags = REG_EXTENDED;
+ if (lua_toboolean (L, -1))
+ flags |= REG_ICASE;
+
+ lua_getfield (L, 2, "notransfer");
+ if (lua_toboolean (L, -1))
+ pattern->notransfer = true;
+
+ lua_rawgeti (L, 2, 1);
+ if (!lua_isstring (L, -1))
+ return luaL_error (L, "expected regular expression");
+
+ size_t len = 0;
+ const char *re = lua_tolstring (L, -1, &len);
+ if (!(pattern->re = regex_compile (re, flags, &pattern->e)))
+ return luaL_error (L, "%s", pattern->e->message);
+ lua_pop (L, 3);
+
+ xlua_newtablecopy (L, 2, 2, lua_rawlen (L, 2));
+ pattern->ref_values = luaL_ref (L, LUA_REGISTRYINDEX);
+ return 1;
+}
+
static luaL_Reg xlua_process_table[] =
{
{ "__gc", xlua_process_gc },
- { "expect", xlua_process_expect },
{ "send", xlua_process_send },
+ { "re", xlua_process_re },
+// { "eof", xlua_process_eof },
+// { "default", xlua_process_default },
{ NULL, NULL }
};
@@ -457,10 +570,65 @@ xlua_spawn (lua_State *L)
return 1;
}
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+static int
+xlua_expect (lua_State *L)
+{
+ int nargs = lua_gettop (L);
+ for (int i = 1; i <= nargs; i++)
+ luaL_checkudata (L, i, XLUA_PATTERN_METATABLE);
+
+ struct poller poller;
+ poller_init (&poller);
+
+ // TODO(p): Add pattern terminals to an event loop,
+ // add timers, run the loop...
+
+ for (int i = 1; i <= nargs; i++)
+ {
+ struct pattern *pattern =
+ luaL_checkudata (L, i, XLUA_PATTERN_METATABLE);
+ switch (pattern->kind)
+ {
+ }
+ }
+
+ // TODO(p): Keep reading input into a buffer,
+ // until there's a match.
+ // - It seems we need to keep the buffer within the process object,
+ // because we can read too much.
+
+ poller_free (&poller);
+ return 0;
+}
+
+// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+static int
+xlua_timeout (lua_State *L)
+{
+ luaL_checktype (L, 1, LUA_TTABLE);
+ if (lua_gettop (L) != 1)
+ return luaL_error (L, "too many arguments");
+
+ struct pattern *pattern = xlua_pattern_new (L, PATTERN_TIMEOUT);
+ int first = 1, last = lua_rawlen (L, 1);
+ if (xlua_pattern_readtimeout (pattern, L, 1))
+ first++;
+
+ xlua_newtablecopy (L, 1, first, last);
+ pattern->ref_values = luaL_ref (L, LUA_REGISTRYINDEX);
+ return 1;
+}
+
static luaL_Reg xlua_library[] =
{
- { "spawn", xlua_spawn },
- { NULL, NULL }
+ { "spawn", xlua_spawn },
+ { "expect", xlua_expect },
+ { "timeout", xlua_timeout },
+// { "continue", xlua_continue },
+ { NULL, NULL }
};
// --- Initialisation, event handling ------------------------------------------
@@ -513,8 +681,6 @@ main (int argc, char *argv[])
luaL_setfuncs (g.L, xlua_process_table, 0);
lua_pop (g.L, 1);
- poller_init (&g.poller);
-
const char *path = argv[1];
lua_pushcfunction (g.L, xlua_error_handler);
if (luaL_loadfile (g.L, path)
@@ -525,7 +691,5 @@ main (int argc, char *argv[])
}
lua_pop (g.L, 1);
lua_close (g.L);
-
- poller_free (&g.poller);
return 0;
}