// How to translate %dynamic in C.  See the corresponding file of external routines in hypot.c

// Compile with gcc -rdynamic prog.c -o prog -ldl

// The library file name is not known to Imp unless we do something hacky
// such as "%from hypot %import %dynamiclongrealfnspec hypotenuse(%longreal x0,y0, x1,y1)"
// or add to the Imp language with a new declaration such as "%library hypot"
// or supply it externally at compile time - an EMAS-style library mechanism
// would have been useful, but for now the call below to 'dlopen' is looking
// in LD_LIBRARY_PATH for the library file.  This will need to be improved on
// by the imptoc environment.

// Run with: export LD_LIBRARY_PATH=.; ./prog  (or use ./hypot.so.1.0  in the dlopen call )

#include <dlfcn.h>  // If dynamics are being used.

#include <stdio.h>
#include <stdlib.h>

static void *dynload(char *lib, char *procname) {
  int rc; void *library, *proc;
  if (   ((library = dlopen(lib, RTLD_NOW | RTLD_NODELETE /*Ensure proc remains callable after closing lib*/)) == NULL)
      || ((proc = dlsym(library, procname)) == NULL)  ) {
    fprintf(stderr, "Error: dynamic load of %s fails - %s\n", procname, dlerror()); exit(1); // dlerror includes lib
  }
  if ((rc = dlclose(library)) != 0) fprintf(stderr, "Warning: dlclose(\"%s\",\"%s\") returned %d - %s\n", lib, procname, rc, dlerror());
  return proc;
}

//  %dynamiclongrealfnspec hypotenuse(%longreal x0,y0, x1,y1)
static double hypotenuse_thunk(double x0, double y0,  double x1, double y1);
static double (*hypotenuse)   (double x0, double y0,  double x1, double y1) = &hypotenuse_thunk;
static double hypotenuse_thunk(double x0, double y0,  double x1, double y1) { return (hypotenuse = dynload("hypot.so.1.0", "hypotenuse"))(x0,y0, x1,y1); }

//%begin
int main(int argc, char *argv[]) {

  //  print string("hypotenuse(1.5,1.5, 2.5,2.5) = ");
  //  print real(hypotenuse(1.5,1.5, 2.5,2.5))   ;! Should be square root of two.
  //  new line
  printf("hypotenuse(1.5,1.5, 2.5,2.5) = %g\n", hypotenuse(1.5,1.5, 2.5,2.5));
  
  //  print string("hypotenuse(2.5,2.5, 3,3) = ");
  //  print real(hypotenuse(2.5,2.5, 3,3))   ;! Should be square root of two divided by 2.
  //  new line
  printf("hypotenuse(2.5,2.5, 3,3) = %g\n", hypotenuse(2.5,2.5, 3,3));
  
//%endofprogram
  exit(0);
  return 0;
}
