Main Page | Modules | Alphabetical List | Data Structures | File List | Data Fields | Globals

dln.c

Go to the documentation of this file.
00001 /**********************************************************************
00002 
00003   dln.c -
00004 
00005   $Author: eban $
00006   $Date: 2005/11/26 11:01:01 $
00007   created at: Tue Jan 18 17:05:06 JST 1994
00008 
00009   Copyright (C) 1993-2003 Yukihiro Matsumoto
00010 
00011 **********************************************************************/
00012 
00013 #include "ruby.h"
00014 #include "dln.h"
00015 
00016 #ifdef HAVE_STDLIB_H
00017 # include <stdlib.h>
00018 #endif
00019 
00020 #ifdef __CHECKER__
00021 #undef HAVE_DLOPEN
00022 #undef USE_DLN_A_OUT
00023 #undef USE_DLN_DLOPEN
00024 #endif
00025 
00026 #ifdef USE_DLN_A_OUT
00027 char *dln_argv0;
00028 #endif
00029 
00030 #ifdef _AIX
00031 #pragma alloca
00032 #endif
00033 
00034 #if defined(HAVE_ALLOCA_H)
00035 #include <alloca.h>
00036 #endif
00037 
00038 #ifdef HAVE_STRING_H
00039 # include <string.h>
00040 #else
00041 # include <strings.h>
00042 #endif
00043 
00044 #ifndef xmalloc
00045 void *xmalloc();
00046 void *xcalloc();
00047 void *xrealloc();
00048 #endif
00049 
00050 #include <stdio.h>
00051 #if defined(_WIN32) || defined(__VMS)
00052 #include "missing/file.h"
00053 #endif
00054 #include <sys/types.h>
00055 #include <sys/stat.h>
00056 
00057 #ifndef S_ISDIR
00058 #   define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
00059 #endif
00060 
00061 #ifdef HAVE_SYS_PARAM_H
00062 # include <sys/param.h>
00063 #endif
00064 #ifndef MAXPATHLEN
00065 # define MAXPATHLEN 1024
00066 #endif
00067 
00068 #ifdef HAVE_UNISTD_H
00069 # include <unistd.h>
00070 #endif
00071 
00072 #ifndef _WIN32
00073 char *getenv();
00074 #endif
00075 
00076 #if defined(__VMS)
00077 #pragma builtins
00078 #include <dlfcn.h>
00079 #endif
00080 
00081 #ifdef __MACOS__
00082 # include <TextUtils.h>
00083 # include <CodeFragments.h>
00084 # include <Aliases.h>
00085 # include "macruby_private.h"
00086 #endif
00087 
00088 #ifdef __BEOS__
00089 # include <image.h>
00090 #endif
00091 
00092 int eaccess();
00093 
00094 #ifndef NO_DLN_LOAD
00095 
00096 #if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(__APPLE__) && !defined(_UNICOSMP)
00097 /* dynamic load with dlopen() */
00098 # define USE_DLN_DLOPEN
00099 #endif
00100 
00101 #ifndef FUNCNAME_PATTERN
00102 # if defined(__hp9000s300) ||  (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || (defined(__OpenBSD__) && !defined(__ELF__)) || defined(NeXT) || defined(__WATCOMC__) || defined(__APPLE__)
00103 #  define FUNCNAME_PATTERN "_Init_%s"
00104 # else
00105 #  define FUNCNAME_PATTERN "Init_%s"
00106 # endif
00107 #endif
00108 
00109 static int
00110 init_funcname_len(buf, file)
00111     char **buf;
00112     const char *file;
00113 {
00114     char *p;
00115     const char *slash;
00116     int len;
00117 
00118     /* Load the file as an object one */
00119     for (slash = file-1; *file; file++) /* Find position of last '/' */
00120 #ifdef __MACOS__
00121         if (*file == ':') slash = file;
00122 #else
00123         if (*file == '/') slash = file;
00124 #endif
00125 
00126     len = strlen(FUNCNAME_PATTERN) + strlen(slash + 1);
00127     *buf = xmalloc(len);
00128     snprintf(*buf, len, FUNCNAME_PATTERN, slash + 1);
00129     for (p = *buf; *p; p++) {         /* Delete suffix if it exists */
00130         if (*p == '.') {
00131             *p = '\0'; break;
00132         }
00133     }
00134     return p - *buf;
00135 }
00136 
00137 #define init_funcname(buf, file) do {\
00138     int len = init_funcname_len(buf, file);\
00139     char *tmp = ALLOCA_N(char, len+1);\
00140     if (!tmp) {\
00141         free(*buf);\
00142         rb_memerror();\
00143     }\
00144     strcpy(tmp, *buf);\
00145     free(*buf);\
00146     *buf = tmp;\
00147 } while (0)
00148 
00149 #ifdef USE_DLN_A_OUT
00150 
00151 #ifndef LIBC_NAME
00152 # define LIBC_NAME "libc.a"
00153 #endif
00154 
00155 #ifndef DLN_DEFAULT_LIB_PATH
00156 #  define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:."
00157 #endif
00158 
00159 #include <errno.h>
00160 
00161 static int dln_errno;
00162 
00163 #define DLN_ENOEXEC     ENOEXEC /* Exec format error */
00164 #define DLN_ECONFL      1201    /* Symbol name conflict */
00165 #define DLN_ENOINIT     1202    /* No initializer given */
00166 #define DLN_EUNDEF      1203    /* Undefine symbol remains */
00167 #define DLN_ENOTLIB     1204    /* Not a library file */
00168 #define DLN_EBADLIB     1205    /* Malformed library file */
00169 #define DLN_EINIT       1206    /* Not initialized */
00170 
00171 static int dln_init_p = 0;
00172 
00173 #include <ar.h>
00174 #include <a.out.h>
00175 #ifndef N_COMM
00176 # define N_COMM 0x12
00177 #endif
00178 #ifndef N_MAGIC
00179 # define N_MAGIC(x) (x).a_magic
00180 #endif
00181 
00182 #define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC)
00183 
00184 #include "util.h"
00185 #include "st.h"
00186 
00187 static st_table *sym_tbl;
00188 static st_table *undef_tbl;
00189 
00190 static int load_lib();
00191 
00192 static int
00193 load_header(fd, hdrp, disp)
00194     int fd;
00195     struct exec *hdrp;
00196     long disp;
00197 {
00198     int size;
00199 
00200     lseek(fd, disp, 0);
00201     size = read(fd, hdrp, sizeof(struct exec));
00202     if (size == -1) {
00203         dln_errno = errno;
00204         return -1;
00205     }
00206     if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) {
00207         dln_errno = DLN_ENOEXEC;
00208         return -1;
00209     }
00210     return 0;
00211 }
00212 
00213 #if defined(sequent)
00214 #define RELOC_SYMBOL(r)                 ((r)->r_symbolnum)
00215 #define RELOC_MEMORY_SUB_P(r)           ((r)->r_bsr)
00216 #define RELOC_PCREL_P(r)                ((r)->r_pcrel || (r)->r_bsr)
00217 #define RELOC_TARGET_SIZE(r)            ((r)->r_length)
00218 #endif
00219 
00220 /* Default macros */
00221 #ifndef RELOC_ADDRESS
00222 #define RELOC_ADDRESS(r)                ((r)->r_address)
00223 #define RELOC_EXTERN_P(r)               ((r)->r_extern)
00224 #define RELOC_SYMBOL(r)                 ((r)->r_symbolnum)
00225 #define RELOC_MEMORY_SUB_P(r)           0
00226 #define RELOC_PCREL_P(r)                ((r)->r_pcrel)
00227 #define RELOC_TARGET_SIZE(r)            ((r)->r_length)
00228 #endif
00229 
00230 #if defined(sun) && defined(sparc)
00231 /* Sparc (Sun 4) macros */
00232 #  undef relocation_info
00233 #  define relocation_info reloc_info_sparc
00234 #  define R_RIGHTSHIFT(r)       (reloc_r_rightshift[(r)->r_type])
00235 #  define R_BITSIZE(r)          (reloc_r_bitsize[(r)->r_type])
00236 #  define R_LENGTH(r)           (reloc_r_length[(r)->r_type])
00237 static int reloc_r_rightshift[] = {
00238   0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0,
00239 };
00240 static int reloc_r_bitsize[] = {
00241   8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16,
00242 };
00243 static int reloc_r_length[] = {
00244   0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
00245 };
00246 #  define R_PCREL(r) \
00247     ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22)
00248 #  define R_SYMBOL(r) ((r)->r_index)
00249 #endif
00250 
00251 #if defined(sequent)
00252 #define R_SYMBOL(r)             ((r)->r_symbolnum)
00253 #define R_MEMORY_SUB(r)         ((r)->r_bsr)
00254 #define R_PCREL(r)              ((r)->r_pcrel || (r)->r_bsr)
00255 #define R_LENGTH(r)             ((r)->r_length)
00256 #endif
00257 
00258 #ifndef R_SYMBOL
00259 #  define R_SYMBOL(r)           ((r)->r_symbolnum)
00260 #  define R_MEMORY_SUB(r)       0
00261 #  define R_PCREL(r)            ((r)->r_pcrel)
00262 #  define R_LENGTH(r)           ((r)->r_length)
00263 #endif
00264 
00265 static struct relocation_info *
00266 load_reloc(fd, hdrp, disp)
00267      int fd;
00268      struct exec *hdrp;
00269      long disp;
00270 {
00271     struct relocation_info *reloc;
00272     int size;
00273 
00274     lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
00275     size = hdrp->a_trsize + hdrp->a_drsize;
00276     reloc = (struct relocation_info*)xmalloc(size);
00277     if (reloc == NULL) {
00278         dln_errno = errno;
00279         return NULL;
00280     }
00281 
00282     if (read(fd, reloc, size) !=  size) {
00283         dln_errno = errno;
00284         free(reloc);
00285         return NULL;
00286     }
00287 
00288     return reloc;
00289 }
00290 
00291 static struct nlist *
00292 load_sym(fd, hdrp, disp)
00293     int fd;
00294     struct exec *hdrp;
00295     long disp;
00296 {
00297     struct nlist * buffer;
00298     struct nlist * sym;
00299     struct nlist * end;
00300     long displ;
00301     int size;
00302 
00303     lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0);
00304     if (read(fd, &size, sizeof(int)) != sizeof(int)) {
00305         goto err_noexec;
00306     }
00307 
00308     buffer = (struct nlist*)xmalloc(hdrp->a_syms + size);
00309     if (buffer == NULL) {
00310         dln_errno = errno;
00311         return NULL;
00312     }
00313 
00314     lseek(fd, disp + N_SYMOFF(*hdrp), 0);
00315     if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) {
00316         free(buffer);
00317         goto err_noexec;
00318     }
00319 
00320     sym = buffer;
00321     end = sym + hdrp->a_syms / sizeof(struct nlist);
00322     displ = (long)buffer + (long)(hdrp->a_syms);
00323 
00324     while (sym < end) {
00325         sym->n_un.n_name = (char*)sym->n_un.n_strx + displ;
00326         sym++;
00327     }
00328     return buffer;
00329 
00330   err_noexec:
00331     dln_errno = DLN_ENOEXEC;
00332     return NULL;
00333 }
00334 
00335 static st_table *
00336 sym_hash(hdrp, syms)
00337     struct exec *hdrp;
00338     struct nlist *syms;
00339 {
00340     st_table *tbl;
00341     struct nlist *sym = syms;
00342     struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist));
00343 
00344     tbl = st_init_strtable();
00345     if (tbl == NULL) {
00346         dln_errno = errno;
00347         return NULL;
00348     }
00349 
00350     while (sym < end) {
00351         st_insert(tbl, sym->n_un.n_name, sym);
00352         sym++;
00353     }
00354     return tbl;
00355 }
00356 
00357 static int
00358 dln_init(prog)
00359     const char *prog;
00360 {
00361     char *file;
00362     int fd;
00363     struct exec hdr;
00364     struct nlist *syms;
00365 
00366     if (dln_init_p == 1) return 0;
00367 
00368     file = dln_find_exe(prog, NULL);
00369     if (file == NULL || (fd = open(file, O_RDONLY)) < 0) {
00370         dln_errno = errno;
00371         return -1;
00372     }
00373 
00374     if (load_header(fd, &hdr, 0) == -1) return -1;
00375     syms = load_sym(fd, &hdr, 0);
00376     if (syms == NULL) {
00377         close(fd);
00378         return -1;
00379     }
00380     sym_tbl = sym_hash(&hdr, syms);
00381     if (sym_tbl == NULL) {      /* file may be start with #! */
00382         char c = '\0';
00383         char buf[MAXPATHLEN];
00384         char *p;
00385 
00386         free(syms);
00387         lseek(fd, 0L, 0);
00388         if (read(fd, &c, 1) == -1) {
00389             dln_errno = errno;
00390             return -1;
00391         }
00392         if (c != '#') goto err_noexec;
00393         if (read(fd, &c, 1) == -1) {
00394             dln_errno = errno;
00395             return -1;
00396         }
00397         if (c != '!') goto err_noexec;
00398 
00399         p = buf;
00400         /* skip forwarding spaces */
00401         while (read(fd, &c, 1) == 1) {
00402             if (c == '\n') goto err_noexec;
00403             if (c != '\t' && c != ' ') {
00404                 *p++ = c;
00405                 break;
00406             }
00407         }
00408         /* read in command name */
00409         while (read(fd, p, 1) == 1) {
00410             if (*p == '\n' || *p == '\t' || *p == ' ') break;
00411             p++;
00412             if (p-buf >= MAXPATHLEN) {
00413                 dln_errno = ENAMETOOLONG;
00414                 return -1;
00415             }
00416         }
00417         *p = '\0';
00418 
00419         return dln_init(buf);
00420     }
00421     dln_init_p = 1;
00422     undef_tbl = st_init_strtable();
00423     close(fd);
00424     return 0;
00425 
00426   err_noexec:
00427     close(fd);
00428     dln_errno = DLN_ENOEXEC;
00429     return -1;
00430 }
00431 
00432 static long
00433 load_text_data(fd, hdrp, bss, disp)
00434     int fd;
00435     struct exec *hdrp;
00436     int bss;
00437     long disp;
00438 {
00439     int size;
00440     unsigned char* addr;
00441 
00442     lseek(fd, disp + N_TXTOFF(*hdrp), 0);
00443     size = hdrp->a_text + hdrp->a_data;
00444 
00445     if (bss == -1) size += hdrp->a_bss;
00446     else if (bss > 1) size += bss;
00447 
00448     addr = (unsigned char*)xmalloc(size);
00449     if (addr == NULL) {
00450         dln_errno = errno;
00451         return 0;
00452     }
00453 
00454     if (read(fd, addr, size) !=  size) {
00455         dln_errno = errno;
00456         free(addr);
00457         return 0;
00458     }
00459 
00460     if (bss == -1) {
00461         memset(addr +  hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss);
00462     }
00463     else if (bss > 0) {
00464         memset(addr +  hdrp->a_text + hdrp->a_data, 0, bss);
00465     }
00466 
00467     return (long)addr;
00468 }
00469 
00470 static int
00471 undef_print(key, value)
00472     char *key, *value;
00473 {
00474     fprintf(stderr, "  %s\n", key);
00475     return ST_CONTINUE;
00476 }
00477 
00478 static void
00479 dln_print_undef()
00480 {
00481     fprintf(stderr, " Undefined symbols:\n");
00482     st_foreach(undef_tbl, undef_print, NULL);
00483 }
00484 
00485 static void
00486 dln_undefined()
00487 {
00488     if (undef_tbl->num_entries > 0) {
00489         fprintf(stderr, "dln: Calling undefined function\n");
00490         dln_print_undef();
00491         rb_exit(1);
00492     }
00493 }
00494 
00495 struct undef {
00496     char *name;
00497     struct relocation_info reloc;
00498     long base;
00499     char *addr;
00500     union {
00501         char c;
00502         short s;
00503         long l;
00504     } u;
00505 };
00506 
00507 static st_table *reloc_tbl = NULL;
00508 static void
00509 link_undef(name, base, reloc)
00510     const char *name;
00511     long base;
00512     struct relocation_info *reloc;
00513 {
00514     static int u_no = 0;
00515     struct undef *obj;
00516     char *addr = (char*)(reloc->r_address + base);
00517 
00518     obj = (struct undef*)xmalloc(sizeof(struct undef));
00519     obj->name = strdup(name);
00520     obj->reloc = *reloc;
00521     obj->base = base;
00522     switch (R_LENGTH(reloc)) {
00523       case 0:           /* byte */
00524         obj->u.c = *addr;
00525         break;
00526       case 1:           /* word */
00527         obj->u.s = *(short*)addr;
00528         break;
00529       case 2:           /* long */
00530         obj->u.l = *(long*)addr;
00531         break;
00532     }
00533     if (reloc_tbl == NULL) {
00534         reloc_tbl = st_init_numtable();
00535     }
00536     st_insert(reloc_tbl, u_no++, obj);
00537 }
00538 
00539 struct reloc_arg {
00540     const char *name;
00541     long value;
00542 };
00543 
00544 static int
00545 reloc_undef(no, undef, arg)
00546     int no;
00547     struct undef *undef;
00548     struct reloc_arg *arg;
00549 {
00550     int datum;
00551     char *address;
00552 #if defined(sun) && defined(sparc)
00553     unsigned int mask = 0;
00554 #endif
00555 
00556     if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE;
00557     address = (char*)(undef->base + undef->reloc.r_address);
00558     datum = arg->value;
00559 
00560     if (R_PCREL(&(undef->reloc))) datum -= undef->base;
00561 #if defined(sun) && defined(sparc)
00562     datum += undef->reloc.r_addend;
00563     datum >>= R_RIGHTSHIFT(&(undef->reloc));
00564     mask = (1 << R_BITSIZE(&(undef->reloc))) - 1;
00565     mask |= mask -1;
00566     datum &= mask;
00567     switch (R_LENGTH(&(undef->reloc))) {
00568       case 0:
00569         *address = undef->u.c;
00570         *address &= ~mask;
00571         *address |= datum;
00572         break;
00573       case 1:
00574         *(short *)address = undef->u.s;
00575         *(short *)address &= ~mask;
00576         *(short *)address |= datum;
00577         break;
00578       case 2:
00579         *(long *)address = undef->u.l;
00580         *(long *)address &= ~mask;
00581         *(long *)address |= datum;
00582         break;
00583     }
00584 #else
00585     switch (R_LENGTH(&(undef->reloc))) {
00586       case 0:           /* byte */
00587         if (R_MEMORY_SUB(&(undef->reloc)))
00588             *address = datum - *address;
00589         else *address = undef->u.c + datum;
00590         break;
00591       case 1:           /* word */
00592         if (R_MEMORY_SUB(&(undef->reloc)))
00593             *(short*)address = datum - *(short*)address;
00594         else *(short*)address = undef->u.s + datum;
00595         break;
00596       case 2:           /* long */
00597         if (R_MEMORY_SUB(&(undef->reloc)))
00598             *(long*)address = datum - *(long*)address;
00599         else *(long*)address = undef->u.l + datum;
00600         break;
00601     }
00602 #endif
00603     free(undef->name);
00604     free(undef);
00605     return ST_DELETE;
00606 }
00607 
00608 static void
00609 unlink_undef(name, value)
00610     const char *name;
00611     long value;
00612 {
00613     struct reloc_arg arg;
00614 
00615     arg.name = name;
00616     arg.value = value;
00617     st_foreach(reloc_tbl, reloc_undef, &arg);
00618 }
00619 
00620 #ifdef N_INDR
00621 struct indr_data {
00622     char *name0, *name1;
00623 };
00624 
00625 static int
00626 reloc_repl(no, undef, data)
00627     int no;
00628     struct undef *undef;
00629     struct indr_data *data;
00630 {
00631     if (strcmp(data->name0, undef->name) == 0) {
00632         free(undef->name);
00633         undef->name = strdup(data->name1);
00634     }
00635     return ST_CONTINUE;
00636 }
00637 #endif
00638 
00639 static int
00640 load_1(fd, disp, need_init)
00641     int fd;
00642     long disp;
00643     const char *need_init;
00644 {
00645     static char *libc = LIBC_NAME;
00646     struct exec hdr;
00647     struct relocation_info *reloc = NULL;
00648     long block = 0;
00649     long new_common = 0; /* Length of new common */
00650     struct nlist *syms = NULL;
00651     struct nlist *sym;
00652     struct nlist *end;
00653     int init_p = 0;
00654 
00655     if (load_header(fd, &hdr, disp) == -1) return -1;
00656     if (INVALID_OBJECT(hdr)) {
00657         dln_errno = DLN_ENOEXEC;
00658         return -1;
00659     }
00660     reloc = load_reloc(fd, &hdr, disp);
00661     if (reloc == NULL) return -1;
00662 
00663     syms = load_sym(fd, &hdr, disp);
00664     if (syms == NULL) {
00665         free(reloc);
00666         return -1;
00667     }
00668 
00669     sym = syms;
00670     end = syms + (hdr.a_syms / sizeof(struct nlist));
00671     while (sym < end) {
00672         struct nlist *old_sym;
00673         int value = sym->n_value;
00674 
00675 #ifdef N_INDR
00676         if (sym->n_type == (N_INDR | N_EXT)) {
00677             char *key = sym->n_un.n_name;
00678 
00679             if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) {
00680                 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) {
00681                     unlink_undef(key, old_sym->n_value);
00682                     free(key);
00683                 }
00684             }
00685             else {
00686                 struct indr_data data;
00687 
00688                 data.name0 = sym->n_un.n_name;
00689                 data.name1 = sym[1].n_un.n_name;
00690                 st_foreach(reloc_tbl, reloc_repl, &data);
00691 
00692                 st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL);
00693                 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) {
00694                     free(key);
00695                 }
00696             }
00697             sym += 2;
00698             continue;
00699         }
00700 #endif
00701         if (sym->n_type == (N_UNDF | N_EXT)) {
00702             if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) {
00703                 old_sym = NULL;
00704             }
00705 
00706             if (value) {
00707                 if (old_sym) {
00708                     sym->n_type = N_EXT | N_COMM;
00709                     sym->n_value = old_sym->n_value;
00710                 }
00711                 else {
00712                     int rnd =
00713                         value >= sizeof(double) ? sizeof(double) - 1
00714                             : value >= sizeof(long) ? sizeof(long) - 1
00715                                 : sizeof(short) - 1;
00716 
00717                     sym->n_type = N_COMM;
00718                     new_common += rnd;
00719                     new_common &= ~(long)rnd;
00720                     sym->n_value = new_common;
00721                     new_common += value;
00722                 }
00723             }
00724             else {
00725                 if (old_sym) {
00726                     sym->n_type = N_EXT | N_COMM;
00727                     sym->n_value = old_sym->n_value;
00728                 }
00729                 else {
00730                     sym->n_value = (long)dln_undefined;
00731                     st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL);
00732                 }
00733             }
00734         }
00735         sym++;
00736     }
00737 
00738     block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp);
00739     if (block == 0) goto err_exit;
00740 
00741     sym = syms;
00742     while (sym < end) {
00743         struct nlist *new_sym;
00744         char *key;
00745 
00746         switch (sym->n_type) {
00747           case N_COMM:
00748             sym->n_value += hdr.a_text + hdr.a_data;
00749           case N_TEXT|N_EXT:
00750           case N_DATA|N_EXT:
00751 
00752             sym->n_value += block;
00753 
00754             if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0
00755                 && new_sym->n_value != (long)dln_undefined) {
00756                 dln_errno = DLN_ECONFL;
00757                 goto err_exit;
00758             }
00759 
00760             key = sym->n_un.n_name;
00761             if (st_delete(undef_tbl, (st_data_t*)&key, NULL) != 0) {
00762                 unlink_undef(key, sym->n_value);
00763                 free(key);
00764             }
00765 
00766             new_sym = (struct nlist*)xmalloc(sizeof(struct nlist));
00767             *new_sym = *sym;
00768             new_sym->n_un.n_name = strdup(sym->n_un.n_name);
00769             st_insert(sym_tbl, new_sym->n_un.n_name, new_sym);
00770             break;
00771 
00772           case N_TEXT:
00773           case N_DATA:
00774             sym->n_value += block;
00775             break;
00776         }
00777         sym++;
00778     }
00779 
00780     /*
00781      * First comes the text-relocation
00782      */
00783     {
00784         struct relocation_info * rel = reloc;
00785         struct relocation_info * rel_beg = reloc +
00786             (hdr.a_trsize/sizeof(struct relocation_info));
00787         struct relocation_info * rel_end = reloc +
00788             (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info);
00789 
00790         while (rel < rel_end) {
00791             char *address = (char*)(rel->r_address + block);
00792             long datum = 0;
00793 #if defined(sun) && defined(sparc)
00794             unsigned int mask = 0;
00795 #endif
00796 
00797             if(rel >= rel_beg)
00798                 address += hdr.a_text;
00799 
00800             if (rel->r_extern) { /* Look it up in symbol-table */
00801                 sym = &(syms[R_SYMBOL(rel)]);
00802                 switch (sym->n_type) {
00803                   case N_EXT|N_UNDF:
00804                     link_undef(sym->n_un.n_name, block, rel);
00805                   case N_EXT|N_COMM:
00806                   case N_COMM:
00807                     datum = sym->n_value;
00808                     break;
00809                   default:
00810                     goto err_exit;
00811                 }
00812             } /* end.. look it up */
00813             else { /* is static */
00814                 switch (R_SYMBOL(rel)) { 
00815                   case N_TEXT:
00816                   case N_DATA:
00817                     datum = block;
00818                     break;
00819                   case N_BSS:
00820                     datum = block +  new_common;
00821                     break;
00822                   case N_ABS:
00823                     break;
00824                 }
00825             } /* end .. is static */
00826             if (R_PCREL(rel)) datum -= block;
00827 
00828 #if defined(sun) && defined(sparc)
00829             datum += rel->r_addend;
00830             datum >>= R_RIGHTSHIFT(rel);
00831             mask = (1 << R_BITSIZE(rel)) - 1;
00832             mask |= mask -1;
00833             datum &= mask;
00834 
00835             switch (R_LENGTH(rel)) {
00836               case 0:
00837                 *address &= ~mask;
00838                 *address |= datum;
00839                 break;
00840               case 1:
00841                 *(short *)address &= ~mask;
00842                 *(short *)address |= datum;
00843                 break;
00844               case 2:
00845                 *(long *)address &= ~mask;
00846                 *(long *)address |= datum;
00847                 break;
00848             }
00849 #else
00850             switch (R_LENGTH(rel)) {
00851               case 0:           /* byte */
00852                 if (datum < -128 || datum > 127) goto err_exit;
00853                 *address += datum;
00854                 break;
00855               case 1:           /* word */
00856                 *(short *)address += datum;
00857                 break;
00858               case 2:           /* long */
00859                 *(long *)address += datum;
00860                 break;
00861             }
00862 #endif
00863             rel++;
00864         }
00865     }
00866 
00867     if (need_init) {
00868         int len;
00869         char **libs_to_be_linked = 0;
00870         char *buf;
00871 
00872         if (undef_tbl->num_entries > 0) {
00873             if (load_lib(libc) == -1) goto err_exit;
00874         }
00875 
00876         init_funcname(&buf, need_init);
00877         len = strlen(buf);
00878 
00879         for (sym = syms; sym<end; sym++) {
00880             char *name = sym->n_un.n_name;
00881             if (name[0] == '_' && sym->n_value >= block) {
00882                 if (strcmp(name+1, "dln_libs_to_be_linked") == 0) {
00883                     libs_to_be_linked = (char**)sym->n_value;
00884                 }
00885                 else if (strcmp(name+1, buf) == 0) {
00886                     init_p = 1;
00887                     ((int (*)())sym->n_value)();
00888                 }
00889             }
00890         }
00891         if (libs_to_be_linked && undef_tbl->num_entries > 0) {
00892             while (*libs_to_be_linked) {
00893                 load_lib(*libs_to_be_linked);
00894                 libs_to_be_linked++;
00895             }
00896         }
00897     }
00898     free(reloc);
00899     free(syms);
00900     if (need_init) {
00901         if (init_p == 0) {
00902             dln_errno = DLN_ENOINIT;
00903             return -1;
00904         }
00905         if (undef_tbl->num_entries > 0) {
00906             if (load_lib(libc) == -1) goto err_exit;
00907             if (undef_tbl->num_entries > 0) {
00908                 dln_errno = DLN_EUNDEF;
00909                 return -1;
00910             }
00911         }
00912     }
00913     return 0;
00914 
00915   err_exit:
00916     if (syms) free(syms);
00917     if (reloc) free(reloc);
00918     if (block) free((char*)block);
00919     return -1;
00920 }
00921 
00922 static int target_offset;
00923 static int
00924 search_undef(key, value, lib_tbl)
00925     const char *key;
00926     int value;
00927     st_table *lib_tbl;
00928 {
00929     long offset;
00930 
00931     if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
00932     target_offset = offset;
00933     return ST_STOP;
00934 }
00935 
00936 struct symdef {
00937     int rb_str_index;
00938     int lib_offset;
00939 };
00940 
00941 char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH;
00942 
00943 static int
00944 load_lib(lib)
00945     const char *lib;
00946 {
00947     char *path, *file;
00948     char armagic[SARMAG];
00949     int fd, size;
00950     struct ar_hdr ahdr;
00951     st_table *lib_tbl = NULL;
00952     int *data, nsym;
00953     struct symdef *base;
00954     char *name_base;
00955 
00956     if (dln_init_p == 0) {
00957         dln_errno = DLN_ENOINIT;
00958         return -1;
00959     }
00960 
00961     if (undef_tbl->num_entries == 0) return 0;
00962     dln_errno = DLN_EBADLIB;
00963 
00964     if (lib[0] == '-' && lib[1] == 'l') {
00965         long len = strlen(lib) + 4;
00966         char *p = alloca(len);
00967         snprintf(p, len, "lib%s.a", lib+2);
00968         lib = p;
00969     }
00970 
00971     /* library search path: */
00972     /* look for environment variable DLN_LIBRARY_PATH first. */
00973     /* then variable dln_librrb_ary_path. */
00974     /* if path is still NULL, use "." for path. */
00975     path = getenv("DLN_LIBRARY_PATH");
00976     if (path == NULL) path = dln_librrb_ary_path;
00977 
00978     file = dln_find_file(lib, path);
00979     fd = open(file, O_RDONLY);
00980     if (fd == -1) goto syserr;
00981     size = read(fd, armagic, SARMAG);
00982     if (size == -1) goto syserr;
00983 
00984     if (size != SARMAG) {
00985         dln_errno = DLN_ENOTLIB;
00986         goto badlib;
00987     }
00988     size = read(fd, &ahdr, sizeof(ahdr));
00989     if (size == -1) goto syserr;
00990     if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) {
00991         goto badlib;
00992     }
00993 
00994     if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) {
00995         /* make hash table from __.SYMDEF */
00996 
00997         lib_tbl = st_init_strtable();
00998         data = (int*)xmalloc(size);
00999         if (data == NULL) goto syserr;
01000         size = read(fd, data, size);
01001         nsym = *data / sizeof(struct symdef);
01002         base = (struct symdef*)(data + 1);
01003         name_base = (char*)(base + nsym) + sizeof(int);
01004         while (nsym > 0) {
01005             char *name = name_base + base->rb_str_index;
01006 
01007             st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr));
01008             nsym--;
01009             base++;
01010         }
01011         for (;;) {
01012             target_offset = -1;
01013             st_foreach(undef_tbl, search_undef, lib_tbl);
01014             if (target_offset == -1) break;
01015             if (load_1(fd, target_offset, 0) == -1) {
01016                 st_free_table(lib_tbl);
01017                 free(data);
01018                 goto badlib;
01019             }
01020             if (undef_tbl->num_entries == 0) break;
01021         }
01022         free(data);
01023         st_free_table(lib_tbl);
01024     }
01025     else {
01026         /* linear library, need to scan (FUTURE) */
01027 
01028         for (;;) {
01029             int offset = SARMAG;
01030             int found = 0;
01031             struct exec hdr;
01032             struct nlist *syms, *sym, *end;
01033 
01034             while (undef_tbl->num_entries > 0) {
01035                 found = 0;
01036                 lseek(fd, offset, 0);
01037                 size = read(fd, &ahdr, sizeof(ahdr));
01038                 if (size == -1) goto syserr;
01039                 if (size == 0) break;
01040                 if (size != sizeof(ahdr)
01041                     || sscanf(ahdr.ar_size, "%d", &size) != 1) {
01042                     goto badlib;
01043                 }
01044                 offset += sizeof(ahdr);
01045                 if (load_header(fd, &hdr, offset) == -1)
01046                     goto badlib;
01047                 syms = load_sym(fd, &hdr, offset);
01048                 if (syms == NULL) goto badlib;
01049                 sym = syms;
01050                 end = syms + (hdr.a_syms / sizeof(struct nlist));
01051                 while (sym < end) {
01052                     if (sym->n_type == N_EXT|N_TEXT
01053                         && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) {
01054                         break;
01055                     }
01056                     sym++;
01057                 }
01058                 if (sym < end) {
01059                     found++;
01060                     free(syms);
01061                     if (load_1(fd, offset, 0) == -1) {
01062                         goto badlib;
01063                     }
01064                 }
01065                 offset += size;
01066                 if (offset & 1) offset++;
01067             }
01068             if (found) break;
01069         }
01070     }
01071     close(fd);
01072     return 0;
01073 
01074   syserr:
01075     dln_errno = errno;
01076   badlib:
01077     if (fd >= 0) close(fd);
01078     return -1;
01079 }
01080 
01081 static int
01082 load(file)
01083     const char *file;
01084 {
01085     int fd;
01086     int result;
01087 
01088     if (dln_init_p == 0) {
01089         if (dln_init(dln_argv0) == -1) return -1;
01090     }
01091     result = strlen(file);
01092     if (file[result-1] == 'a') {
01093         return load_lib(file);
01094     }
01095 
01096     fd = open(file, O_RDONLY);
01097     if (fd == -1) {
01098         dln_errno = errno;
01099         return -1;
01100     }
01101     result = load_1(fd, 0, file);
01102     close(fd);
01103 
01104     return result;
01105 }
01106 
01107 void*
01108 dln_sym(name)
01109     const char *name;
01110 {
01111     struct nlist *sym;
01112 
01113     if (st_lookup(sym_tbl, name, &sym))
01114         return (void*)sym->n_value;
01115     return NULL;
01116 }
01117 
01118 #endif /* USE_DLN_A_OUT */
01119 
01120 #ifdef USE_DLN_DLOPEN
01121 # if defined(__NetBSD__) && defined(__NetBSD_Version__) && __NetBSD_Version__ < 105000000
01122 #  include <nlist.h>
01123 #  include <link.h>
01124 # else
01125 #  include <dlfcn.h>
01126 # endif
01127 #endif
01128 
01129 #ifdef __hpux
01130 #include <errno.h>
01131 #include "dl.h"
01132 #endif
01133 
01134 #if defined(_AIX)
01135 #include <ctype.h>      /* for isdigit()        */
01136 #include <errno.h>      /* for global errno     */
01137 #include <sys/ldr.h>
01138 #endif
01139 
01140 #ifdef NeXT
01141 #if NS_TARGET_MAJOR < 4
01142 #include <mach-o/rld.h>
01143 #else
01144 #include <mach-o/dyld.h>
01145 #ifndef NSLINKMODULE_OPTION_BINDNOW
01146 #define NSLINKMODULE_OPTION_BINDNOW 1
01147 #endif
01148 #endif
01149 #else
01150 #ifdef __APPLE__
01151 #include <mach-o/dyld.h>
01152 #endif
01153 #endif
01154 
01155 #if defined _WIN32 && !defined __CYGWIN__
01156 #include <windows.h>
01157 #endif
01158 
01159 #ifdef _WIN32_WCE
01160 #undef FormatMessage
01161 #define FormatMessage FormatMessageA
01162 #undef LoadLibrary
01163 #define LoadLibrary LoadLibraryA
01164 #undef GetProcAddress
01165 #define GetProcAddress GetProcAddressA
01166 #endif
01167 
01168 static const char *
01169 dln_strerror()
01170 {
01171 #ifdef USE_DLN_A_OUT
01172     char *strerror();
01173 
01174     switch (dln_errno) {
01175       case DLN_ECONFL:
01176         return "Symbol name conflict";
01177       case DLN_ENOINIT:
01178         return "No initializer given";
01179       case DLN_EUNDEF:
01180         return "Unresolved symbols";
01181       case DLN_ENOTLIB:
01182         return "Not a library file";
01183       case DLN_EBADLIB:
01184         return "Malformed library file";
01185       case DLN_EINIT:
01186         return "Not initialized";
01187       default:
01188         return strerror(dln_errno);
01189     }
01190 #endif
01191 
01192 #ifdef USE_DLN_DLOPEN
01193     return (char*)dlerror();
01194 #endif
01195 
01196 #if defined _WIN32 && !defined __CYGWIN__
01197     static char message[1024];
01198     int error = GetLastError();
01199     char *p = message;
01200     p += sprintf(message, "%d: ", error);
01201     FormatMessage(
01202         FORMAT_MESSAGE_FROM_SYSTEM       | FORMAT_MESSAGE_IGNORE_INSERTS,
01203         NULL,
01204         error,
01205         MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
01206         p,
01207         sizeof message - strlen(message),
01208         NULL);
01209 
01210     for (p = message; *p; p++) {
01211         if (*p == '\n' || *p == '\r')
01212             *p = ' ';
01213     }
01214     return message;
01215 #endif
01216 }
01217 
01218 
01219 #if defined(_AIX) && ! defined(_IA64)
01220 static void
01221 aix_loaderror(const char *pathname)
01222 {
01223     char *message[8], errbuf[1024];
01224     int i,j;
01225 
01226     struct errtab { 
01227         int errnum;
01228         char *errstr;
01229     } load_errtab[] = {
01230         {L_ERROR_TOOMANY,       "too many errors, rest skipped."},
01231         {L_ERROR_NOLIB,         "can't load library:"},
01232         {L_ERROR_UNDEF,         "can't find symbol in library:"},
01233         {L_ERROR_RLDBAD,
01234              "RLD index out of range or bad relocation type:"},
01235         {L_ERROR_FORMAT,        "not a valid, executable xcoff file:"},
01236         {L_ERROR_MEMBER,
01237              "file not an archive or does not contain requested member:"},
01238         {L_ERROR_TYPE,          "symbol table mismatch:"},
01239         {L_ERROR_ALIGN,         "text alignment in file is wrong."},
01240         {L_ERROR_SYSTEM,        "System error:"},
01241         {L_ERROR_ERRNO,         NULL}
01242     };
01243 
01244 #define LOAD_ERRTAB_LEN (sizeof(load_errtab)/sizeof(load_errtab[0]))
01245 #define ERRBUF_APPEND(s) strncat(errbuf, s, sizeof(errbuf)-strlen(errbuf)-1)
01246 
01247     snprintf(errbuf, 1024, "load failed - %s ", pathname);
01248 
01249     if (!loadquery(1, &message[0], sizeof(message))) 
01250         ERRBUF_APPEND(strerror(errno));
01251     for(i = 0; message[i] && *message[i]; i++) {
01252         int nerr = atoi(message[i]);
01253         for (j=0; j<LOAD_ERRTAB_LEN; j++) {
01254            if (nerr == load_errtab[i].errnum && load_errtab[i].errstr)
01255                 ERRBUF_APPEND(load_errtab[i].errstr);
01256         }
01257         while (isdigit(*message[i])) message[i]++; 
01258         ERRBUF_APPEND(message[i]);
01259         ERRBUF_APPEND("\n");
01260     }
01261     errbuf[strlen(errbuf)-1] = '\0';    /* trim off last newline */
01262     rb_loaderror(errbuf);
01263     return;
01264 }
01265 #endif
01266 
01267 #if defined(__VMS)
01268 #include <starlet.h>
01269 #include <rms.h>
01270 #include <stsdef.h>
01271 #include <unixlib.h>
01272 #include <descrip.h>
01273 #include <lib$routines.h>
01274 
01275 static char *vms_filespec;
01276 static int vms_fileact(char *filespec, int type);
01277 static long vms_fisexh(long *sigarr, long *mecarr);
01278 #endif
01279 
01280 #endif /* NO_DLN_LOAD */
01281 
01282 void*
01283 dln_load(file)
01284     const char *file;
01285 {
01286 #ifdef NO_DLN_LOAD
01287     rb_raise(rb_eLoadError, "this executable file can't load extension libraries");
01288 #else
01289 
01290 #if !defined(_AIX) && !defined(NeXT)
01291     const char *error = 0;
01292 #define DLN_ERROR() (error = dln_strerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error))
01293 #endif
01294 
01295 #if defined _WIN32 && !defined __CYGWIN__
01296     HINSTANCE handle;
01297     char winfile[MAXPATHLEN];
01298     void (*init_fct)();
01299     char *buf;
01300 
01301     if (strlen(file) >= MAXPATHLEN) rb_loaderror("filename too long");
01302 
01303     /* Load the file as an object one */
01304     init_funcname(&buf, file);
01305 
01306     strcpy(winfile, file);
01307 
01308     /* Load file */
01309     if ((handle = LoadLibrary(winfile)) == NULL) {
01310         error = dln_strerror();
01311         goto failed;
01312     }
01313 
01314     if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) {
01315         rb_loaderror("%s - %s\n%s", dln_strerror(), buf, file);
01316     }
01317 
01318     /* Call the init code */
01319     (*init_fct)();
01320     return handle;
01321 #else
01322 #ifdef USE_DLN_A_OUT
01323     if (load(file) == -1) {
01324         error = dln_strerror();
01325         goto failed;
01326     }
01327     return 0;
01328 #else
01329 
01330     char *buf;
01331     /* Load the file as an object one */
01332     init_funcname(&buf, file);
01333 
01334 #ifdef USE_DLN_DLOPEN
01335 #define DLN_DEFINED
01336     {
01337         void *handle;
01338         void (*init_fct)();
01339 
01340 #ifndef RTLD_LAZY
01341 # define RTLD_LAZY 1
01342 #endif
01343 #ifdef __INTERIX
01344 # undef RTLD_GLOBAL
01345 #endif
01346 #ifndef RTLD_GLOBAL
01347 # define RTLD_GLOBAL 0
01348 #endif
01349 
01350         /* Load file */
01351         if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
01352             error = dln_strerror();
01353             goto failed;
01354         }
01355 
01356         init_fct = (void(*)())dlsym(handle, buf);
01357         if (init_fct == NULL) {
01358             error = DLN_ERROR();
01359             dlclose(handle);
01360             goto failed;
01361         }
01362         /* Call the init code */
01363         (*init_fct)();
01364 
01365         return handle;
01366     }
01367 #endif /* USE_DLN_DLOPEN */
01368 
01369 #ifdef __hpux
01370 #define DLN_DEFINED
01371     {
01372         shl_t lib = NULL;
01373         int flags;
01374         void (*init_fct)();
01375 
01376         flags = BIND_DEFERRED;
01377         lib = shl_load(file, flags, 0);
01378         if (lib == NULL) {
01379             extern int errno;
01380             rb_loaderror("%s - %s", strerror(errno), file);
01381         }
01382         shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct);
01383         if (init_fct == NULL) {
01384             shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct);
01385             if (init_fct == NULL) {
01386                 errno = ENOSYM;
01387                 rb_loaderror("%s - %s", strerror(ENOSYM), file);
01388             }
01389         }
01390         (*init_fct)();
01391         return (void*)lib;
01392     }
01393 #endif /* hpux */
01394 
01395 #if defined(_AIX) && ! defined(_IA64)
01396 #define DLN_DEFINED
01397     {
01398         void (*init_fct)();
01399 
01400         init_fct = (void(*)())load((char*)file, 1, 0);
01401         if (init_fct == NULL) {
01402             aix_loaderror(file);
01403         }
01404         if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) {
01405             aix_loaderror(file);
01406         }
01407         (*init_fct)();
01408         return (void*)init_fct;
01409     }
01410 #endif /* _AIX */
01411 
01412 #if defined(NeXT) || defined(__APPLE__)
01413 #define DLN_DEFINED
01414 /*----------------------------------------------------
01415    By SHIROYAMA Takayuki Psi@fortune.nest.or.jp
01416  
01417    Special Thanks...
01418     Yu tomoak-i@is.aist-nara.ac.jp,
01419     Mi hisho@tasihara.nest.or.jp,
01420     sunshine@sunshineco.com,
01421     and... Miss ARAI Akino(^^;)
01422  ----------------------------------------------------*/
01423 #if defined(NeXT) && (NS_TARGET_MAJOR < 4)/* NeXTSTEP rld functions */
01424 
01425     {
01426         NXStream* s;
01427         unsigned long init_address;
01428         char *object_files[2] = {NULL, NULL};
01429 
01430         void (*init_fct)();
01431         
01432         object_files[0] = (char*)file;
01433         
01434         s = NXOpenFile(2,NX_WRITEONLY);
01435 
01436         /* Load object file, if return value ==0 ,  load failed*/
01437         if(rld_load(s, NULL, object_files, NULL) == 0) {
01438             NXFlush(s);
01439             NXClose(s);
01440             rb_loaderror("Failed to load %.200s", file);
01441         }
01442 
01443         /* lookup the initial function */
01444         if(rld_lookup(s, buf, &init_address) == 0) {
01445             NXFlush(s);
01446             NXClose(s);
01447             rb_loaderror("Failed to lookup Init function %.200s", file);
01448         }
01449 
01450         NXFlush(s);
01451         NXClose(s);
01452 
01453         /* Cannot call *init_address directory, so copy this value to
01454            funtion pointer */
01455         init_fct = (void(*)())init_address;
01456         (*init_fct)();
01457         return (void*)init_address;
01458     }
01459 #else/* OPENSTEP dyld functions */
01460     {
01461         int dyld_result;
01462         NSObjectFileImage obj_file; /* handle, but not use it */
01463         /* "file" is module file name .
01464            "buf" is pointer to initial function name with "_" . */
01465 
01466         void (*init_fct)();
01467 
01468 
01469         dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file);
01470 
01471         if (dyld_result != NSObjectFileImageSuccess) {
01472             rb_loaderror("Failed to load %.200s", file);
01473         }
01474 
01475         NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW);
01476 
01477         /* lookup the initial function */
01478         if(!NSIsSymbolNameDefined(buf)) {
01479             rb_loaderror("Failed to lookup Init function %.200s",file);
01480         }       
01481         init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf));
01482         (*init_fct)();
01483 
01484         return (void*)init_fct;
01485     }
01486 #endif /* rld or dyld */
01487 #endif
01488 
01489 #ifdef __BEOS__
01490 # define DLN_DEFINED
01491     {
01492       status_t err_stat;  /* BeOS error status code */
01493       image_id img_id;    /* extention module unique id */
01494       void (*init_fct)(); /* initialize function for extention module */
01495 
01496       /* load extention module */
01497       img_id = load_add_on(file);
01498       if (img_id <= 0) {
01499         rb_loaderror("Failed to load %.200s", file);
01500       }
01501       
01502       /* find symbol for module initialize function. */
01503       /* The Be Book KernelKit Images section described to use
01504          B_SYMBOL_TYPE_TEXT for symbol of function, not
01505          B_SYMBOL_TYPE_CODE. Why ? */
01506       /* strcat(init_fct_symname, "__Fv"); */  /* parameter nothing. */
01507       /* "__Fv" dont need! The Be Book Bug ? */
01508       err_stat = get_image_symbol(img_id, buf,
01509                                   B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
01510 
01511       if (err_stat != B_NO_ERROR) {
01512         char real_name[MAXPATHLEN];
01513 
01514         strcpy(real_name, buf);
01515         strcat(real_name, "__Fv");
01516         err_stat = get_image_symbol(img_id, real_name,
01517                                     B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
01518       }
01519 
01520       if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) {
01521         unload_add_on(img_id);
01522         rb_loaderror("Failed to lookup Init function %.200s", file);
01523       }
01524       else if (B_NO_ERROR != err_stat) {
01525         char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)";
01526         unload_add_on(img_id);
01527         rb_loaderror(errmsg, strerror(err_stat), buf);
01528       }
01529 
01530       /* call module initialize function. */
01531       (*init_fct)();
01532       return (void*)img_id;
01533     }
01534 #endif /* __BEOS__*/
01535 
01536 #ifdef __MACOS__
01537 # define DLN_DEFINED
01538     {
01539       OSErr err;
01540       FSSpec libspec;
01541       CFragConnectionID connID;
01542       Ptr mainAddr;
01543       char errMessage[1024];
01544       Boolean isfolder, didsomething;
01545       Str63 fragname;
01546       Ptr symAddr;
01547       CFragSymbolClass class;
01548       void (*init_fct)();
01549       char fullpath[MAXPATHLEN];
01550 
01551       strcpy(fullpath, file);
01552 
01553       /* resolve any aliases to find the real file */
01554       c2pstr(fullpath);
01555       (void)FSMakeFSSpec(0, 0, fullpath, &libspec);
01556       err = ResolveAliasFile(&libspec, 1, &isfolder, &didsomething);
01557       if (err) {
01558           rb_loaderror("Unresolved Alias - %s", file);
01559       }
01560 
01561       /* Load the fragment (or return the connID if it is already loaded */
01562       fragname[0] = 0;
01563       err = GetDiskFragment(&libspec, 0, 0, fragname, 
01564                             kLoadCFrag, &connID, &mainAddr,
01565                             errMessage);
01566       if (err) {
01567           p2cstr(errMessage);
01568           rb_loaderror("%s - %s",errMessage , file);
01569       }
01570 
01571       /* Locate the address of the correct init function */
01572       c2pstr(buf);
01573       err = FindSymbol(connID, buf, &symAddr, &class);
01574       if (err) {
01575           rb_loaderror("Unresolved symbols - %s" , file);
01576       }
01577       init_fct = (void (*)())symAddr;
01578       (*init_fct)();
01579       return (void*)init_fct;
01580     }
01581 #endif /* __MACOS__ */
01582 
01583 #if defined(__VMS)
01584 #define DLN_DEFINED
01585     {
01586         long status;
01587         void (*init_fct)();
01588         char *fname, *p1, *p2;
01589 
01590         $DESCRIPTOR(fname_d, "");
01591         $DESCRIPTOR(image_d, "");
01592         $DESCRIPTOR(buf_d, "");
01593 
01594         decc$to_vms(file, vms_fileact, 0, 0);
01595 
01596         fname = (char *)__alloca(strlen(file)+1);
01597         strcpy(fname,file);
01598         if (p1 = strrchr(fname,'/'))
01599             fname = p1 + 1;
01600         if (p2 = strrchr(fname,'.'))
01601             *p2 = '\0';
01602 
01603         fname_d.dsc$w_length  = strlen(fname);
01604         fname_d.dsc$a_pointer = fname;
01605         image_d.dsc$w_length  = strlen(vms_filespec);
01606         image_d.dsc$a_pointer = vms_filespec;
01607         buf_d.dsc$w_length    = strlen(buf);
01608         buf_d.dsc$a_pointer   = buf;
01609 
01610         lib$establish(vms_fisexh);
01611 
01612         status = lib$find_image_symbol (
01613                      &fname_d,
01614                      &buf_d, 
01615                      &init_fct, 
01616                      &image_d);
01617 
01618         lib$establish(0);
01619 
01620         if (status == RMS$_FNF) {
01621             error = dln_strerror();
01622             goto failed;
01623         } else if (!$VMS_STATUS_SUCCESS(status)) {
01624             error = DLN_ERROR();
01625             goto failed;
01626         }
01627 
01628         /* Call the init code */
01629         (*init_fct)();
01630 
01631         return 1;
01632     }
01633 #endif /* __VMS */
01634 
01635 #ifndef DLN_DEFINED
01636     rb_notimplement();
01637 #endif
01638 
01639 #endif /* USE_DLN_A_OUT */
01640 #endif
01641 #if !defined(_AIX) && !defined(NeXT)
01642   failed:
01643     rb_loaderror("%s - %s", error, file);
01644 #endif
01645 
01646 #endif /* NO_DLN_LOAD */
01647     return 0;                   /* dummy return */
01648 }
01649 
01650 static char *dln_find_1();
01651 
01652 char *
01653 dln_find_exe(fname, path)
01654     const char *fname;
01655     const char *path;
01656 {
01657     if (!path) {
01658         path = getenv(PATH_ENV);
01659     }
01660 
01661     if (!path) {
01662 #if defined(MSDOS) || defined(_WIN32) || defined(__human68k__) || defined(__MACOS__)
01663         path = "/usr/local/bin;/usr/ucb;/usr/bin;/bin;.";
01664 #else
01665         path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:.";
01666 #endif
01667     }
01668     return dln_find_1(fname, path, 1);
01669 }
01670 
01671 char *
01672 dln_find_file(fname, path)
01673     const char *fname;
01674     const char *path;
01675 {
01676 #ifndef __MACOS__
01677     if (!path) path = ".";
01678     return dln_find_1(fname, path, 0);
01679 #else
01680     if (!path) path = ".";
01681     return _macruby_path_conv_posix_to_macos(dln_find_1(fname, path, 0));
01682 #endif
01683 }
01684 
01685 #if defined(__CYGWIN32__)
01686 const char *
01687 conv_to_posix_path(win32, posix, len)
01688     char *win32;
01689     char *posix;
01690     int len;
01691 {
01692     char *first = win32;
01693     char *p = win32;
01694     char *dst = posix;
01695 
01696     posix[0] = '\0';
01697     for (p = win32; *p; p++)
01698         if (*p == ';') {
01699             *p = 0;
01700             cygwin32_conv_to_posix_path(first, posix);
01701             posix += strlen(posix);
01702             *posix++ = ':';
01703             first = p + 1;
01704             *p = ';';
01705         }
01706     if (len < strlen(first))
01707         fprintf(stderr, "PATH length too long: %s\n", first);
01708     else
01709         cygwin32_conv_to_posix_path(first, posix);
01710     return dst;
01711 }
01712 #endif
01713 
01714 static char fbuf[MAXPATHLEN];
01715 
01716 static char *
01717 dln_find_1(fname, path, exe_flag)
01718     char *fname;
01719     char *path;
01720     int exe_flag;               /* non 0 if looking for executable. */
01721 {
01722     register char *dp;
01723     register char *ep;
01724     register char *bp;
01725     struct stat st;
01726 #ifdef __MACOS__
01727     const char* mac_fullpath;
01728 #endif
01729 
01730     if (!fname) return fname;
01731     if (fname[0] == '/') return fname;
01732     if (strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0)
01733       return fname;
01734     if (exe_flag && strchr(fname, '/')) return fname;
01735 #ifdef DOSISH
01736     if (fname[0] == '\\') return fname;
01737 # ifdef DOSISH_DRIVE_LETTER
01738     if (strlen(fname) > 2 && fname[1] == ':') return fname;
01739 # endif
01740     if (strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0)
01741       return fname;
01742     if (exe_flag && strchr(fname, '\\')) return fname;
01743 #endif
01744 
01745     for (dp = path;; dp = ++ep) {
01746         register int l;
01747         int i;
01748         int fspace;
01749 
01750         /* extract a component */
01751         ep = strchr(dp, PATH_SEP[0]);
01752         if (ep == NULL)
01753             ep = dp+strlen(dp);
01754 
01755         /* find the length of that component */
01756         l = ep - dp;
01757         bp = fbuf;
01758         fspace = sizeof fbuf - 2;
01759         if (l > 0) {
01760             /*
01761             **  If the length of the component is zero length,
01762             **  start from the current directory.  If the
01763             **  component begins with "~", start from the
01764             **  user's $HOME environment variable.  Otherwise
01765             **  take the path literally.
01766             */
01767 
01768             if (*dp == '~' && (l == 1 ||
01769 #if defined(DOSISH)
01770                                dp[1] == '\\' || 
01771 #endif
01772                                dp[1] == '/')) {
01773                 char *home;
01774 
01775                 home = getenv("HOME");
01776                 if (home != NULL) {
01777                     i = strlen(home);
01778                     if ((fspace -= i) < 0)
01779                         goto toolong;
01780                     memcpy(bp, home, i);
01781                     bp += i;
01782                 }
01783                 dp++;
01784                 l--;
01785             }
01786             if (l > 0) {
01787                 if ((fspace -= l) < 0)
01788                     goto toolong;
01789                 memcpy(bp, dp, l);
01790                 bp += l;
01791             }
01792 
01793             /* add a "/" between directory and filename */
01794             if (ep[-1] != '/')
01795                 *bp++ = '/';
01796         }
01797 
01798         /* now append the file name */
01799         i = strlen(fname);
01800         if ((fspace -= i) < 0) {
01801           toolong:
01802             fprintf(stderr, "openpath: pathname too long (ignored)\n");
01803             *bp = '\0';
01804             fprintf(stderr, "\tDirectory \"%s\"\n", fbuf);
01805             fprintf(stderr, "\tFile \"%s\"\n", fname);
01806             goto next;
01807         }
01808         memcpy(bp, fname, i + 1);
01809 
01810 #ifndef __MACOS__
01811         if (stat(fbuf, &st) == 0) {
01812             if (exe_flag == 0) return fbuf;
01813             /* looking for executable */
01814             if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
01815                 return fbuf;
01816         }
01817 #else
01818         if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) {
01819             if (exe_flag == 0) return mac_fullpath;
01820             /* looking for executable */
01821             if (stat(mac_fullpath, &st) == 0) {
01822                 if (!S_ISDIR(st.st_mode) && eaccess(mac_fullpath, X_OK) == 0)
01823                     return mac_fullpath;
01824             }
01825         }
01826 #endif
01827 #if defined(DOSISH)
01828         if (exe_flag) {
01829             static const char *extension[] = {
01830 #if defined(MSDOS)
01831                 ".com", ".exe", ".bat",
01832 #if defined(DJGPP)
01833                 ".btm", ".sh", ".ksh", ".pl", ".sed",
01834 #endif
01835 #elif defined(__EMX__) || defined(_WIN32)
01836                 ".exe", ".com", ".cmd", ".bat",
01837 /* end of __EMX__ or _WIN32 */
01838 #else
01839                 ".r", ".R", ".x", ".X", ".bat", ".BAT",
01840 /* __human68k__ */
01841 #endif
01842                 (char *) NULL
01843             };
01844             int j;
01845 
01846             for (j = 0; extension[j]; j++) {
01847                 if (fspace < strlen(extension[j])) {
01848                     fprintf(stderr, "openpath: pathname too long (ignored)\n");
01849                     fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf);
01850                     fprintf(stderr, "\tFile \"%s%s\"\n", fname, extension[j]);
01851                     continue;
01852                 }
01853                 strcpy(bp + i, extension[j]);
01854 #ifndef __MACOS__
01855                 if (stat(fbuf, &st) == 0)
01856                     return fbuf;
01857 #else
01858                 if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf))
01859                     return mac_fullpath;
01860 
01861 #endif
01862             }
01863         }
01864 #endif /* MSDOS or _WIN32 or __human68k__ or __EMX__ */
01865 
01866       next:
01867         /* if not, and no other alternatives, life is bleak */
01868         if (*ep == '\0') {
01869             return NULL;
01870         }
01871 
01872         /* otherwise try the next component in the search path */
01873     }
01874 }
01875 
01876 #if defined(__VMS)
01877 
01878 /* action routine for decc$to_vms */
01879 static int vms_fileact(char *filespec, int type)
01880 {
01881     if (vms_filespec)
01882         free(vms_filespec);
01883     vms_filespec = malloc(strlen(filespec)+1);
01884     strcpy(vms_filespec, filespec);
01885     return 1;
01886 }
01887 
01888 /* exception handler for LIB$FIND_IMAGE_SYMBOL */
01889 static long vms_fisexh(long *sigarr, long *mecarr)
01890 {
01891     sys$unwind(1, 0);
01892     return 1;
01893 }
01894 
01895 #endif /* __VMS */
01896 

Generated on Wed Jan 18 23:31:58 2006 for Ruby by doxygen 1.3.5