This is a heresy I have done, of my own free will and volition, and
which I now know as being a sin.

I have butchered the one true awk source code, made it re-entrant and
embeddable in C programs, and now present it as a library and a small
driver program. The driver program now uses getopt_long, and gives a
good idea of how to use awklib in embedded code.

Furthermore, I have "added" to the one true language. The additions are
4 functions:

	dlopen(handle, shared object name)
	dlproto(handle, C function prototype as a string)
	dlcall(handle, function, function args...)
	dlclose(handle)

which allows you to do such abominations as:

	dlopen(libc, "libc");
	dlproto(libc, "int write(int, ptr, int)")
	dlcall(libc, "write", 1, "hi\n", 3)
	dlclose(libc)

Please note that you can specify the prototype at the same time as the
foreign function call, with dlcall:

	dlopen(libc, "libc");
	dlcall(libc, "int write(int, ptr, int)", 1, "hi\n", 3)

and then:

% ./awk 'BEGIN {\
? dlopen(libc, "libc")\
? dlcall(libc, "int printf(pointer)", "Hello world\n") }' /dev/null
Hello world
%

In order to support foreign functions which typically use a structure
passed into every function as a handle (very much like the awklib
implementation here), I'd also added two other functions which can be
called from scripts:

	buf = dlalloc(size)
	dlfree(buf)

and also a new prototype keyword called "storage" - this is functionally
equivalent to int, but more intuitively obvious that the argument should
be pre-allocated storage.

% ./awk 'BEGIN {\
	dlopen(libc, "libc")\
	size = 1024\
	buf = dlalloc(size)\
	dlcall(libc, "int snprintf(storage, int, ptr, int)", buf, size, "allocated size is %d\n", size)\
	dlcall(libc, "int printf(storage)", buf)\
	dlfree(buf) }' /dev/null
allocated size is 1024
%

Finally, we need a way to get that information back into an awk script,
and we do that with the

	var = dlfield(storage, offset, length, type)

function.

