#include <dlfcn.h>
#include <stdlib.h>
#include <extension.h>
#include <debug.h>
/* dammit ... had to add these for the IN_EIC error-trap flag */
#include <bastard.h>
extern struct DISASM_ENV disasm_env;
/* </DAMMIT> */

/* the way it works:
 * Extensions are loaded and unloaded by referring to their type constants.
 * Only routines which call the extensions will refer to the extension
 * structures directly, so there is no API for doing do.
 *
 * Note that the functions each extension provides will be callable via
 * the bastard API, so scripts will not call the extensions directly.
 */
void InitExtensions(){
   ext_arch = calloc(sizeof(struct EXT__ARCH), 1);
   ext_asm = calloc(sizeof(struct EXT__ASM), 1);
   ext_format = calloc(sizeof(struct EXT__FORMAT), 1);
   ext_lang = calloc(sizeof(struct EXT__LANG), 1);
   ext_engine = calloc(sizeof(struct EXT__ENGINE), 1);
   ext_plugin = calloc(sizeof(struct EXT__PLUGIN), 1);
   
   return;
}

void CleanupExtensions(){
   /* foreach extension, call cleanup and unload */
   UnloadExtension(EXT_ARCH);
   UnloadExtension(EXT_ASM);
   UnloadExtension(EXT_FORMAT);
   UnloadExtension(EXT_LANG);
   UnloadExtension(EXT_ENGINE);
   UnloadExtension(EXT_PLUGIN);
   /* free the demn memory */
   free(ext_arch);
   free(ext_asm);
   free(ext_format);
   free(ext_lang);
   free(ext_engine);
   free(ext_plugin);
   return;
}

int LoadExt_internal( struct EXTENSION *ext, int type, char *filename, 
                     int method){

   /* if previously loaded, just return */
   DEBUG_PrintMsg("checking if %s is already loaded\n", filename);
   if ( ext->filename && ! strcmp(filename, ext->filename)) return(1);
   /* if another extension of the same type is currently loaded, unload it */
   if (ext->filename || ext->lib ) UnloadExtension(type);
   /* if a library, load it */
   if ( method == EXT_SO )
      if (! (ext->lib = dlopen(filename, RTLD_NOW)) ){
         ErrorMsg(4200, dlerror());
         return(SetLastError(4200));
      }
   return(2);
}

int LoadExtension( int type, char *filename, void *param){
   int len, method, rv; /* name length, script or binary */
   struct EXTENSION *ext;

   /* determine extension type based on file extension */
   len = strlen(filename);
   DEBUG_PrintMsg("Starting to Load %s\n", filename);
   if ( ! strncmp(".bc", &filename[len - 3], 3))
      method = EXT_BC;  /* we have a script */
   else { /* binary extension is therefore arbitrary */
      method = EXT_SO; 
   }

   /* set up function pointers for each extension */
   switch (type) {
      case EXT_PLUGIN:
         ext = &ext_plugin->ext;
         if( (rv=LoadExt_internal(ext, type, filename, method)) != 2)
            return(rv);
         DEBUG_PrintMsg("loading plugin %s\n", filename);
         if (method == EXT_BC) {
            ext->fn_init = NULL;
            ext->fn_cleanup = NULL;
            ext_plugin->fn_main = &plugin_main_stub;
         } else { /* method == EXT_SO */
            ext->fn_init = dlsym(ext->lib, "ext_plugin_init");
            ext->fn_cleanup = dlsym(ext->lib, "ext_plugin_cleanup");
            ext_plugin->fn_main = dlsym(ext->lib, "plugin_main");
         }
         break;
      case EXT_ENGINE:
         ext = &ext_engine->ext;
         if( (rv=LoadExt_internal(ext, type, filename, method)) != 2)
            return(rv);
         DEBUG_PrintMsg("loading engine %s\n", filename);
         if (method == EXT_BC) {
            ext->fn_init = NULL;
            ext->fn_cleanup = NULL;
            ext_engine->fn_main = &engine_main_stub;
         } else { /* method == EXT_SO */
            ext->fn_init = dlsym(ext->lib, "ext_engine_init");
            ext->fn_cleanup = dlsym(ext->lib, "ext_engine_cleanup");
            ext_engine->fn_main = dlsym(ext->lib, "engine_main");
         }
         break;
      case EXT_FORMAT:
         ext = &ext_format->ext;
         if( (rv=LoadExt_internal(ext, type, filename, method)) != 2)
            return(rv);
         DEBUG_PrintMsg("loading format %s\n", filename);
         if (method == EXT_BC) {
            ext->fn_init = NULL;
            ext->fn_cleanup = NULL;
            ext_format->fn_read_header = &read_header_stub;
         } else { /* method == EXT_SO */
            ext->fn_init = dlsym(ext->lib, "ext_format_init");
            ext->fn_cleanup = dlsym(ext->lib, "ext_format_cleanup");
            ext_format->fn_read_header = dlsym(ext->lib, "read_header");
            if (! ext_format->fn_read_header ) method = 0;
         }
         break;
      case EXT_ARCH:
         ext = &ext_arch->ext;
         if( (rv=LoadExt_internal(ext, type, filename, method)) != 2)
            return(rv);
         DEBUG_PrintMsg("loading arch %s\n", filename);
         if (method == EXT_BC) {
            ext->fn_init = &arch_init_stub;
            ext->fn_cleanup = &arch_cleanup_stub;
            ext_arch->fn_disasm_addr = &disasm_addr_stub;
            ext_arch->fn_get_prologue = &get_prologue_stub;
            ext_arch->fn_get_epilogue = &get_epilogue_stub;
            ext_arch->fn_gen_effect = &gen_effect_stub;
            ext_arch->fn_gen_int = &gen_int_stub;
         } else { /* method == EXT_SO */
            ext->fn_init = dlsym(ext->lib, "ext_arch_init");
            ext->fn_cleanup = dlsym(ext->lib, "ext_arch_cleanup");
            ext_arch->fn_disasm_addr = dlsym(ext->lib, "disasm_addr");
            ext_arch->fn_get_prologue = dlsym(ext->lib, "get_prologue");
            ext_arch->fn_get_epilogue = dlsym(ext->lib, "get_epilogue");
            ext_arch->fn_gen_effect = dlsym(ext->lib, "gen_reg_effect");
            ext_arch->fn_gen_int = dlsym(ext->lib, "gen_int");
            if (! ext->fn_init || ! ext_arch->fn_disasm_addr) method = 0;
         }
         break;
      case EXT_ASM:
         ext = &ext_asm->ext;
         if( (rv=LoadExt_internal(ext, type, filename, method)) != 2)
            return(rv);
         DEBUG_PrintMsg("loading asm %s\n", filename);
         if (method == EXT_BC) {
            ext->fn_init = &asm_init_stub;
            ext->fn_cleanup = &asm_cleanup_stub;
            ext_asm->fn_sprint_code = &sprint_code_stub;
            ext_asm->fn_sprint_func_s = &sprint_func_start_stub;
            ext_asm->fn_sprint_func_e = &sprint_func_end_stub;
            ext_asm->fn_sprint_struct = &sprint_struct_stub;
            ext_asm->fn_sprint_sec_s = &sprint_section_start_stub;
            ext_asm->fn_sprint_sec_e = &sprint_section_end_stub;
            ext_asm->fn_sprint_addrexp = &sprint_addrexp_stub;
            ext_asm->fn_gen_file = &gen_asmfile_stub;
         } else { /* method == EXT_SO */
            ext->fn_init = dlsym(ext->lib, "ext_asm_init");
            ext->fn_cleanup = dlsym(ext->lib, "ext_asm_cleanup");
            ext_asm->fn_sprint_code = dlsym(ext->lib, "sprint_code");
            ext_asm->fn_sprint_struct = dlsym(ext->lib,"sprint_asm_struct");
            ext_asm->fn_sprint_func_s = dlsym(ext->lib,"sprint_asm_func_start");
            ext_asm->fn_sprint_func_e = dlsym(ext->lib,"sprint_asm_func_end");
            ext_asm->fn_sprint_sec_s=dlsym(ext->lib,"sprint_section_start");
            ext_asm->fn_sprint_sec_e =dlsym(ext->lib, "sprint_section_end");
            ext_asm->fn_sprint_addrexp = dlsym(ext->lib, "sprint_addrexp");
            ext_asm->fn_gen_file = dlsym(ext->lib, "gen_asm_file");
            if (! ext->fn_init || ! ext_asm->fn_sprint_code || 
                  ! ext_asm->fn_sprint_addrexp)          method = 0;
         }
         break;
      case EXT_LANG:
         ext = &ext_lang->ext;
         if( (rv=LoadExt_internal(ext, type, filename, method)) != 2)
            return(rv);
         DEBUG_PrintMsg("loading lang %s\n", filename);
         if (method == EXT_BC) {
            ext->fn_init = &lang_init_stub;
            ext->fn_cleanup = &lang_cleanup_stub;
            ext_lang->fn_findstr = (findstr_fn) &findstr_stub;
            ext_lang->fn_makestr = (makestr_fn) &makestr_stub;
            ext_lang->fn_datatype = (datatype_fn) &datatype_stub;
            ext_lang->fn_sprint_proto = &sprint_proto_stub;
            ext_lang->fn_sprint_func = &sprint_func_stub;
            ext_lang->fn_gen_final = &gen_final_stub;
            ext_lang->fn_gen_file = &gen_hllfile_stub;
         } else { /* method == EXT_SO */
            ext->fn_init = dlsym(ext->lib, "ext_lang_init");
            ext->fn_cleanup = dlsym(ext->lib, "ext_lang_cleanup");
            ext_lang->fn_findstr = dlsym(ext->lib, "findstr");
            ext_lang->fn_makestr = dlsym(ext->lib, "makestr");
            ext_lang->fn_datatype = dlsym(ext->lib, "add_data_types");
            ext_lang->fn_sprint_proto = dlsym(ext->lib, "sprint_proto");
            ext_lang->fn_sprint_func = dlsym(ext->lib, "sprint_func");
            ext_lang->fn_gen_final = dlsym(ext->lib, "gen_final");
            ext_lang->fn_gen_file = dlsym(ext->lib, "gen_file");
         }
         break;
      default:
         return(0); /* this is an unknown type */
   };

   /*if (method == 0) { // reuse method for bailout 
      if (ext->lib) dlclose(ext->lib);
      return(0);
   }*/
   /* set filename, etc for extension */
   ext->filename = calloc(len + 1, 1);
   strncpy(ext->filename, filename, len);
   ext->flags = method & type & EXT_OPEN;

   /* if init call init */
   DEBUG_PrintMsg("Calling init for %s\n", filename);
   if (ext->fn_init) ext->fn_init( param );
   ext->flags &= EXT_INIT;
   DEBUG_PrintMsg("Done Loading %s\n", filename);
   return(1);
}

int GetExtensionFlags( int type ){
   struct EXTENSION *ext;
   switch (type) {
      case EXT_PLUGIN:
         ext = &ext_plugin->ext; break;
      case EXT_ENGINE:
         ext = &ext_engine->ext; break;
      case EXT_FORMAT:
         ext = &ext_format->ext; break;
      case EXT_ARCH:
         ext = &ext_arch->ext; break;
      case EXT_ASM:
         ext = &ext_asm->ext; break;
      case EXT_LANG:
         ext = &ext_lang->ext; break;
      default: 
         return(0);
   }
   return(ext->flags);
}

int UnloadExtension( int type ){
   struct EXTENSION *ext;
   /* if cleanup call cleanup */
   switch (type) {
      case EXT_PLUGIN:
         ext = &ext_plugin->ext; break;
      case EXT_ENGINE:
         ext = &ext_engine->ext; break;
      case EXT_FORMAT:
         ext = &ext_format->ext; break;
      case EXT_ARCH:
         ext = &ext_arch->ext; break;
      case EXT_ASM:
         ext = &ext_asm->ext; break;
      case EXT_LANG:
         ext = &ext_lang->ext; break;
      default: 
         return(0);
   }
   DEBUG_PrintMsg("Unloading extension %s\n", ext->filename);
   ext->flags &= EXT_CLEANUP;
   if (ext->fn_cleanup) ext->fn_cleanup();
   free(ext->filename);
   if (ext->lib) dlclose(ext->lib);
   ext->flags &= EXT_CLOSED;
   memset( ext, 0, sizeof( struct EXTENSION ));
   return(1);
}

/* wrappers ------------- */
/* these are used call .bc script routines instead of .so routines */

/* PLUGIN stubs */
int plugin_main_stub(void *plugin_arg) { 
   EiC_parseString( ":reset here" );
   LoadScript(ext_plugin->ext.filename);
   DEBUG_PrintMsg("executing plugin for  %s\n", ext_plugin->ext.filename);

   EiC_parseString( "void * unsafe plugin_arg @ %ld;", (long)plugin_arg);
   if (plugin_arg) EiC_parseString( "plugin_main(plugin_arg);");
   else EiC_parseString( "plugin_main(NULL);");

   EiCp_ResetStart();
   return(1);
}

/* ENGINE stubs */
int engine_main_stub(void *engine_arg) {
   disasm_env.flags &= IN_EIC;
   EiC_parseString( ":reset here" );
   LoadScript(ext_engine->ext.filename);
   DEBUG_PrintMsg("executing engine for  %s\n", ext_engine->ext.filename);

   EiC_parseString( "void * unsafe engine_arg @ %ld;", (long)engine_arg);
   if (engine_arg) EiC_parseString( "engine_main(engine_arg);");
   else EiC_parseString( "engine_main(NULL);");

   EiCp_ResetStart();
   disasm_env.flags &= ~IN_EIC;
   return(1);
}

/* FORMAT stubs */
int read_header_stub(void){
   int retval = 0;

   EiC_parseString( ":reset here" );
   LoadScript(ext_format->ext.filename);
   DEBUG_PrintMsg("executing ReadHeader for  %s\n", ext_format->ext.filename);

   EiC_parseString( "int rv @ %ld;", (long) &retval);
   EiC_parseString( "rv = read_header();" );
   EiCp_ResetStart();
   //sprintf(cmd, ":clear \"%s\"\n", script);
   return(retval);
}


/* ARCH stubs */
void arch_init_stub(void *param){
   EiC_parseString( ":reset here" );
   LoadScript( ext_arch->ext.filename );
   EiC_parseString( "void * unsafe arch_init_param @ %ld;", (long) param);
   EiC_parseString( "arch_init(arch_init_param);" );
   EiCp_ResetStart();
   return;
}
void arch_cleanup_stub(void){
   EiC_parseString( ":reset here" );
   EiC_parseString( "arch_cleanup( NULL);" );
   EiCp_ResetStart();
   return;
}

int disasm_addr_stub(unsigned char *c, unsigned char n, struct code *inst, long rva){
   EiC_parseString( ":reset here" );
   LoadScript(ext_arch->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_arch->ext.filename);

   EiC_parseString( "unsigned char * unsafe c @ %ld;", (long) c);
   EiC_parseString( "unsigned char n @ %ld;", (long) &n);
   EiC_parseString( "struct code * unsafe inst @ %ld;", (long) inst);
   EiC_parseString( "unsigned int rva @ %ld;", (long) &rva);
   EiC_parseString( "disasm_addr(c, n, inst, rva);");

   EiCp_ResetStart();
   return(1);
}

int get_prologue_stub(struct code **table){
   EiC_parseString( ":reset here" );
   LoadScript(ext_arch->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_arch->ext.filename);

   EiC_parseString( "char ** unsafe table @ %ld;", (long)table);
   EiC_parseString( "get_prologue(table);");

   EiCp_ResetStart();
   return(1);
}
int get_epilogue_stub(struct code **table){ 
   EiC_parseString( ":reset here" );
   LoadScript(ext_arch->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_arch->ext.filename);

   EiC_parseString( "char ** unsafe table @ %ld;", (long)table);
   EiC_parseString( "get_epilogue(table);");

   EiCp_ResetStart();
   return(1);
}
int gen_effect_stub(char *mnemonic, struct code_effect *e){ 
   EiC_parseString( ":reset here" );
   LoadScript(ext_arch->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_arch->ext.filename);

   EiC_parseString( "char * unsafe mnemonic @ %ld;", (long)mnemonic);
   EiC_parseString( "struct code_effect * unsafe e @ %ld;", (long)e);
   EiC_parseString( "get_reg_effect(mnemonic, e);");

   EiCp_ResetStart();
   return(1);
}
int gen_int_stub(int func_id){ 
   EiC_parseString( ":reset here" );
   LoadScript(ext_arch->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_arch->ext.filename);

   EiC_parseString( "int func_id @ %ld;", (long)&func_id);
   EiC_parseString( "gen_int(func_id);");

   EiCp_ResetStart();
   return(1);
}

/* ASM stubs */
void asm_init_stub(void *param){
   EiC_parseString( ":reset here" );
   LoadScript( ext_asm->ext.filename );
   EiC_parseString( "void * unsafe asm_init_param @ %ld;", (long) param);
   EiC_parseString( "asm_init(asm_init_param);" );
   EiCp_ResetStart();
   return;
}
void asm_cleanup_stub(void){
   EiC_parseString( ":reset here" );
   LoadScript( ext_asm->ext.filename );
   EiC_parseString( "asm_cleanup( NULL);" );
   EiCp_ResetStart();
}
int sprint_code_stub(long rva, char *buf, int len, int output) { 
   EiC_parseString( ":reset here" );
   LoadScript(ext_asm->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_asm->ext.filename);

   EiC_parseString( "long rva @ %ld;", (long)&rva);
   EiC_parseString( "char * unsafe buf @ %ld;", (long)buf);
   EiC_parseString( "int len @ %ld;", (long)&len);
   EiC_parseString( "int output @ %ld;", (long)&output);
   EiC_parseString( "sprint_code(rva, buf, len, output);");

   EiCp_ResetStart();
   return(1);
}
int sprint_func_start_stub( char *str, int len, int func_id) {
   EiC_parseString( ":reset here" );
   LoadScript(ext_asm->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_asm->ext.filename);

   EiC_parseString( "char * unsafe str @ %ld;", (long)str);
   EiC_parseString( "int len @ %ld;", (long)&len);
   EiC_parseString( "int func_id @ %ld;", (long)&func_id);
   EiC_parseString( "sprint_func_start(rvstr, len, func_id);");

   EiCp_ResetStart();
   return(1);
}
int sprint_func_end_stub( char *str, int len, int func_id) {
   EiC_parseString( ":reset here" );
   LoadScript(ext_asm->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_asm->ext.filename);

   EiC_parseString( "char * unsafe str @ %ld;", (long)str);
   EiC_parseString( "int len @ %ld;", (long)&len);
   EiC_parseString( "int func_id @ %ld;", (long)&func_id);
   EiC_parseString( "sprint_func_end(rvstr, len, func_id);");

   EiCp_ResetStart();
   return(1);
}
int sprint_struct_stub(char *str, int len, long rva) { 
   char cmd[2048], *script;

   EiC_parseString( ":reset here" );
   LoadScript(ext_asm->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_asm->ext.filename);

   EiC_parseString( "char * unsafe str @ %ld;", (long)str);
   EiC_parseString( "int len @ %ld;", (long)&len);
   EiC_parseString( "int rva @ %ld;", (long)&rva);
   EiC_parseString( "sprint_struct(str, len, rva);");

   EiCp_ResetStart();
   return(1);
}
int sprint_section_start_stub(char *str, int len, char *name) {
   char cmd[2048], *script;

   EiC_parseString( ":reset here" );
   LoadScript(ext_asm->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_asm->ext.filename);

   EiC_parseString( "char * unsafe str @ %ld;", (long)str);
   EiC_parseString( "int len @ %ld;", (long)&len);
   EiC_parseString( "char * unsafe name @ %ld;", (long)name);
   EiC_parseString( "sprint_section_start(str, len, name);");

   EiCp_ResetStart();
   return(1);
}
int sprint_section_end_stub(char *str, int len, char *name) {
   char cmd[2048], *script;

   EiC_parseString( ":reset here" );
   LoadScript(ext_asm->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_asm->ext.filename);

   EiC_parseString( "char * unsafe str @ %ld;", (long)str);
   EiC_parseString( "int len @ %ld;", (long)&len);
   EiC_parseString( "char * unsafe name @ %ld;", (long)name);
   EiC_parseString( "sprint_section_end(str, len, name);");

   EiCp_ResetStart();
   return(1);
}

int gen_asmfile_stub( char *path ) {
   EiC_parseString( ":reset here" );
   LoadScript(ext_asm->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_asm->ext.filename);

   EiC_parseString( "char * unsafe path @ %ld;", (long)path);
   EiC_parseString( "gen_file(path);");

   EiCp_ResetStart();
   return(1);
}

int sprint_addrexp_stub(char *buf, int len, char *scale, char *index, char *base,
                     char *disp, int sign){
   char cmd[2048], *script;

   EiC_parseString( ":reset here" );
   LoadScript(ext_asm->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_asm->ext.filename);


   EiC_parseString( "char * unsafe buf @ %ld;", (long) buf);
   EiC_parseString( "int len @ %ld;", (long) &len);
   EiC_parseString( "char * unsafe scale @ %ld;", (long) scale);
   EiC_parseString( "char * unsafe index @ %ld;", (long) index);
   EiC_parseString( "char * unsafe base @ %ld;", (long) base);
   EiC_parseString( "char * unsafe disp @ %ld;", (long) disp);
   EiC_parseString( "int sign @ %ld;", (long) &sign);
   EiC_parseString( "sprint_addrexp(buf, len, scale, index, base, disp, sign);");

   EiCp_ResetStart();
   return(1);
}

/* LANG stubs */
void lang_init_stub(void *param){
   EiC_parseString( ":reset here" );
   LoadScript( ext_lang->ext.filename );
   EiC_parseString( "void * unsafe lang_init_param @ %ld;", (long) param);
   EiC_parseString( "lang_init(lang_init_param);" );
   EiCp_ResetStart();
   return;
}
void lang_cleanup_stub(void){
   EiC_parseString( ":reset here" );
   LoadScript(ext_lang->ext.filename);
   EiC_parseString( "lang_cleanup( NULL);" );
   EiCp_ResetStart();
   return;
}
int findstr_stub(char *buf, char *text, int text_len, int type){
   EiC_parseString( ":reset here" );
   LoadScript(ext_lang->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_lang->ext.filename);

   EiC_parseString( "char * unsafe buf @ %ld;", (long) buf);
   EiC_parseString( "char * unsafe text @ %ld;", (long) text);
   EiC_parseString( "int text_len @ %ld;", (long) &text_len);
   EiC_parseString( "int type @ %ld;", (long) &type);
   EiC_parseString( "findstr(buf, text, text_len, type);");
   EiCp_ResetStart();
   return(1);
}
int datatype_stub(int mach_word){
   /* mach_word is 4 on 32-bit machines, 8 on 64, etc */
   EiC_parseString( ":reset here" );
   LoadScript(ext_lang->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_lang->ext.filename);

   EiC_parseString( "int mach_word @ %ld;", (long)&mach_word);
   EiC_parseString( "add_data_types(mach_word);");

   EiCp_ResetStart();
   return(1);
}
int makestr_stub(char *buf, int len, int *pos, char *text, int text_len,int type){
   EiC_parseString( ":reset here" );
   LoadScript(ext_lang->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_lang->ext.filename);

   EiC_parseString( "char * unsafe buf @ %ld;", (long) buf);
   EiC_parseString( "int len @ %ld;", (long) &len);
   EiC_parseString( "int * unsafe pos @ %ld;", (long) pos);
   EiC_parseString( "char * unsafe text @ %ld;", (long) text);
   EiC_parseString( "int text_len @ %ld;", (long) &text_len);
   EiC_parseString( "int type @ %ld;", (long) &type);
   EiC_parseString( "makestr(buf, len, pos, text, text_len, type);");

   EiCp_ResetStart();
   return(1);
}
int sprint_proto_stub(char *buf, int len, int func_id){
   EiC_parseString( ":reset here" );
   LoadScript(ext_lang->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_lang->ext.filename);

   EiC_parseString( "char * unsafe buf @ %ld;", (long)buf);
   EiC_parseString( "int len @ %ld;", (long)&len);
   EiC_parseString( "int func_id @ %ld;", (long)&func_id);
   EiC_parseString( "sprint_proto(buf, len, func_id);");

   EiCp_ResetStart();
   return(1);
}
int sprint_func_stub(char *buf, int len, int func_id){
   EiC_parseString( ":reset here" );
   LoadScript(ext_lang->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_lang->ext.filename);

   EiC_parseString( "char * unsafe buf @ %ld;", (long)buf);
   EiC_parseString( "int len @ %ld;", (long)&len);
   EiC_parseString( "int func_id @ %ld;", (long)&func_id);
   EiC_parseString( "sprint_func(buf, len, func_id);");

   EiCp_ResetStart();
   return(1);
}
int gen_final_stub(int func_id){
   EiC_parseString( ":reset here" );
   LoadScript(ext_lang->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_lang->ext.filename);

   EiC_parseString( "int func_id @ %ld;", (long)&func_id);
   EiC_parseString( "gen_final(func_id);");

   EiCp_ResetStart();
   return(1);
}
int gen_hllfile_stub( char *path) {
   EiC_parseString( ":reset here" );
   LoadScript(ext_lang->ext.filename);
   DEBUG_PrintMsg("executing %s\n", ext_lang->ext.filename);

   EiC_parseString( "char * unsafe path @ %ld;", (long)path);
   EiC_parseString( "gen_file(path);");

   EiCp_ResetStart();
   return(1);
}

/* safety wrappers -- called by routines outside of this file */
int ext_plugin_main(void *param){
   if (ext_plugin->fn_main) return((*ext_plugin->fn_main)(param));
   return(0);
}

int ext_engine_main(void *param){
   if (ext_engine->fn_main) return((*ext_engine->fn_main)(param));
   return(0);
}

int ext_disasm_addr(char *buf, char tbl, struct code *c, long rva){
   if (ext_arch->fn_disasm_addr)
      return((*ext_arch->fn_disasm_addr)(buf, tbl, c, rva));
   return(0);
}

int ext_get_prologue(struct code **table){
   if (ext_arch->fn_get_prologue)
      return((*ext_arch->fn_get_prologue)(table));
   return(0);
}

int ext_get_epilogue(struct code **table){
   if (ext_arch->fn_get_epilogue)
      return((*ext_arch->fn_get_epilogue)(table));
   return(0);
}

int ext_gen_effect(char *mnemonic, struct code_effect *e){
   if (ext_arch->fn_gen_effect)
      return((*ext_arch->fn_gen_effect)(mnemonic, e));
   return(0);
}

int ext_gen_int(int func_id){
   if (ext_arch->fn_gen_int)
      return((*ext_arch->fn_gen_int)(func_id));
   return(0);
}

int ext_add_data_types(int mach_word){
   if (ext_lang->fn_datatype)
      return((*ext_lang->fn_datatype)(mach_word));
   return(0);
}

int ext_findstr(char *buf, int len, int *pos, char *text, int text_len, 
                int type) {
   if (ext_lang->fn_findstr)
      return( (*ext_lang->fn_findstr)(buf, len, pos, text, text_len, type));
   return(0);
}

int ext_makestr(char *buf, char *text, int text_len, int type){
   if (ext_lang->fn_makestr)
      return((*ext_lang->fn_makestr)(buf, text, text_len, type));
   return(0);
}

int ext_sprint_hll_proto(char *buf, int len, int func_id){
   if (ext_lang->fn_sprint_proto)
      return((*ext_lang->fn_sprint_proto)(buf, len, func_id));
   return(0);
}

int ext_sprint_hll_func(char *buf, int len, int func_id){
   if (ext_lang->fn_sprint_func)
      return((*ext_lang->fn_sprint_func)(buf, len, func_id));
   return(0);
}

int ext_gen_final(int func_id){
   if (ext_lang->fn_gen_final)
      return((*ext_lang->fn_gen_final)(func_id));
   return(0);
}

int ext_gen_hll_file(char *path){
   if (ext_lang->fn_gen_file)
      return((*ext_lang->fn_gen_file)(path));
   return(0);
}
int ext_read_header(void){
   if (ext_format->fn_read_header){
      (*ext_format->fn_read_header)();
      return(1);
   }
   return(0);
}
int ext_sprint_code(long rva, char *line, int len, int output){
   if (ext_asm->fn_sprint_code)
      return((*ext_asm->fn_sprint_code)(rva, line, len, output));
   return(0);
}
int ext_sprint_addrexp(char *str, int len, char *scale, char *index, 
                       char *base, char *disp, int sign){
   if (ext_asm->fn_sprint_addrexp)
      return((*ext_asm->fn_sprint_addrexp)(str, len, scale, index, base, 
                                           disp, sign));
   return(0);
}
int ext_sprint_asm_func_start(char *str, int len, int func_id){
   if ( ext_asm->fn_sprint_func_s )
      return((*ext_asm->fn_sprint_func_s)(str, len, func_id));
   return(0);
}
int ext_sprint_asm_func_end(char *str, int len, int func_id){
   if ( ext_asm->fn_sprint_func_e )
      return((*ext_asm->fn_sprint_func_e)(str, len, func_id));
   return(0);
}
int ext_sprint_asm_struct(char *str, int len, long rva) {
   if (ext_asm->fn_sprint_struct)
      return((*ext_asm->fn_sprint_struct)(str, len, rva));
   return(0);
}
int ext_sprint_sec_start(char *str, int len, char *name){
   if (ext_asm->fn_sprint_sec_s)
      return((*ext_asm->fn_sprint_sec_s)(str, len, name));
   return(0);
}
int ext_sprint_sec_end(char *str, int len, char *name){
   if (ext_asm->fn_sprint_sec_e)
      return((*ext_asm->fn_sprint_sec_e)(str, len, name));
   return(0);
}

int ext_gen_asm_file(char *path){
   if (ext_asm->fn_gen_file)
      return((*ext_asm->fn_gen_file)(path));
   return(0);
}

