
/******************************************************************************
* MODULE     : connect.gen.cc
* DESCRIPTION: Connection of extern packages to TeXmacs
* COPYRIGHT  : (C) 1999  Joris van der Hoeven
*******************************************************************************
* This software falls under the GNU general public license and comes WITHOUT
* ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
* If you don't have this file, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
******************************************************************************/

#module code_connect
#include <dlfcn.h>
#include <TeXmacs.h>

/******************************************************************************
* Exports of TeXmacs
******************************************************************************/

static TeXmacs_exports_1 TeXmacs= {
  "TeXmacs communication protocol 1",
  "TeXmacs 1.0.0.1"
};

/******************************************************************************
* The package resource
******************************************************************************/

#import resource (package_rep, package)
struct package_rep: rep<package> {
  string lib;       // Name of the library
  string symbol;    // Name of the function which determines exported routines
  string init;      // Initialization string
  void*  routs;     // Routines exported by package
  string in_prot;   // Protocol for TeXmacs->package communication
  string out_prot;  // Protocol for package->TeXmacs communication

public:
  package_rep (string name, string lib, string symbol, string init);

  bool   installed ();
  string install ();
  string evaluate (string session, string what);
  string execute (string session, string what);
};
#import code_resource (package_rep, package)

/******************************************************************************
* Package routines
******************************************************************************/

package_rep::package_rep (string name2, string s1, string s2, string s3):
  rep<package> (name2), lib (s1), symbol (s2), init (s3), routs (NULL),
  in_prot ("verbatim"), out_prot ("verbatim") {}

bool
package_rep::installed () {
  return routs != NULL;
}

string
package_rep::install () {
  if (routs != NULL) return "Already installed";
  if (debug (0)) cout << "TeXmacs] Installing package '" << res_name << "'\n";

  char* _symbol= as_charp (symbol);
  char* _lib   = as_charp (lib);
  char* _init  = as_charp (init);

  string r;
  pointer f;
  pointer handle= dlopen (_lib, RTLD_LAZY);
  if (handle) {
    f = dlsym (handle, _symbol);
    if (f!=NULL) {
      void* (*func) (int)= (void* (*) (int)) f;
      routs= func (1);
      package_exports_1* pack= (package_exports_1*) routs;
      char* _errors= NULL;
      char* _message= pack->install (&TeXmacs, _init, &_errors);
      if (_errors != NULL) { routs= NULL; r= "Error: " * string (_errors); }
      else r= string (_message == NULL? ((char*) ""): _message);
      if (_message != NULL) free (_message);
      if (_errors != NULL) free (_errors);
    }
    else r= "Can not find symbol '" * symbol * "' in " * lib;
  }
  else {
    const char *err = dlerror();
    if (err==NULL) r= "Error: could not open library " * lib;
    else r= "Error: " * string ((char *) err);
  }

  delete[] _init;
  delete[] _lib;
  delete[] _symbol;
  if (debug (0)) cout << "TeXmacs] " * r * "\n";
  return r;
}

string
package_rep::evaluate (string session, string s) {
  if (routs==NULL) return "Error: package '" * res_name * "' not installed";
  package_exports_1* pack= (package_exports_1*) routs;

  char* _session= as_charp (session);
  char* _s= as_charp (s);
  char* _errors= NULL;
  char* _r= pack->evaluate (_s, _session, &_errors);
  string r= string (_r==NULL? (_errors==NULL? ((char*) "Error"): _errors): _r);
  if (_r != NULL) free (_r);
  if (_errors != NULL) free (_errors);
  delete[] _s;
  delete[] _session;
  return r;
}

string
package_rep::execute (string session, string s) {
  if (routs==NULL) return "Error: package '" * res_name * "' not installed";
  package_exports_1* pack= (package_exports_1*) routs;

  char* _session= as_charp (session);
  char* _s= as_charp (s);
  char* _errors= NULL;
  char* _r= pack->execute (_s, _session, &_errors);
  string r= string (_r==NULL? (_errors==NULL? ((char*) "Error"): _errors): _r);
  if (_r != NULL) free (_r);
  if (_errors != NULL) free (_errors);
  delete[] _s;
  delete[] _session;
  return r;
}

/******************************************************************************
* Linking symbols from dynamic libraries
******************************************************************************/

string
symbol_install (string lib, string symb, pointer& f) {
  char*  _lib = as_charp (lib);
  char*  _symb= as_charp (symb);
  string out  = "Install#" * lib;

  pointer handle= dlopen (_lib, RTLD_LAZY);
  if (handle) {
    f= dlsym (handle, _symb);
    if (f!=NULL) {
      out= "Dynamically linked symbol '" * symb * "'";
      if (debug (0)) cout << "TeXmacs] " << out << "\n";
    }
    else out= "Can not find symbol '" * symb * "'";
  }
  else {
    f= NULL;
    const char *err = dlerror();
    if (err==NULL) out= "Couldn't find dynamic library";
    else out= string ((char *) err);
  }

  delete[] _symb;
  delete[] _lib;
  return out;
}

/******************************************************************************
* Exported routines
******************************************************************************/

bool
package_declared (string name) {
  return (resource<package> -> contains (name));
}

void
package_declare (string name, string lib, string symbol, string init) {
  if (package_declared (name)) return;
  package pack= new package_rep (name, lib, symbol, init);
  (void) pack;
}

void
package_format (string name, string in_prot, string out_prot) {
  if (!package_declared (name)) return;
  package pack (name);
  pack->in_prot= in_prot;
  pack->out_prot= out_prot;
}

bool
package_installed (string name) {
  if (!package_declared (name)) return FALSE;
  package pack (name);
  return pack->installed ();
}

string
package_install (string name) {
  if (!package_declared (name))
    return "Error: package '" * name * "' not declared";
  package pack (name);
  return pack->install ();
}

tree
package_evaluate (string name, string session, tree expr) {
  string s= tree_to_verbatim (expr);
  if (!package_declared (name))
    return "Error: package '" * name * "' not declared";
  package pack (name);
  return get_texmacs_input (pack->evaluate (session, s), pack->out_prot);
}

string
package_execute (string name, string session, string expr) {
  if (!package_declared (name))
    return "Error: package '" * name * "' not declared";
  package pack (name);
  return pack->execute (session, expr);
}

#endmodule // code_connect
