home *** CD-ROM | disk | FTP | other *** search
/ ftp.cs.arizona.edu / ftp.cs.arizona.edu.tar / ftp.cs.arizona.edu / icon / historic / v941.tgz / icon.v941src.tar / icon.v941src / src / runtime / fload.r < prev    next >
Text File  |  2001-12-12  |  6KB  |  224 lines

  1. /*
  2.  * File: fload.r
  3.  *  Contents: loadfunc.
  4.  *
  5.  *  This file contains loadfunc(), the dynamic loading function for
  6.  *  Unix systems having the <dlfcn.h> interface.
  7.  *
  8.  *  from Icon:
  9.  *     p := loadfunc(filename, funcname)
  10.  *     p(arg1, arg2, ...)
  11.  *
  12.  *  in C:
  13.  *     int func(int argc, dptr argv)
  14.  *        return -1 for failure, 0 for success, >0 for error
  15.  *        argc is number of true args not including argv[0]
  16.  *        argv[0] is for return value; others are true args
  17.  */
  18.  
  19. #ifdef LoadFunc
  20.  
  21. #ifndef RTLD_LAZY    /* normally from <dlfcn.h> */
  22. #define RTLD_LAZY 1
  23. #endif                    /* RTLD_LAZY */
  24.  
  25. #ifdef FreeBSD
  26.    /*
  27.     * If DL_GETERRNO exists, this is an FreeBSD 1.1.5 or 2.0
  28.     * which lacks dlerror(); supply a substitute.
  29.     */
  30.    #passthru #ifdef DL_GETERRNO
  31.       char *dlerror(void)
  32.       {
  33.          int no;
  34.  
  35.          if (0 == dlctl(NULL, DL_GETERRNO, &no))
  36.             return(strerror(no));
  37.          else
  38.             return(NULL);
  39.       }
  40.    #passthru #endif
  41. #endif                    /* __FreeBSD__ */
  42.  
  43. int glue();
  44. int makefunc    (dptr d, char *name, int (*func)());
  45.  
  46. "loadfunc(filename,funcname) - load C function dynamically."
  47.  
  48. function{0,1} loadfunc(filename,funcname)
  49.  
  50.    if !cnv:C_string(filename) then
  51.       runerr(103, filename)
  52.    if !cnv:C_string(funcname) then
  53.       runerr(103, funcname)
  54.  
  55.    abstract {
  56.       return proc
  57.       }
  58.    body
  59.       {
  60.       int (*func)();
  61.       static char *curfile;
  62.       static void *handle;
  63.       char *funcname2;
  64.  
  65.       /*
  66.        * Get a library handle, reusing it over successive calls.
  67.        */
  68.       if (!handle || !curfile || strcmp(filename, curfile) != 0) {
  69.          if (curfile)
  70.             free((pointer)curfile);    /* free the old file name */
  71.          curfile = salloc(filename);    /* save the new name */
  72.          handle = dlopen(filename, RTLD_LAZY);    /* get the handle */
  73.          }
  74.       /*
  75.        * Load the function.  Diagnose both library and function errors here.
  76.        */
  77.       if (handle) {
  78.          func = (int (*)())dlsym(handle, funcname);
  79.          if (!func) {
  80.             /*
  81.              * If no function, try again by prepending an underscore.
  82.              * (for OpenBSD and similar systems.)
  83.              */
  84.             funcname2 = malloc(strlen(funcname) + 2);
  85.             if (funcname2) {
  86.                *funcname2 = '_';
  87.                strcpy(funcname2 + 1, funcname);
  88.                func = (int (*)())dlsym(handle, funcname2);
  89.                free(funcname2);
  90.                }
  91.             }
  92.          }
  93.       if (!handle || !func) {
  94.          fprintf(stderr, "\nloadfunc(\"%s\",\"%s\"): %s\n",
  95.             filename, funcname, dlerror());
  96.          runerr(216);
  97.          }
  98.       /*
  99.        * Build and return a proc descriptor.
  100.        */
  101.       if (!makefunc(&result, funcname, func))
  102.          runerr(305);
  103.       return result;
  104.       }
  105. end
  106.  
  107. /*
  108.  * makefunc(d, name, func) -- make function descriptor in d.
  109.  *
  110.  *  Returns 0 if memory could not be allocated.
  111.  */
  112. int makefunc(d, name, func)
  113. dptr d;
  114. char *name;
  115. int (*func)();
  116.    {
  117.    struct b_proc *blk;
  118.  
  119.    blk = (struct b_proc *)malloc(sizeof(struct b_proc));
  120.    if (!blk)
  121.       return 0;
  122.    blk->title = T_Proc;
  123.    blk->blksize = sizeof(struct b_proc);
  124.  
  125. #if COMPILER
  126.    blk->ccode = glue;        /* set code addr to glue routine */
  127. #else                    /* COMPILER */
  128.    blk->entryp.ccode = glue;    /* set code addr to glue routine */
  129. #endif                    /* COMPILER */
  130.  
  131.    blk->nparam = -1;        /* varargs flag */
  132.    blk->ndynam = -1;        /* treat as built-in function */
  133.    blk->nstatic = 0;
  134.    blk->fstatic = 0;
  135.    blk->pname.dword = strlen(name);
  136.    blk->pname.vword.sptr = salloc(name);
  137.    blk->lnames[0].dword = 0;
  138.    blk->lnames[0].vword.sptr = (char *)func;
  139.                 /* save func addr in lnames[0] vword */
  140.    d->dword = D_Proc;        /* build proc descriptor */
  141.    d->vword.bptr = (union block *)blk;
  142.    return 1;
  143.    }
  144.  
  145. /*
  146.  * This glue routine is called when a loaded function is invoked.
  147.  * It digs the actual C code address out of the proc block, and calls that.
  148.  */
  149.  
  150. #if COMPILER
  151.  
  152. int glue(argc, dargv, rslt, succ_cont)
  153. int argc;
  154. dptr dargv;
  155. dptr rslt;
  156. continuation succ_cont;
  157.    {
  158.    int i, status, (*func)();
  159.    struct b_proc *blk;
  160.    struct descrip r;
  161.    tended struct descrip p;
  162.  
  163.    dargv--;                /* reset pointer to proc entry */
  164.    for (i = 0; i <= argc; i++)
  165.       deref(&dargv[i], &dargv[i]);    /* dereference args including proc */
  166.  
  167.    blk = (struct b_proc *)dargv[0].vword.bptr;    /* proc block address */
  168.    func = (int (*)())blk->lnames[0].vword.sptr;    /* entry point address */
  169.  
  170.    p = dargv[0];            /* save proc for traceback */
  171.    dargv[0] = nulldesc;            /* set default return value */
  172.    status = (*func)(argc, dargv);    /* call func */
  173.  
  174.    if (status == 0) {
  175.       *rslt = dargv[0];
  176.       Return;                /* success */
  177.       }
  178.  
  179.    if (status < 0)
  180.       Fail;                /* failure */
  181.  
  182.    r = dargv[0];            /* save result value */
  183.    dargv[0] = p;            /* restore proc for traceback */
  184.    if (is:null(r))
  185.       RunErr(status, NULL);        /* error, no value */
  186.    RunErr(status, &r);            /* error, with value */
  187.    }
  188.  
  189. #else                        /* COMPILER */
  190.  
  191. int glue(argc, dargv)
  192. int argc;
  193. dptr dargv;
  194.    {
  195.    int status, (*func)();
  196.    struct b_proc *blk;
  197.    struct descrip r;
  198.    tended struct descrip p;
  199.  
  200.    blk = (struct b_proc *)dargv[0].vword.bptr;    /* proc block address */
  201.    func = (int (*)())blk->lnames[0].vword.sptr;    /* entry point address */
  202.  
  203.    p = dargv[0];            /* save proc for traceback */
  204.    dargv[0] = nulldesc;            /* set default return value */
  205.    status = (*func)(argc, dargv);    /* call func */
  206.  
  207.    if (status == 0)
  208.       Return;                /* success */
  209.    if (status < 0)
  210.       Fail;                /* failure */
  211.  
  212.    r = dargv[0];            /* save result value */
  213.    dargv[0] = p;            /* restore proc for traceback */
  214.    if (is:null(r))
  215.       RunErr(status, NULL);        /* error, no value */
  216.    RunErr(status, &r);            /* error, with value */
  217.    }
  218.  
  219. #endif                        /* COMPILER */
  220.  
  221. #else                        /* LoadFunc */
  222. static char junk;            /* avoid empty module */
  223. #endif                        /* LoadFunc */
  224.