56f4f42001-09-18Fredrik Hübinette (Hubbe) #ifdef TESTING #define NO_PIKE_INCLUDES #define CREATE_MAIN #define NO_PIKE_GUTS #endif #ifndef NO_PIKE_INCLUDES
e1195f1997-03-23Fredrik Hübinette (Hubbe) # include "global.h" # include "interpret.h" # include "constants.h"
b2d3e42000-12-01Fredrik Hübinette (Hubbe) # include "pike_error.h"
e1195f1997-03-23Fredrik Hübinette (Hubbe) # include "module.h" # include "stralloc.h" # include "pike_macros.h"
6559821999-02-01Per Hedbor # include "main.h"
c39e432001-08-02Fredrik Hübinette (Hubbe) # include "constants.h"
37b0222002-01-31Marcus Comstedt # include "language.h" # include "lex.h"
24ddc71998-03-28Henrik Grubbström (Grubba) 
37b0222002-01-31Marcus Comstedt RCSID("$Id: dynamic_load.c,v 1.59 2002/01/31 17:52:14 marcus Exp $");
ecf1552001-09-10Henrik Grubbström (Grubba)  #else /* TESTING */ #include <stdio.h>
24ddc71998-03-28Henrik Grubbström (Grubba) 
79f71c1998-07-09Francesco Chemolli #endif /* !TESTING */ #ifdef HAVE_ERRNO_H #include <errno.h> #endif /* HAVE_ERRNO_H */ #ifdef HAVE_STRING_H #include <string.h> #endif /* HAVE_STRING_H */
ca74dd1996-10-08Fredrik Hübinette (Hubbe) 
9649491998-02-27Fredrik Hübinette (Hubbe) #if !defined(HAVE_DLOPEN) #if defined(HAVE_DLD_LINK) && defined(HAVE_DLD_GET_FUNC)
7860031997-01-22Bernhard Fastenrath #define USE_DLD
9649491998-02-27Fredrik Hübinette (Hubbe) #define HAVE_SOME_DLOPEN #define EMULATE_DLOPEN #else
79f71c1998-07-09Francesco Chemolli #if defined(HAVE_SHL_LOAD) && defined(HAVE_DL_H) #define USE_HPUX_DL #define HAVE_SOME_DLOPEN #define EMULATE_DLOPEN #else
1c0ff32000-12-18Fredrik Hübinette (Hubbe)  #if 0
9649491998-02-27Fredrik Hübinette (Hubbe) #if defined(HAVE_LOADLIBRARY) && defined(HAVE_FREELIBRARY) && \ defined(HAVE_GETPROCADDRESS) && defined(HAVE_WINBASE_H) #define USE_LOADLIBRARY #define HAVE_SOME_DLOPEN #define EMULATE_DLOPEN #endif
1c0ff32000-12-18Fredrik Hübinette (Hubbe) #endif /* 0 */
ecf1552001-09-10Henrik Grubbström (Grubba) #ifdef HAVE_MACH_O_DYLD_H /* MacOS X... */ #define USE_DYLD #define HAVE_SOME_DLOPEN #define EMULATE_DLOPEN #else /* !HAVE_MACH_O_DYLD_H */
9b15e02000-12-22Fredrik Hübinette (Hubbe) #ifdef USE_MY_WIN32_DLOPEN #include "pike_dlfcn.h" #define HAVE_SOME_DLOPEN #define HAVE_DLOPEN #endif
ecf1552001-09-10Henrik Grubbström (Grubba) #endif /* HAVE_MACH_O_DYLD_H */
9b15e02000-12-22Fredrik Hübinette (Hubbe) 
9649491998-02-27Fredrik Hübinette (Hubbe) #endif
79f71c1998-07-09Francesco Chemolli #endif
9649491998-02-27Fredrik Hübinette (Hubbe) #else #define HAVE_SOME_DLOPEN
7860031997-01-22Bernhard Fastenrath #endif
9649491998-02-27Fredrik Hübinette (Hubbe)  #ifdef HAVE_SOME_DLOPEN
2631a61996-10-09Fredrik Hübinette (Hubbe) 
e1195f1997-03-23Fredrik Hübinette (Hubbe) typedef void (*modfun)(void);
9649491998-02-27Fredrik Hübinette (Hubbe) #ifdef USE_LOADLIBRARY #include <windows.h>
c7241b2000-08-10Henrik Grubbström (Grubba) static TCHAR *convert_string(const char *str, ptrdiff_t len)
9649491998-02-27Fredrik Hübinette (Hubbe) {
c7241b2000-08-10Henrik Grubbström (Grubba)  ptrdiff_t e;
9649491998-02-27Fredrik Hübinette (Hubbe)  TCHAR *ret=(TCHAR *)xalloc((len+1) * sizeof(TCHAR)); for(e=0;e<len;e++) ret[e]=EXTRACT_UCHAR(str+e); ret[e]=0; return ret; }
01a9572000-02-03Henrik Grubbström (Grubba) static void *dlopen(const char *foo, int how)
9649491998-02-27Fredrik Hübinette (Hubbe) { TCHAR *tmp; HINSTANCE ret; tmp=convert_string(foo, strlen(foo)); ret=LoadLibrary(tmp); free((char *)tmp);
1f21332000-07-28Fredrik Hübinette (Hubbe)  if(ret) { void ** psym=(void **)GetProcAddress(ret, "PikeSymbol"); if(psym) { extern void *PikeSymbol[]; *psym = PikeSymbol; } }
9649491998-02-27Fredrik Hübinette (Hubbe)  return (void *)ret; } static char * dlerror(void) { static char buffer[200];
a4a1722000-12-05Per Hedbor  sprintf(buffer,"LoadLibrary failed with error: %d",GetLastError());
9649491998-02-27Fredrik Hübinette (Hubbe)  return buffer; } static void *dlsym(void *module, char * function) { return (void *)GetProcAddress((HMODULE)module, function); } static void dlclose(void *module) { FreeLibrary((HMODULE)module); }
ecf1552001-09-10Henrik Grubbström (Grubba) #define dlinit() 1
9649491998-02-27Fredrik Hübinette (Hubbe) 
79f71c1998-07-09Francesco Chemolli #endif /* USE_LOADLIBRARY */
9649491998-02-27Fredrik Hübinette (Hubbe) 
e1195f1997-03-23Fredrik Hübinette (Hubbe) #ifdef USE_DLD #include <dld.h>
01a9572000-02-03Henrik Grubbström (Grubba) static void *dlopen(const char *module_name, int how)
e1195f1997-03-23Fredrik Hübinette (Hubbe) { dld_create_reference("pike_module_init"); if(dld_link(module_name)) { return (void *)strdup(module_name); }else{ return 0; } } static char *dlerror(void) { return dld_strerror(dld_errno); } static void *dlsym(void *module, char *function) { return dld_get_func(function); } static void *dlclose(void *module) { if(!module) return; dld_unlink_by_file((char *)module); free(module); }
ecf1552001-09-10Henrik Grubbström (Grubba) static int dlinit(void)
e1195f1997-03-23Fredrik Hübinette (Hubbe) { extern char ** ARGV; if(dld_init(dld_find_executable(ARGV[0]))) { fprintf(stderr,"Failed to init dld\n");
ecf1552001-09-10Henrik Grubbström (Grubba)  return 0;
e1195f1997-03-23Fredrik Hübinette (Hubbe)  }
ecf1552001-09-10Henrik Grubbström (Grubba)  /* OK */ return 1;
e1195f1997-03-23Fredrik Hübinette (Hubbe) }
79f71c1998-07-09Francesco Chemolli #endif /* USE_DLD */ #ifdef USE_HPUX_DL #include <dl.h>
513a2b1998-07-09Henrik Grubbström (Grubba) #if defined(BIND_VERBOSE)
79f71c1998-07-09Francesco Chemolli #define RTLD_NOW BIND_IMMEDIATE | BIND_VERBOSE #else #define RTLD_NOW BIND_IMMEDIATE
513a2b1998-07-09Henrik Grubbström (Grubba) #endif /* BIND_VERBOSE */
79f71c1998-07-09Francesco Chemolli  extern int errno;
01a9572000-02-03Henrik Grubbström (Grubba) static void *dlopen(const char *libname, int how)
79f71c1998-07-09Francesco Chemolli { shl_t lib; lib = shl_load(libname, how, 0L); return (void *)lib; }
e1195f1997-03-23Fredrik Hübinette (Hubbe) 
79f71c1998-07-09Francesco Chemolli static char *dlerror(void) { #ifdef HAVE_STRERROR return strerror(errno); #else return ""; /* I hope it's better than null..*/
9649491998-02-27Fredrik Hübinette (Hubbe) #endif
79f71c1998-07-09Francesco Chemolli } static void *dlsym(void *module, char *function) { void *func; int result; shl_t mod = (shl_t)module; result = shl_findsym(&mod, function, TYPE_UNDEFINED, &func); if (result == -1) return NULL; return func; } static void dlclose(void *module) { shl_unload((shl_t)module); }
ecf1552001-09-10Henrik Grubbström (Grubba) #define dlinit() 1
79f71c1998-07-09Francesco Chemolli  #endif /* USE_HPUX_DL */
ecf1552001-09-10Henrik Grubbström (Grubba) #ifdef USE_DYLD #include <mach-o/dyld.h> #define RTLD_NOW NSLINKMODULE_OPTION_BINDNOW #define dlinit() _dyld_present() static void *dlopen(const char *module_name, int how) { NSObjectFileImageReturnCode code = 0; NSObjectFileImage image = NULL; if ((code = NSCreateObjectFileImageFromFile(module_name, &image)) != NSObjectFileImageSuccess) { fprintf(stderr, "NSCreateObjectFileImageFromFile(\"%s\") failed with %d\n", module_name, code); return NULL; } /* FIXME: image should be freed somewhere! */ return NSLinkModule(image, module_name, how | NSLINKMODULE_OPTION_RETURN_ON_ERROR); } static char *dlerror(void) { NSLinkEditErrors class = 0; int error_number = 0; char *file_name = NULL; char *error_string = NULL; NSLinkEditError(&class, &error_number, &file_name, &error_string); return error_string; } static void *dlsym(void *module, char *function) { return NSLookupSymbolInModule(module, function); } static void *dlclose(void *module) { NSUnLinkModule(module, NSUNLINKMODULE_OPTION_NONE); return NULL; } #endif /* USE_DYLD */
9649491998-02-27Fredrik Hübinette (Hubbe)  #ifndef EMULATE_DLOPEN
2631a61996-10-09Fredrik Hübinette (Hubbe) #ifdef HAVE_DLFCN_H
ca74dd1996-10-08Fredrik Hübinette (Hubbe) #include <dlfcn.h>
2631a61996-10-09Fredrik Hübinette (Hubbe) #endif
ca74dd1996-10-08Fredrik Hübinette (Hubbe) 
ecf1552001-09-10Henrik Grubbström (Grubba) #define dlinit() 1
79f71c1998-07-09Francesco Chemolli #endif /* !EMULATE_DLOPEN */
7860031997-01-22Bernhard Fastenrath 
58dd661998-09-18Fredrik Hübinette (Hubbe) #endif /* HAVE_SOME_DLOPEN */
e1195f1997-03-23Fredrik Hübinette (Hubbe) #ifndef RTLD_NOW #define RTLD_NOW 0 #endif
5aeade1999-02-01Per Hedbor #ifndef RTLD_LAZY #define RTLD_LAZY 0 #endif #ifndef RTLD_GLOBAL #define RTLD_GLOBAL 0 #endif
56f4f42001-09-18Fredrik Hübinette (Hubbe) #ifndef NO_PIKE_GUTS
e1195f1997-03-23Fredrik Hübinette (Hubbe) 
1f21332000-07-28Fredrik Hübinette (Hubbe) #if defined(HAVE_DLOPEN) || defined(USE_DLD) || defined(USE_HPUX_DL) || defined(USE_LOADLIBRARY)
e00cc82000-09-29Martin Stjernholm #define USE_DYNAMIC_MODULES #endif #ifdef USE_DYNAMIC_MODULES
6cf83a1997-02-06Fredrik Hübinette (Hubbe) 
ca74dd1996-10-08Fredrik Hübinette (Hubbe) struct module_list { struct module_list * next;
368fe71997-01-26Fredrik Hübinette (Hubbe)  void *module;
6cf83a1997-02-06Fredrik Hübinette (Hubbe)  modfun init, exit;
368fe71997-01-26Fredrik Hübinette (Hubbe) }; struct module_list *dynamic_module_list = 0;
418a371999-04-25Henrik Grubbström (Grubba) #ifdef NO_CAST_TO_FUN /* Function pointers can't be casted to scalar pointers according to * ISO-C (probably to support true Harward achitecture machines). */ static modfun CAST_TO_FUN(void *ptr) { union { void *ptr; modfun fun; } u; u.ptr = ptr; return u.fun; } #else /* !NO_CAST_TO_FUN */ #define CAST_TO_FUN(X) ((modfun)X) #endif /* NO_CAST_TO_FUN */
37b0222002-01-31Marcus Comstedt struct compilation_save { struct lex lex; int compilation_depth; }; static void cleanup_compilation(struct compilation_save *save)
fc29cf2002-01-30Marcus Comstedt { free_program(end_program());
37b0222002-01-31Marcus Comstedt  free_string(lex.current_file); compilation_depth = save->compilation_depth; lex = save->lex;
fc29cf2002-01-30Marcus Comstedt }
7c0df72001-02-06Henrik Grubbström (Grubba) /*! @decl int load_module(string module_name) *! *! Load a binary module. *! *! This function loads a module written in C or some other language *! into Pike. The module is initialized and any programs or constants *! defined will immediately be available. *! *! When a module is loaded the function @tt{pike_module_init()@} will *! be called to initialize it. When Pike exits @tt{pike_module_exit()@} *! will be called. These two functions @b{must@} be available in the module. *! *! @note *! The current working directory is normally not searched for *! dynamic modules. Please use @tt{"./name.so"@} instead of just *! @tt{"name.so"@} to load modules from the current directory. */
368fe71997-01-26Fredrik Hübinette (Hubbe) void f_load_module(INT32 args) {
9552622001-09-10Fredrik Hübinette (Hubbe)  extern int compilation_depth; extern int global_callable_flags;
ca74dd1996-10-08Fredrik Hübinette (Hubbe)  void *module;
6cf83a1997-02-06Fredrik Hübinette (Hubbe)  modfun init, exit;
368fe71997-01-26Fredrik Hübinette (Hubbe)  struct module_list *new_module; const char *module_name;
fc29cf2002-01-30Marcus Comstedt  ONERROR err;
37b0222002-01-31Marcus Comstedt  struct compilation_save save;
9552622001-09-10Fredrik Hübinette (Hubbe) 
368fe71997-01-26Fredrik Hübinette (Hubbe)  if(sp[-args].type != T_STRING)
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Bad argument 1 to load_module()\n");
368fe71997-01-26Fredrik Hübinette (Hubbe)  module_name = sp[-args].u.string->str;
0819302000-02-17Fredrik Hübinette (Hubbe)  /* Removing RTLD_GLOBAL breaks some PiGTK themes - Hubbe */
8bff492000-09-26Fredrik Hübinette (Hubbe)  /* Using RTLD_LAZY is faster, but makes it impossible to * detect linking problems at runtime.. */
5aeade1999-02-01Per Hedbor  module=dlopen(module_name,
8bff492000-09-26Fredrik Hübinette (Hubbe)  RTLD_NOW |RTLD_GLOBAL );
ef78b01997-11-03Henrik Grubbström (Grubba) 
368fe71997-01-26Fredrik Hübinette (Hubbe)  if(!module) {
466a321997-09-07Henrik Grubbström (Grubba)  const char *err = dlerror();
e1195f1997-03-23Fredrik Hübinette (Hubbe)  if(!err) err = "Unknown reason";
14160c1998-05-15Henrik Grubbström (Grubba)  if (sp[-args].u.string->len < 1024) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("load_module(\"%s\") failed: %s\n",
14160c1998-05-15Henrik Grubbström (Grubba)  sp[-args].u.string->str, err); } else {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("load_module() failed: %s\n", err);
14160c1998-05-15Henrik Grubbström (Grubba)  }
368fe71997-01-26Fredrik Hübinette (Hubbe)  }
418a371999-04-25Henrik Grubbström (Grubba)  init = CAST_TO_FUN(dlsym(module, "pike_module_init"));
fb84a71997-03-04Henrik Grubbström (Grubba)  if (!init) {
418a371999-04-25Henrik Grubbström (Grubba)  init = CAST_TO_FUN(dlsym(module, "_pike_module_init"));
fb84a71997-03-04Henrik Grubbström (Grubba)  }
418a371999-04-25Henrik Grubbström (Grubba)  exit = CAST_TO_FUN(dlsym(module, "pike_module_exit"));
fb84a71997-03-04Henrik Grubbström (Grubba)  if (!exit) {
418a371999-04-25Henrik Grubbström (Grubba)  exit = CAST_TO_FUN(dlsym(module, "_pike_module_exit"));
fb84a71997-03-04Henrik Grubbström (Grubba)  }
368fe71997-01-26Fredrik Hübinette (Hubbe)  if(!init || !exit) { dlclose(module);
14160c1998-05-15Henrik Grubbström (Grubba) 
b2b8951998-05-15Henrik Grubbström (Grubba)  if (strlen(module_name) < 1024) {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Failed to initialize dynamic module \"%s\".\n", module_name);
14160c1998-05-15Henrik Grubbström (Grubba)  } else {
b2d3e42000-12-01Fredrik Hübinette (Hubbe)  Pike_error("Failed to initialize dynamic module.\n");
14160c1998-05-15Henrik Grubbström (Grubba)  }
368fe71997-01-26Fredrik Hübinette (Hubbe)  } new_module=ALLOC_STRUCT(module_list); new_module->next=dynamic_module_list; dynamic_module_list=new_module; new_module->module=module;
6cf83a1997-02-06Fredrik Hübinette (Hubbe)  new_module->init=init; new_module->exit=exit;
368fe71997-01-26Fredrik Hübinette (Hubbe) 
37b0222002-01-31Marcus Comstedt  save.lex = lex; lex.current_line=1; lex.current_file=make_shared_string("-"); save.compilation_depth=compilation_depth;
9552622001-09-10Fredrik Hübinette (Hubbe)  compilation_depth=-1;
368fe71997-01-26Fredrik Hübinette (Hubbe)  start_new_program();
c39e432001-08-02Fredrik Hübinette (Hubbe) 
9552622001-09-10Fredrik Hübinette (Hubbe)  global_callable_flags|=CALLABLE_DYNAMIC;
c39e432001-08-02Fredrik Hübinette (Hubbe) 
044c621999-04-14Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG { struct svalue *save_sp=sp; #endif
37b0222002-01-31Marcus Comstedt  SET_ONERROR(err, cleanup_compilation, &save);
6cf83a1997-02-06Fredrik Hübinette (Hubbe)  (*(modfun)init)();
fc29cf2002-01-30Marcus Comstedt  UNSET_ONERROR(err);
044c621999-04-14Fredrik Hübinette (Hubbe) #ifdef PIKE_DEBUG if(sp != save_sp)
6f95902000-08-17Henrik Grubbström (Grubba)  fatal("load_module(%s) left %ld droppings on stack!\n",
044c621999-04-14Fredrik Hübinette (Hubbe)  module_name,
6f95902000-08-17Henrik Grubbström (Grubba)  PTRDIFF_T_TO_LONG(sp - save_sp));
044c621999-04-14Fredrik Hübinette (Hubbe)  } #endif
6cf83a1997-02-06Fredrik Hübinette (Hubbe) 
044c621999-04-14Fredrik Hübinette (Hubbe)  pop_n_elems(args);
6cf83a1997-02-06Fredrik Hübinette (Hubbe)  push_program(end_program());
37b0222002-01-31Marcus Comstedt  free_string(lex.current_file); compilation_depth = save.compilation_depth; lex = save.lex;
368fe71997-01-26Fredrik Hübinette (Hubbe) }
e00cc82000-09-29Martin Stjernholm #endif /* USE_DYNAMIC_MODULES */
368fe71997-01-26Fredrik Hübinette (Hubbe) 
e1195f1997-03-23Fredrik Hübinette (Hubbe) void init_dynamic_load(void)
368fe71997-01-26Fredrik Hübinette (Hubbe) {
e00cc82000-09-29Martin Stjernholm #ifdef USE_DYNAMIC_MODULES
ecf1552001-09-10Henrik Grubbström (Grubba)  if (dlinit()) {
45ee5d1999-02-10Fredrik Hübinette (Hubbe) 
ecf1552001-09-10Henrik Grubbström (Grubba)  /* function(string:program) */
1f21332000-07-28Fredrik Hübinette (Hubbe) 
ecf1552001-09-10Henrik Grubbström (Grubba)  ADD_EFUN("load_module", f_load_module, tFunc(tStr,tPrg(tObj)), OPT_EXTERNAL_DEPEND); }
368fe71997-01-26Fredrik Hübinette (Hubbe) #endif }
da667d2000-09-28Henrik Grubbström (Grubba) /* Call the pike_module_exit() callbacks for the dynamic modules. */
be478c1997-08-30Henrik Grubbström (Grubba) void exit_dynamic_load(void)
368fe71997-01-26Fredrik Hübinette (Hubbe) {
e00cc82000-09-29Martin Stjernholm #ifdef USE_DYNAMIC_MODULES struct module_list *tmp;
fc29cf2002-01-30Marcus Comstedt  JMP_BUF recovery;
e00cc82000-09-29Martin Stjernholm  for (tmp = dynamic_module_list; tmp; tmp = tmp->next)
fc29cf2002-01-30Marcus Comstedt  { if(SETJMP(recovery)) call_handle_error(); else (*tmp->exit)(); UNSETJMP(recovery); }
da667d2000-09-28Henrik Grubbström (Grubba) #endif } /* Unload all the dynamically loaded modules. */ void free_dynamic_load(void) {
e00cc82000-09-29Martin Stjernholm #ifdef USE_DYNAMIC_MODULES
da667d2000-09-28Henrik Grubbström (Grubba)  while(dynamic_module_list) { struct module_list *tmp=dynamic_module_list; dynamic_module_list=tmp->next;
3c0c281998-01-26Fredrik Hübinette (Hubbe) #ifndef DEBUG_MALLOC
368fe71997-01-26Fredrik Hübinette (Hubbe)  dlclose(tmp->module);
3c0c281998-01-26Fredrik Hübinette (Hubbe) #endif
368fe71997-01-26Fredrik Hübinette (Hubbe)  free((char *)tmp); }
7860031997-01-22Bernhard Fastenrath #endif
368fe71997-01-26Fredrik Hübinette (Hubbe) }
56f4f42001-09-18Fredrik Hübinette (Hubbe) #endif /* NO_PIKE_GUTS */ #ifdef CREATE_MAIN
e1195f1997-03-23Fredrik Hübinette (Hubbe) #include <stdio.h>
368fe71997-01-26Fredrik Hübinette (Hubbe) 
e1195f1997-03-23Fredrik Hübinette (Hubbe) int main()
368fe71997-01-26Fredrik Hübinette (Hubbe) {
e1195f1997-03-23Fredrik Hübinette (Hubbe)  void *module,*fun;
618bdd2001-11-26Henrik Grubbström (Grubba)  if (!dlinit()) { fprintf(stderr, "dlinit() failed.\n"); exit(1); }
e1195f1997-03-23Fredrik Hübinette (Hubbe)  module=dlopen("./myconftest.so",RTLD_NOW); if(!module)
ca74dd1996-10-08Fredrik Hübinette (Hubbe)  {
e1195f1997-03-23Fredrik Hübinette (Hubbe)  fprintf(stderr,"Failed to link myconftest.so: %s\n",dlerror()); exit(1);
a69b791996-12-28Henrik Grubbström (Grubba)  }
e1195f1997-03-23Fredrik Hübinette (Hubbe)  fun=dlsym(module,"testfunc"); if(!fun) fun=dlsym(module,"_testfunc"); if(!fun)
ca74dd1996-10-08Fredrik Hübinette (Hubbe)  {
e1195f1997-03-23Fredrik Hübinette (Hubbe)  fprintf(stderr,"Failed to find function testfunc: %s\n",dlerror()); exit(1);
ca74dd1996-10-08Fredrik Hübinette (Hubbe)  }
a991451997-07-08Fredrik Hübinette (Hubbe)  fprintf(stderr,"Calling testfunc\n");
e1195f1997-03-23Fredrik Hübinette (Hubbe)  ((void (*)(void))fun)();
a991451997-07-08Fredrik Hübinette (Hubbe)  fprintf(stderr,"testfunc returned!\n");
e1195f1997-03-23Fredrik Hübinette (Hubbe)  exit(1);
ca74dd1996-10-08Fredrik Hübinette (Hubbe) }
56f4f42001-09-18Fredrik Hübinette (Hubbe) #endif /* CREATE_MAIN */