/*
 * dyndemo.c
 *
 * This is a test and demonstration of run-time loading of a module
 * of code.
 */

/* Signature: 22391ded 12-Apr-2008 */

#include "config.h"

#include <stdio.h>

#ifdef WIN32
#include <windows.h>
#else
#include <dlfcn.h>
#endif

extern int variable_in_base;
extern int function_in_base(int x);

/*
 * I will make the compiled version of this file big to show that
 * it does not get copied into the sub-function in any way... So the
 * next new lines just ensure that function_in_base has a very long and
 * messy definition. I want to do this so that one can then inspect the
 * size of the dyndemo executable and the dynmodule DLL and observe that
 * the DLL is small enough that it really can not possibly contain the
 * body of "function_in_base".
 */

int p(int x)
{
   return 3*x-1;
}

#define q x = p(x);
#define r q q q q q q q q q q
#define s r r r r r r r r r r
#define t s s s s s s s s s s

int function_in_base(int x)
{
    t
    return 7*x-3;
}

int variable_in_base = 0x12345678;

/*
 * So that I can check results I have a copy here of the function
 * I put in the loadable module...
 */

int clone(int x)
{
    return 3*function_in_base(x) + 1;
}

typedef int onearg(int a);

int main(int argc, char *argv[])
{
    onearg *b = NULL;
#ifdef WIN32
    HANDLE a = LoadLibrary(".\\dynmodule.dll");
    printf("Dynamic loading of test code\na = %p\n", (void *)a);
    fflush(stdout);
    if (a == 0)
    {   DWORD err = GetLastError();
        char errbuf[80];
        printf("Error code %ld = %lx\n", (long)err, (long)err);
        err = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM,
                            NULL, err, 0, errbuf, 80, NULL);
        if (err != 0) printf("%s", errbuf);
        return 0;
    }
    b = (onearg *)GetProcAddress(a, "callme");
#else
    void *a;
    printf("Dynamic loading test code\n");
    fflush(stdout);
    a = dlopen("./dynmodule.so", RTLD_NOW | RTLD_GLOBAL);
    printf("a = %p\n", a);
    fflush(stdout);
    if (a == NULL)
    {   printf("Err = <%s>\n", dlerror()); fflush(stdout);
        return 0;
    }
    b = dlsym(a, "callme");
#endif
    printf("b = %p\n", b);
    fflush(stdout);
    if (b == NULL) return 0;
    printf("variable as printed from base = %.8x @ %p\n",
        variable_in_base, &variable_in_base);
    printf("function as printed from base = %p\n",
        function_in_base);
/*
 * The next 2 lines are expected to display the same numeric value.
 */
    printf("b(7) = %x\n", ((onearg *)b)(7));
    printf("clone(7) = %x\n", clone(7));
    fflush(stdout);
#ifdef WIN32
    FreeLibrary(a);   
#else
    dlclose(a);
#endif
    return 0;
}

/* end of dyndemo.c */

