diff options
| -rw-r--r-- | degesch.c | 262 | 
1 files changed, 137 insertions, 125 deletions
| @@ -1251,15 +1251,7 @@ enum ispect_type  	ISPECT_STR,                         ///< "struct str"  	ISPECT_STR_MAP,                     ///< "struct str_map" -	ISPECT_REF,                         ///< Weakly referenced object - -	// XXX: maybe a PTR type that doesn't warrant weak_refs but is copied -}; - -// TODO: once this finalizes, turn instatiations into macros -struct ispect -{ -	struct ispect_field *fields;        ///< Fields +	ISPECT_REF                          ///< Weakly referenced object  };  struct ispect_field @@ -1267,15 +1259,23 @@ struct ispect_field  	const char *name;                   ///< Name of the field  	size_t offset;                      ///< Offset in the structure  	enum ispect_type type;              ///< Type of the field -	bool is_list;                       ///< This object is a list -	struct ispect *subtype;             ///< Subtype information + +	enum ispect_type subtype;           ///< STR_MAP subtype +	struct ispect_field *fields;        ///< REF target fields +	bool is_list;                       ///< REF target is a list  };  #define ISPECT(object, field, type)                                            \ -	{ #field, offsetof (struct object, field), ISPECT_ ## type, false, NULL }, -#define ISPECT_(object, field, type, is_list, subtype)                         \ -	{ #field, offsetof (struct object, field), ISPECT_ ## type, is_list,       \ -	  &g_ ## subtype ## _ispect }, +	{ #field, offsetof (struct object, field), ISPECT_##type, 0, NULL, false }, +#define ISPECT_REF(object, field, is_list, ref_type)                           \ +	{ #field, offsetof (struct object, field), ISPECT_REF, 0,                  \ +	  g_##ref_type##_ispect, is_list }, +#define ISPECT_MAP(object, field, subtype)                                     \ +	{ #field, offsetof (struct object, field), ISPECT_STR_MAP,                 \ +	  ISPECT_##subtype, NULL, false }, +#define ISPECT_MAP_REF(object, field, is_list, ref_type)                       \ +	{ #field, offsetof (struct object, field), ISPECT_STR_MAP,                 \ +	  ISPECT_REF, g_##ref_type##_ispect, is_list },  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -1317,18 +1317,13 @@ struct user  	struct user_channel *channels;      ///< Channels the user is on  }; -static struct ispect_field g_user_ispect_fields[] = +static struct ispect_field g_user_ispect[] =  {  	ISPECT( user, nickname, STRING )  	ISPECT( user, away,     BOOL   )  	{}  }; -static struct ispect g_user_ispect = -{ -	.fields = g_user_ispect_fields, -}; -  static struct user *  user_new (void)  { @@ -1397,21 +1392,17 @@ struct channel  	bool left_manually;                 ///< Don't rejoin on reconnect  }; -static struct ispect_field g_channel_ispect_fields[] = +static struct ispect_field g_channel_ispect[] =  { -	ISPECT( channel, name,           STRING ) -	ISPECT( channel, topic,          STRING ) -	ISPECT( channel, no_param_modes, STR    ) -	ISPECT( channel, users_len,      SIZE   ) -	ISPECT( channel, left_manually,  BOOL   ) +	ISPECT( channel, name,           STRING  ) +	ISPECT( channel, topic,          STRING  ) +	ISPECT( channel, no_param_modes, STR     ) +	ISPECT_MAP( channel, param_modes, STRING ) +	ISPECT( channel, users_len,      SIZE    ) +	ISPECT( channel, left_manually,  BOOL    )  	{}  }; -static struct ispect g_channel_ispect = -{ -	.fields = g_channel_ispect_fields, -}; -  static struct channel *  channel_new (void)  { @@ -1584,25 +1575,20 @@ struct buffer  	struct user *user;                  ///< Reference to user  }; -static struct ispect g_server_ispect; -static struct ispect_field g_buffer_ispect_fields[] = +static struct ispect_field g_server_ispect[]; +static struct ispect_field g_buffer_ispect[] =  { -	ISPECT ( buffer, name,                  STRING ) -	ISPECT ( buffer, new_messages_count,    UINT   ) -	ISPECT ( buffer, new_unimportant_count, UINT   ) -	ISPECT ( buffer, highlighted,           BOOL   ) -	ISPECT ( buffer, hide_unimportant,      BOOL   ) -	ISPECT_( buffer, server,                REF, false, server  ) -	ISPECT_( buffer, channel,               REF, false, channel ) -	ISPECT_( buffer, user,                  REF, false, user    ) +	ISPECT( buffer, name,                  STRING ) +	ISPECT( buffer, new_messages_count,    UINT   ) +	ISPECT( buffer, new_unimportant_count, UINT   ) +	ISPECT( buffer, highlighted,           BOOL   ) +	ISPECT( buffer, hide_unimportant,      BOOL   ) +	ISPECT_REF( buffer, server,  false, server    ) +	ISPECT_REF( buffer, channel, false, channel   ) +	ISPECT_REF( buffer, user,    false, user      )  	{}  }; -static struct ispect g_buffer_ispect = -{ -	.fields = g_buffer_ispect_fields, -}; -  static struct buffer *  buffer_new (struct input *input)  { @@ -1751,31 +1737,26 @@ struct server  	unsigned irc_max_modes;             ///< Max parametrized modes per command  }; -static struct ispect_field g_server_ispect_fields[] = +static struct ispect_field g_server_ispect[] =  { -	ISPECT ( server, name,              STRING ) -	ISPECT ( server, state,             INT    ) -	ISPECT ( server, reconnect_attempt, UINT   ) -	ISPECT ( server, manual_disconnect, BOOL   ) -	ISPECT ( server, irc_user_host,     STRING ) -	ISPECT ( server, autoaway_active,   BOOL   ) -	ISPECT ( server, cap_echo_message,  BOOL   ) -	ISPECT_( server, buffer,            REF, false, buffer ) +	ISPECT( server, name,              STRING ) +	ISPECT( server, state,             INT    ) +	ISPECT( server, reconnect_attempt, UINT   ) +	ISPECT( server, manual_disconnect, BOOL   ) +	ISPECT( server, irc_user_host,     STRING ) +	ISPECT( server, autoaway_active,   BOOL   ) +	ISPECT( server, cap_echo_message,  BOOL   ) +	ISPECT_REF( server, buffer, false, buffer )  	// TODO: either rename the underlying field or fix the plugins  	{ "user",      offsetof (struct server, irc_user), -	  ISPECT_REF, false, &g_user_ispect }, +	  ISPECT_REF, 0, g_user_ispect, false },  	{ "user_mode", offsetof (struct server, irc_user_mode), -	  ISPECT_STR, false, NULL }, +	  ISPECT_STR, 0, NULL, false },  	{}  }; -static struct ispect g_server_ispect = -{ -	.fields = g_server_ispect_fields, -}; -  static void on_irc_timeout (void *user_data);  static void on_irc_ping_timeout (void *user_data);  static void on_irc_autojoin_timeout (void *user_data); @@ -2109,19 +2090,15 @@ struct app_context  }  *g_ctx; -static struct ispect_field g_ctx_ispect_fields[] = +static struct ispect_field g_ctx_ispect[] =  { -	ISPECT_( app_context, buffers,        REF, true,  buffer ) -	ISPECT_( app_context, global_buffer,  REF, false, buffer ) -	ISPECT_( app_context, current_buffer, REF, false, buffer ) +	ISPECT_MAP_REF( app_context, servers,    false, server ) +	ISPECT_REF( app_context, buffers,        true,  buffer ) +	ISPECT_REF( app_context, global_buffer,  false, buffer ) +	ISPECT_REF( app_context, current_buffer, false, buffer )  	{}  }; -static struct ispect g_ctx_ispect = -{ -	.fields = g_ctx_ispect_fields, -}; -  static int *  filter_color_cube_for_acceptable_nick_colors (size_t *len)  { @@ -8540,7 +8517,7 @@ typedef void (*lua_weak_unref_fn) (void *object, struct weak_ref_link **link);  struct lua_weak_info  {  	const char *name;                   ///< Metatable name -	struct ispect *ispect;              ///< Introspection data +	struct ispect_field *ispect;        ///< Introspection data  	lua_weak_ref_fn ref;                ///< Weak link invalidator  	lua_weak_unref_fn unref;            ///< Weak link generator @@ -8616,7 +8593,7 @@ lua_weak_deref (lua_State *L, const struct lua_weak_info *info)  	static struct lua_weak_info lua_ ## id ## _info =                          \  	{                                                                          \  		.name   = metatable_id,                                                \ -		.ispect = &g_ ## id ## _ispect,                                        \ +		.ispect = g_ ## id ## _ispect,                                         \  		.ref    = (lua_weak_ref_fn)   id ## _weak_ref,                         \  		.unref  = (lua_weak_unref_fn) id ## _weak_unref,                       \  	}; @@ -8636,7 +8613,7 @@ LUA_WEAK_DECLARE (server,  XLUA_SERVER_METATABLE)  static struct lua_weak_info lua_ctx_info =  {  	.name = PROGRAM_NAME, -	.ispect = &g_ctx_ispect, +	.ispect = g_ctx_ispect,  };  // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -9783,15 +9760,15 @@ static luaL_Reg lua_plugin_library[] =  static struct lua_ispect_mapping  { -	struct ispect *ispect;              ///< Type info +	struct ispect_field *ispect;        ///< Type info  	struct lua_weak_info *info;         ///< Lua-specific additions  }  lua_types[] =  { -	{ &g_user_ispect,    &lua_user_info    }, -	{ &g_channel_ispect, &lua_channel_info }, -	{ &g_buffer_ispect,  &lua_buffer_info  }, -	{ &g_server_ispect,  &lua_server_info  }, +	{ g_user_ispect,    &lua_user_info    }, +	{ g_channel_ispect, &lua_channel_info }, +	{ g_buffer_ispect,  &lua_buffer_info  }, +	{ g_server_ispect,  &lua_server_info  },  };  static void * @@ -9817,6 +9794,7 @@ lua_plugin_panic (lua_State *L)  	return 0;  } +// As a rule in this codebase, these fields are right at the top of structs  struct list_header  {  	void *next;                         ///< Next item @@ -9824,10 +9802,21 @@ struct list_header  };  static void -lua_plugin_push_ref (struct lua_plugin *self, void *object, bool is_list, -	struct lua_weak_info *info) +lua_plugin_push_ref (struct lua_plugin *self, void *object, +	struct ispect_field *field)  { -	if (!is_list) +	// TODO: we can definitely make a resolution table right in Lua, +	//   lua_plugin_reg_weak() can fill it automatically (lightud->lightud) +	struct lua_weak_info *info = NULL; +	for (size_t i = 0; i < N_ELEMENTS (lua_types); i++) +		if (lua_types[i].ispect == field->fields) +		{ +			info = lua_types[i].info; +			break; +		} +	hard_assert (info != NULL); + +	if (!field->is_list)  	{  		lua_weak_push (self, object, info);  		return; @@ -9842,6 +9831,55 @@ lua_plugin_push_ref (struct lua_plugin *self, void *object, bool is_list,  	}  } +static void lua_plugin_push_map_field (struct lua_plugin *self, +	const char *key, void *p, struct ispect_field *field); + +static void +lua_plugin_push_struct (struct lua_plugin *self, enum ispect_type type, +	void *value, struct ispect_field *field) +{ +	if (type == ISPECT_STR) +	{ +		struct str *s = value; +		lua_pushlstring (self->L, s->str, s->len); +		return; +	} +	if (type == ISPECT_STR_MAP) +	{ +		struct str_map_iter iter; +		str_map_iter_init (&iter, value); + +		void *value; +		lua_newtable (self->L); +		while ((value = str_map_iter_next (&iter))) +			lua_plugin_push_map_field (self, iter.link->key, value, field); +		return; +	} +	hard_assert (!"unhandled introspection object type"); +} + +static void +lua_plugin_push_map_field (struct lua_plugin *self, +	const char *key, void *p, struct ispect_field *field) +{ +	// That would mean maps in maps ad infinitum +	hard_assert (field->subtype != ISPECT_STR_MAP); + +	intptr_t n = (intptr_t) p; +	switch (field->subtype) +	{ +	// Here the types are generally casted to a void pointer +	case ISPECT_BOOL:   lua_pushboolean (self->L, (bool     ) n); break; +	case ISPECT_INT:    lua_pushinteger (self->L, (int      ) n); break; +	case ISPECT_UINT:   lua_pushinteger (self->L, (unsigned ) n); break; +	case ISPECT_SIZE:   lua_pushinteger (self->L, (size_t   ) n); break; +	case ISPECT_STRING: lua_pushstring  (self->L,             p); break; +	case ISPECT_REF: lua_plugin_push_ref (self, p, field); break; +	default: lua_plugin_push_struct (self, field->subtype, p, field); +	} +	lua_setfield (self->L, -2, key); +} +  static bool  lua_plugin_property_get_ispect (lua_State *L, const char *property_name)  { @@ -9851,53 +9889,27 @@ lua_plugin_property_get_ispect (lua_State *L, const char *property_name)  	struct lua_weak *weak = luaL_checkudata (L, 1, info->name);  	// TODO: I think we can do better than this, maybe binary search at least? -	struct ispect_field *iter; -	for (iter = info->ispect->fields; iter->name; iter++) -		if (!strcmp (property_name, iter->name)) +	struct ispect_field *field; +	for (field = info->ispect; field->name; field++) +		if (!strcmp (property_name, field->name))  			break; -	if (!iter->name) +	if (!field->name)  		return false; -	void *p = (uint8_t *) weak->object + iter->offset; -	switch (iter->type) +	struct lua_plugin *self = weak->plugin; +	void *p = (uint8_t *) weak->object + field->offset; +	switch (field->type)  	{ -	case ISPECT_BOOL:   lua_pushboolean (L, *(bool     *) p); return true; -	case ISPECT_INT:    lua_pushinteger (L, *(int      *) p); return true; -	case ISPECT_UINT:   lua_pushinteger (L, *(unsigned *) p); return true; -	case ISPECT_SIZE:   lua_pushinteger (L, *(size_t   *) p); return true; -	case ISPECT_STRING: lua_pushstring  (L, *(char    **) p); return true; -	case ISPECT_STR: -	{ -		struct str *s = p; -		lua_pushlstring (L, s->str, s->len); -		return true; -	} -	case ISPECT_STR_MAP: -	{ -		// FIXME: we should be able to support other things than strings -		struct str_map_iter iter; -		str_map_iter_init (&iter, p); - -		char *s; -		lua_newtable (L); -		while ((s = str_map_iter_next (&iter))) -			lua_plugin_kv (L, iter.link->key, s); -		return true; +	// Here the types are really what's under the pointer +	case ISPECT_BOOL:   lua_pushboolean (L, *(bool     *) p); break; +	case ISPECT_INT:    lua_pushinteger (L, *(int      *) p); break; +	case ISPECT_UINT:   lua_pushinteger (L, *(unsigned *) p); break; +	case ISPECT_SIZE:   lua_pushinteger (L, *(size_t   *) p); break; +	case ISPECT_STRING: lua_pushstring  (L, *(char    **) p); break; +	case ISPECT_REF: lua_plugin_push_ref (self, *(void **) p, field); break; +	default: lua_plugin_push_struct (self, field->type, p, field);  	} -	case ISPECT_REF: -	{ -		// TODO: we can definitely make a resolution table right in Lua, -		//   lua_plugin_reg_weak() can fill it automatically (lightud->lightud) -		for (size_t i = 0; i < N_ELEMENTS (lua_types); i++) -			if (lua_types[i].ispect == iter->subtype) -			{ -				lua_plugin_push_ref (weak->plugin, *(void **) p, -					iter->is_list, lua_types[i].info); -				return true; -			} -	} -	} -	return soft_assert (false); +	return true;  }  static int | 
