diff options
Diffstat (limited to 'tools/wdye')
| -rw-r--r-- | tools/wdye/wdye.c | 104 | 
1 files changed, 58 insertions, 46 deletions
| diff --git a/tools/wdye/wdye.c b/tools/wdye/wdye.c index 31652c6..3985abf 100644 --- a/tools/wdye/wdye.c +++ b/tools/wdye/wdye.c @@ -191,7 +191,7 @@ struct process  {  	int terminal_fd;                    ///< Process stdin/stdout/stderr  	pid_t pid;                          ///< Process ID -	// TODO(p): Either `TERMINAL *` or read-out values. +	int ref_term;                       ///< Terminal information  };  static struct process * @@ -200,6 +200,10 @@ xlua_process_new (lua_State *L)  	struct process *self = lua_newuserdata (L, sizeof *self);  	luaL_setmetatable (L, XLUA_PROCESS_METATABLE);  	memset (self, 0, sizeof *self); + +	self->terminal_fd = -1; +	self->pid = -1; +	self->ref_term = LUA_NOREF;  	return self;  } @@ -211,6 +215,7 @@ xlua_process_gc (lua_State *L)  		xclose (self->terminal_fd);  	if (self->pid != -1)  		kill (self->pid, SIGKILL); +	luaL_unref (L, LUA_REGISTRYINDEX, self->ref_term);  	return 0;  } @@ -237,8 +242,6 @@ xlua_process_send (lua_State *L)  static luaL_Reg xlua_process_table[] =  {  	{ "__gc",       xlua_process_gc       }, -//	{ "__index",    xlua_process_index    }, -//	{ "__newindex", xlua_process_newindex },  	{ "expect",     xlua_process_expect   },  	{ "send",       xlua_process_send     },  	{ NULL,         NULL                  } @@ -246,13 +249,34 @@ static luaL_Reg xlua_process_table[] =  // --- Terminal ---------------------------------------------------------------- -// TODO(p): Probably create an object to interact with tinfo. +static bool +load_terminfo (const char *term, struct str_map *strings) +{ +	// TODO(p): See if we can get away with using a bogus FD. +	int err = 0; +	TERMINAL *saved_term = set_curterm (NULL); +	if (setupterm ((char *) term, STDOUT_FILENO, &err) != OK) +	{ +		set_curterm (saved_term); +		return false; +	} + +	for (size_t i = 0; strfnames[i]; i++) +	{ +		const char *value = tigetstr (strnames[i]); +		if (value && value != (char *) -1) +			str_map_set (strings, strfnames[i], xstrdup (value)); +	} +	del_curterm (set_curterm (saved_term)); +	return true; +}  // --- Library -----------------------------------------------------------------  struct xlua_spawn_context  {  	struct str_map env;                 ///< Subprocess environment map +	struct str_map term;                ///< terminfo database strings  	struct strv envv;                   ///< Subprocess environment vector  	struct strv argv;                   ///< Subprocess argument vector @@ -264,6 +288,9 @@ xlua_spawn_context_make (void)  {  	struct xlua_spawn_context self = {};  	self.env = str_map_make (free); +	self.term = str_map_make (free); + +	// XXX: It might make sense to enable starting from an empty environment.  	for (char **p = environ; *p; p++)  	{  		const char *equals = strchr (*p, '='); @@ -283,6 +310,7 @@ static void  xlua_spawn_context_free (struct xlua_spawn_context *self)  {  	str_map_free (&self->env); +	str_map_free (&self->term);  	strv_free (&self->envv);  	strv_free (&self->argv); @@ -317,31 +345,6 @@ environ_map_serialize (struct str_map *env, struct strv *envv)  			xstrdup_printf ("%s=%s", iter.link->key, value));  } -static bool -xlua_load_terminal (lua_State *L, const char *term) -{ -	// TODO(p): See if we can get away with using a bogus FD. -	int err = 0; -	TERMINAL *saved_term = set_curterm (NULL); -	if (setupterm ((char *) term, STDOUT_FILENO, &err) != OK) -	{ -		set_curterm (saved_term); -		return false; -	} - -	for (size_t i = 0; strfnames[i]; i++) -	{ -		const char *name = strfnames[i]; -		const char *value = tigetstr (strnames[i]); -		if (value && value != (char *) -1) -			continue; -	} - -	del_curterm (set_curterm (saved_term)); - -	return true; -} -  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  static int @@ -349,28 +352,24 @@ xlua_spawn_protected (lua_State *L)  {  	struct xlua_spawn_context *ctx = lua_touserdata (L, 1); -	// TODO(p): Consider taking the TERM from the passed environ, -	//   or defaulting to inherited TERM.  These should match anyway. - -	// Step 1: Prepare a terminal object. -	(void) xlua_getfield (L, 1, "term", LUA_TSTRING, true); -	const char *term = lua_tostring (L, -1); - - -	// TODO(p): Process the terminal name, -	//   possibly by creating another indexable Lua object/table. -	//    - Remember to use a default when `term == NULL`. - -	lua_pop (L, 1); - -	// Step 2: Prepare process environment. +	// Step 1: Prepare process environment.  	if (xlua_getfield (L, 1, "environ", LUA_TTABLE, true))  	{  		environ_map_update (&ctx->env, L);  		lua_pop (L, 1);  	} +	char *term = str_map_find (&ctx->env, "TERM"); +	if (!term) +	{ +		print_debug ("setting a default TERM"); +		str_map_set (&ctx->env, "TERM", (term = xstrdup ("dumb"))); +	}  	environ_map_serialize (&ctx->env, &ctx->envv); +	// Step 2: Load terminal information. +	if (!load_terminfo (term, &ctx->term)) +		luaL_error (L, "failed to initialize terminfo for %s", term); +  	// Step 3: Prepare process command line.  	size_t argc = lua_rawlen (L, 1);  	for (size_t i = 1; i <= argc; i++) @@ -391,6 +390,18 @@ xlua_spawn_protected (lua_State *L)  	// This will get garbage collected as appropriate on failure.  	struct process *process = xlua_process_new (L); +	// This could be made into an object that can adjust winsize/termios. +	lua_createtable (L, 0, ctx->term.len); +	struct str_map_iter iter = str_map_iter_make (&ctx->term); +	const char *value = NULL; +	while ((value = str_map_iter_next (&iter))) +	{ +		lua_pushstring (L, iter.link->key); +		lua_pushstring (L, value); +		lua_settable (L, -3); +	} +	process->ref_term = luaL_ref (L, LUA_REGISTRYINDEX); +  	// Step 5: Spawn the process, which gets a new process group.  	process->pid =  		pty_fork (&process->terminal_fd, NULL, NULL, NULL, &ctx->error); @@ -497,8 +508,9 @@ main (int argc, char *argv[])  		print_error ("%s: %s", path, lua_tostring (g.L, -1));  		lua_pop (g.L, 1);  	} - -	// TODO(p): Do we need to pop the error handler? +	lua_pop (g.L, 1);  	lua_close (g.L); + +	poller_free (&g.poller);  	return 0;  } | 
