diff options
| author | Přemysl Eric Janouch <p@janouch.name> | 2025-01-04 08:11:24 +0100 | 
|---|---|---|
| committer | Přemysl Eric Janouch <p@janouch.name> | 2025-01-04 08:15:05 +0100 | 
| commit | b8b01466f3ff0cceef0b718e06f501e2fd954d4d (patch) | |
| tree | 81de37114e231d8c14203b0c1a6518c016ab5a73 | |
| parent | e612d80cc3c3ef139bfcf8b5acee57262b41be13 (diff) | |
| download | liberty-b8b01466f3ff0cceef0b718e06f501e2fd954d4d.tar.gz liberty-b8b01466f3ff0cceef0b718e06f501e2fd954d4d.tar.xz liberty-b8b01466f3ff0cceef0b718e06f501e2fd954d4d.zip  | |
WIP
| -rw-r--r-- | tools/wdye/wdye.c | 206 | 
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;  }  | 
