#ifdef LINUX
#include <dlfcn.h>
#elif WIN32
#define PUBLIC __declspec(dllexport)
#define LIBRARY_CALL WINAPI
#include <windows.h>
#endif
#include "cs.h"

int csoundLoadExternal(void)
{
  return 0;
}

int csoundLoadExternals(void)
{
    char *libname;
#ifdef LINUX
    void *handle;
#elif WIN32
    long handle;
#else
    void *handle = NULL;
#endif
    char *error;
    char buffer[256];
    OENTRY *(*init)(GLOBALS*);
    long (*size)(void);

    if (cglob.oplibs==NULL) return 1;
    printf("Loading libraries %s\n", cglob.oplibs);
    strcpy(buffer, cglob.oplibs);
    libname = strtok(buffer, ",");
#ifdef BETA
    printf("libname %s\n", libname);
#endif
    while (libname!=NULL) {
#ifdef LINUX
      handle = dlopen (libname, RTLD_NOW | RTLD_GLOBAL);
#elif WIN32
      handle = (long) LoadLibrary(libname);
#endif
      if (!handle) {
        printf("Failed to load %s\n", libname);
      }
      else {
        OENTRY *opcodlst_n;
        long length, olength;
#ifdef BETA
        printf("Found handle\n");
#endif
#ifdef LINUX
        size = dlsym(handle, "opcode_size");
        if ((error = dlerror()) != NULL)  {
          printf("Failed to initialise %s: %s", libname, error);
          goto next;
        }
#ifdef BETA
        printf("Found size\n");
#endif
        length = (*size)();
#ifdef BETA
        printf("Length=%d\n", length);
#endif
        init = dlsym(handle, "opcode_init");
#ifdef BETA
        printf("Found init\n");
#endif
        if ((error = dlerror()) != NULL)  {
          printf("Failed to initialise %s: %s", libname, error);
          goto next;
        }
#ifdef BETA
        printf("Calling init\n");
#endif
        opcodlst_n = (*init)(&cglob);
        olength = oplstend-opcodlst;
#elif WIN32
        size = (long(*)(void))GetProcAddress((HINSTANCE)handle, "opcode_size");
        if (size == NULL)  {
          printf("Failed to initialise %s", libname);
          goto next;
        }
#ifdef BETA
        printf("Found size\n");
#endif
        length = (*size)();
#ifdef BETA
        printf("Length=%d\n", length);
#endif
        init = (OENTRY *(*)(GLOBALS*))GetProcAddress((HINSTANCE)handle,
                                                     "opcode_init");
#ifdef BETA
        printf("Found init\n");
#endif
        if (init == NULL)  {
          printf("Failed to initialise %s", libname);
          goto next;
        }
#ifdef BETA
        printf("Calling init\n");
#endif
        opcodlst_n = (*init)(&cglob);
        olength = oplstend-opcodlst;
#endif
#ifdef BETA
        printf("Got opcodlst %p\noplstend=%p, opcodlst=%p, length=%d\n",
               opcodlst_n, oplstend, opcodlst, olength);
        printf("Adding %d(%d) -- first opcode is %s\n",
               length, length/sizeof(OENTRY), opcodlst_n[0].opname);
#endif
        opcodlst = (OENTRY*) mrealloc(opcodlst, olength*sizeof(OENTRY) + length);
        memcpy(opcodlst+olength, opcodlst_n, length);
        oplstend = opcodlst +  olength + length/sizeof(OENTRY);
      }
    next:
      libname = strtok(NULL, ",");
    }
#ifdef BETA
    printf("All loaded\n");
#endif
    return 1;
}

