dlhack()

In my living room, there's a TV, with a computer connected to it.

In that computer, there's a DVD-ROM player, a hard disk, and a card with a TV output.

On that hard disk, there's Debian with xine to view DVDs

When I originally put it there, I would pick up the keyboard to do some user input. This works, but a keyboard is klunky. So, instead, I've been working on jsxine, a little application that does not much more than open a window, and tell xine to play a DVD there, but use the joystick for UI[1]. My 'joystick' is a Logitech Wingman Gamepad Extreme, which has a cable long enough for me to be able to use it comfortably from the couch, so I can use it as a sort of remote control.

The current version has quite some things hardcoded: button 0 is 'select', button 5 is 'eject', button 6 'previous chapter', button 7 'next chapter', and button 8 is 'start or stop playing'. The primary two axes move around in the DVD menu; and other stuff is not yet implemented. This layout, of course, makes a lot of sense on this particular gamepad, but I doubt it does on other joystick devices. And since I want this to eventually be useful for other people, too, I recognized that I would need some way to configure things.

My initial stab at configuration would create a hash table of available actions, read out a configuration file, and then find the appropriate function pointer in the hash table. While this works, it has one rather important downside: adding a configurable action would requrie another item in the hash table; this would eventually make the hash table horribly long. So I thought, why not use the configuration value to ask the dynamic linker to get me a function pointer?

With a little help from my friends, that's exactly what I did. Proof-of-concept code:

#include <dlfcn.h>
#include <stdio.h>

int function() {
	printf("In function!\n");
}

int main(int argc, char**argv) {
	int (*funcptr)(void);
	void* handle;

	printf("foo\n");
	handle = dlopen(NULL, RTLD_NOW);
	funcptr = dlsym(handle, "function");
	funcptr();
	return 0;
}

Compile with cc -ldl -rdynamic. Et voila, that gets you an application which can do a lookup of function names at run time.

Long live C.

Of course, there's a bit of a danger in the above example. A user could just write a config file that has things like 'open' and/or 'write' as arguments, or the like. One should make sure that it can be obvious from the function name that it does indeed define an action; for example, by giving them a common prefix, and prepending that prefix to the function name before handing the name off to dlsym().

But other than that, this seems to work. It apparently also is documented in the FreeBSD documentation on dlopen(), so maybe it's not as much a hack as I thought...

Oh well.

Note that on GNU systems, you can also put a #define _GNU_SOURCE before the #include <dlfcn.h>, you can drop the dlopen() call and go straight to dlsym(), with RTLD_DEFAULT as the handle.

[1] Yes, I could have done a Xine plugin. I didn't want to. This is as much a project to produce something useful as it is a project to hack and have fun.