load dynamic-library during rc-file parsing



I post the idea to this mailing list at several days ago.
That is loading dynamic-library during rc-file parsing.

I was very excited by the potential of this mechanism, and expected
affirmative replays. But there was no replays. ( why? :-( )

So, I implement the idea.

In rc-file, following directive become available.
	library <tag> = <filename>
or
	library <tag> [ = <filename> ]
	{
	  [file = <filename>]
	  [init = <initialize function name>]
	}

During rc-file parsing, if parser met above directive, it loads specified
library and call initialize function.
Default intialize function is named <tag>_init. but if user specifies the
name, it is called instead of the default.

Current implementation allows just loading any library at run-time.
But, if signal connection or key-binding becomes controlable by rc-file and
these are combined with this mechanism, almost all gtk application has
infinite configurability.

	bind "<Control><Shift>n" {
		<library tag> "any_function_you_want" ()
        }

(IMHO, there is few scriptable application, but almost all gtk apps use
 gtk_rc_parse)

For example, vi key-binding requires special functions which implement
the current state, regular expression searching, etc.
But, people who satisfied current key-binding would not agree to add these
vi specific functions to gtk.
With presented feature, anyone who want to use vi binding just add following
directive to rc-file.
	include "<somewhere>/vi-binding"

( somebody would implement vi-binding ;-> )


May this mechanism be allowed to use some space in libgtk ?

Thanks.


                                  -Takashi Matsuda
                                   matsu@arch.comp.kyutech.ac.jp


Index: gtk/gtkrc.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkrc.c,v
retrieving revision 1.19
diff -r1.19 gtkrc.c
25a26
> #include <dlfcn.h>
30,33c31,35
< typedef struct _GtkRcStyle  GtkRcStyle;
< typedef struct _GtkRcSet    GtkRcSet;
< typedef struct _GtkRcNode   GtkRcNode;
< typedef struct _GtkRcFile   GtkRcFile;
---
> typedef struct _GtkRcStyle	GtkRcStyle;
> typedef struct _GtkRcSet	GtkRcSet;
> typedef struct _GtkRcNode	GtkRcNode;
> typedef struct _GtkRcFile	GtkRcFile;
> typedef struct _GtkRcLibrary	GtkRcLibrary;
64a67,74
> struct _GtkRcLibrary
> {
>   void *handle;
>   gchar *name;
>   gchar *file;
>   gchar *init_func;
> };
> 
108a119
> static guint	   gtk_rc_parse_library		   (GScanner     *scanner);
175a187,190
>   TOKEN_LIBRARY,
>   TOKEN_FILE,
>   TOKEN_INIT,
>   TOKEN_CONNECT,
202a218,221
>   { "library", TOKEN_LIBRARY },
>   { "file", TOKEN_FILE },
>   { "init", TOKEN_INIT },
>   { "connect", TOKEN_CONNECT },
206a226
> static GHashTable *rc_library_ht = NULL;
223a244,245
>   rc_library_ht = g_hash_table_new ((GHashFunc) gtk_rc_style_hash,
> 				    (GCompareFunc) gtk_rc_style_compare);
805a828,830
>     case TOKEN_LIBRARY:
>       return gtk_rc_parse_library (scanner);
> 
1485a1511,1696
> }
> 
> static void
> gtk_rc_close_library (GtkRcLibrary *lib)
> {
>   if (lib->handle)
>     {
>       dlclose (lib->handle);
>       lib->handle = NULL;
>     }
> }
> 
> static guint
> gtk_rc_parse_library (GScanner   *scanner)
> {
>   GtkRcLibrary *rc_lib;
>   guint token;
>   guint retval;
>   gchar *funcname;
>   gint insert = FALSE;
>   gint namelen;
>   gint (*init_func)(void) = NULL;
>   
>   token = g_scanner_get_next_token (scanner);
>   if (token != TOKEN_LIBRARY)
>     return TOKEN_LIBRARY;
>   
>   token = g_scanner_get_next_token (scanner);
>   if (token != G_TOKEN_STRING)
>     return G_TOKEN_STRING;
>   
>   rc_lib = g_hash_table_lookup (rc_library_ht, scanner->value.v_string);
>   
>   if (!rc_lib)
>     {
>       rc_lib = g_new (GtkRcLibrary, 1);
>       rc_lib->name = g_strdup (scanner->value.v_string);
>       rc_lib->file = NULL;
>       rc_lib->init_func = NULL;
>       rc_lib->handle = NULL;
> 
>       insert = TRUE;
>     }
>   
>   token = g_scanner_peek_next_token (scanner);
>   if (token == G_TOKEN_EQUAL_SIGN)
>     {
>       token = g_scanner_get_next_token (scanner);
> 
>       token = g_scanner_get_next_token (scanner);
>       if (token != G_TOKEN_STRING)
> 	{
> 	  retval = G_TOKEN_STRING;
> 	  goto ERROR;
> 	}
>       if (rc_lib->file)
> 	{
> 	  g_free (rc_lib->file);
> 	  gtk_rc_close_library (rc_lib);
> 	}
>       rc_lib->file = g_strdup (scanner->value.v_string);
> 
>       token = g_scanner_peek_next_token (scanner);
>     }
> 
>   if (token != G_TOKEN_LEFT_CURLY && !rc_lib->file)
>     {
>       retval = G_TOKEN_LEFT_CURLY;
>       goto ERROR;
>     }
> 
>   if (token == G_TOKEN_LEFT_CURLY)
>     {
>       token = g_scanner_get_next_token (scanner);
> 
>       token = g_scanner_get_next_token (scanner);
>       while (token != G_TOKEN_RIGHT_CURLY)
> 	{
> 	  switch (token)
> 	    {
> 	    case TOKEN_FILE:
> 	      token = g_scanner_get_next_token (scanner);
> 	      if (token != G_TOKEN_EQUAL_SIGN)
> 		{
> 		  retval = G_TOKEN_EQUAL_SIGN;
> 		  goto ERROR;
> 		}
> 	      token = g_scanner_get_next_token (scanner);
> 	      if (token != G_TOKEN_STRING)
> 		{
> 		  retval = G_TOKEN_STRING;
> 		  goto ERROR;
> 		}
> 	      if (rc_lib->file)
> 		g_free (rc_lib->file);
> 	      if (rc_lib->handle)
> 		gtk_rc_close_library (rc_lib);
> 	      rc_lib->file = g_strdup (scanner->value.v_string);
> 
> 	      break;	
> 
> 	    case TOKEN_INIT:
> 	      token = g_scanner_get_next_token (scanner);
> 	      if (token != G_TOKEN_EQUAL_SIGN)
> 		{
> 		  retval = G_TOKEN_EQUAL_SIGN;
> 		  goto ERROR;
> 		}
> 	      token = g_scanner_get_next_token (scanner);
> 	      if (token != G_TOKEN_STRING)
> 		{
> 		  retval = G_TOKEN_STRING;
> 		  goto ERROR;
> 		}
> 	      if (rc_lib->init_func)
> 		g_free (rc_lib->init_func);
> 	      rc_lib->init_func = g_strdup (scanner->value.v_string);
> 
> 	      break;	
> 	    default:
> 	      retval = G_TOKEN_RIGHT_CURLY;
> 	      goto ERROR;
> 	    }
> 
> 	  token = g_scanner_get_next_token (scanner);
> 	}
>     }
> 
>   if (!rc_lib->file) 
>     {
>       g_warning ("library file for library tag \"%s\" is not specified.",
> 		 rc_lib->name);	
>       retval = G_TOKEN_NONE;
>       goto ERROR;
>     }
> 
>   if (!rc_lib->handle)
>     {
>       rc_lib->handle = dlopen (rc_lib->file, RTLD_LAZY);
>       if (!rc_lib->handle)
> 	{
> 	  g_warning ("can not load library \"%s\".", rc_lib->file);
> 	  retval = G_TOKEN_NONE;
> 	  goto ERROR;
> 	}
>       
>       if (rc_lib->init_func)
> 	init_func = dlsym (rc_lib->handle, rc_lib->init_func);
>       if (!init_func)
> 	{
> 	  namelen = strlen (rc_lib->name);
> 	  funcname = g_new (gchar, namelen + 6); 
> 	  strcpy (funcname, rc_lib->name);
> 	  strcpy (funcname+namelen, "_init");
> 	  init_func = dlsym (rc_lib->handle, funcname);
> 	  g_free (funcname);
> 	}
>       if (init_func)
> 	{
> 	  gint ret = (*init_func)();
> 	  if (ret)
> 	    {
> 	      g_warning ("library \"%s\" initialization failed.", rc_lib->name);
> 	      retval = G_TOKEN_NONE;
> 	      goto ERROR;
> 	    }
> 	}
>     }
> 
>   if (insert)
>     g_hash_table_insert (rc_library_ht, rc_lib->name, rc_lib);
> 
>   return G_TOKEN_NONE;
> 
>  ERROR:
>   if (rc_lib)
>     {
>       if (rc_lib->name)
> 	g_free (rc_lib->name);
>       if (rc_lib->file)
> 	g_free (rc_lib->file);
> 
>       g_free (rc_lib);
>     }
>   
>   return retval;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]