* include/ruby/io.h (rb_io_t): new fields: writeconv,
[ruby-svn.git] / dln.c
blob6fc97787e615e69ca24ff42c2855251e3f0f5dfa
1 /**********************************************************************
3 dln.c -
5 $Author$
6 created at: Tue Jan 18 17:05:06 JST 1994
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
10 **********************************************************************/
12 #include "ruby/ruby.h"
13 #include "dln.h"
15 #ifdef HAVE_STDLIB_H
16 # include <stdlib.h>
17 #endif
19 #ifdef __CHECKER__
20 #undef HAVE_DLOPEN
21 #undef USE_DLN_A_OUT
22 #undef USE_DLN_DLOPEN
23 #endif
25 #ifdef USE_DLN_A_OUT
26 char *dln_argv0;
27 #endif
29 #if defined(HAVE_ALLOCA_H)
30 #include <alloca.h>
31 #endif
33 #ifdef HAVE_STRING_H
34 # include <string.h>
35 #else
36 # include <strings.h>
37 #endif
39 #ifndef xmalloc
40 void *xmalloc();
41 void *xcalloc();
42 void *xrealloc();
43 #endif
45 #define free(x) xfree(x)
47 #include <stdio.h>
48 #if defined(_WIN32) || defined(__VMS)
49 #include "missing/file.h"
50 #endif
51 #include <sys/types.h>
52 #include <sys/stat.h>
54 #ifndef S_ISDIR
55 # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
56 #endif
58 #ifdef HAVE_SYS_PARAM_H
59 # include <sys/param.h>
60 #endif
61 #ifndef MAXPATHLEN
62 # define MAXPATHLEN 1024
63 #endif
65 #ifdef HAVE_UNISTD_H
66 # include <unistd.h>
67 #endif
69 #ifndef _WIN32
70 char *getenv();
71 #endif
73 #if defined(__VMS)
74 #pragma builtins
75 #include <dlfcn.h>
76 #endif
78 #ifdef __MACOS__
79 # include <TextUtils.h>
80 # include <CodeFragments.h>
81 # include <Aliases.h>
82 # include "macruby_private.h"
83 #endif
85 #if defined(__APPLE__) && defined(__MACH__) /* Mac OS X */
86 # if defined(HAVE_DLOPEN)
87 /* Mac OS X with dlopen (10.3 or later) */
88 # define MACOSX_DLOPEN
89 # else
90 # define MACOSX_DYLD
91 # endif
92 #endif
94 #ifdef __BEOS__
95 # include <image.h>
96 #endif
98 #ifndef NO_DLN_LOAD
100 #if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX) && !defined(MACOSX_DYLD) && !defined(_UNICOSMP)
101 /* dynamic load with dlopen() */
102 # define USE_DLN_DLOPEN
103 #endif
105 #ifndef FUNCNAME_PATTERN
106 # if defined(__hp9000s300) || (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || (defined(__OpenBSD__) && !defined(__ELF__)) || defined(NeXT) || defined(__WATCOMC__) || defined(MACOSX_DYLD)
107 # define FUNCNAME_PATTERN "_Init_%s"
108 # else
109 # define FUNCNAME_PATTERN "Init_%s"
110 # endif
111 #endif
113 static int
114 init_funcname_len(char **buf, const char *file)
116 char *p;
117 const char *slash;
118 int len;
120 /* Load the file as an object one */
121 for (slash = file-1; *file; file++) /* Find position of last '/' */
122 #ifdef __MACOS__
123 if (*file == ':') slash = file;
124 #else
125 if (*file == '/') slash = file;
126 #endif
128 len = strlen(FUNCNAME_PATTERN) + strlen(slash + 1);
129 *buf = xmalloc(len);
130 snprintf(*buf, len, FUNCNAME_PATTERN, slash + 1);
131 for (p = *buf; *p; p++) { /* Delete suffix if it exists */
132 if (*p == '.') {
133 *p = '\0'; break;
136 return p - *buf;
139 #define init_funcname(buf, file) do {\
140 int len = init_funcname_len(buf, file);\
141 char *tmp = ALLOCA_N(char, len+1);\
142 if (!tmp) {\
143 free(*buf);\
144 rb_memerror();\
146 strcpy(tmp, *buf);\
147 free(*buf);\
148 *buf = tmp;\
149 } while (0)
151 #ifdef USE_DLN_A_OUT
153 #ifndef LIBC_NAME
154 # define LIBC_NAME "libc.a"
155 #endif
157 #ifndef DLN_DEFAULT_LIB_PATH
158 # define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:."
159 #endif
161 #include <errno.h>
163 static int dln_errno;
165 #define DLN_ENOEXEC ENOEXEC /* Exec format error */
166 #define DLN_ECONFL 1201 /* Symbol name conflict */
167 #define DLN_ENOINIT 1202 /* No initializer given */
168 #define DLN_EUNDEF 1203 /* Undefine symbol remains */
169 #define DLN_ENOTLIB 1204 /* Not a library file */
170 #define DLN_EBADLIB 1205 /* Malformed library file */
171 #define DLN_EINIT 1206 /* Not initialized */
173 static int dln_init_p = 0;
175 #include <ar.h>
176 #include <a.out.h>
177 #ifndef N_COMM
178 # define N_COMM 0x12
179 #endif
180 #ifndef N_MAGIC
181 # define N_MAGIC(x) (x).a_magic
182 #endif
184 #define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC)
186 #include "ruby/util.h"
187 #include "ruby/st.h"
189 static st_table *sym_tbl;
190 static st_table *undef_tbl;
192 static int load_lib();
194 static int
195 load_header(int fd, struct exec *hdrp, long disp)
197 int size;
199 lseek(fd, disp, 0);
200 size = read(fd, hdrp, sizeof(struct exec));
201 if (size == -1) {
202 dln_errno = errno;
203 return -1;
205 if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) {
206 dln_errno = DLN_ENOEXEC;
207 return -1;
209 return 0;
212 #if defined(sequent)
213 #define RELOC_SYMBOL(r) ((r)->r_symbolnum)
214 #define RELOC_MEMORY_SUB_P(r) ((r)->r_bsr)
215 #define RELOC_PCREL_P(r) ((r)->r_pcrel || (r)->r_bsr)
216 #define RELOC_TARGET_SIZE(r) ((r)->r_length)
217 #endif
219 /* Default macros */
220 #ifndef RELOC_ADDRESS
221 #define RELOC_ADDRESS(r) ((r)->r_address)
222 #define RELOC_EXTERN_P(r) ((r)->r_extern)
223 #define RELOC_SYMBOL(r) ((r)->r_symbolnum)
224 #define RELOC_MEMORY_SUB_P(r) 0
225 #define RELOC_PCREL_P(r) ((r)->r_pcrel)
226 #define RELOC_TARGET_SIZE(r) ((r)->r_length)
227 #endif
229 #if defined(sun) && defined(sparc)
230 /* Sparc (Sun 4) macros */
231 # undef relocation_info
232 # define relocation_info reloc_info_sparc
233 # define R_RIGHTSHIFT(r) (reloc_r_rightshift[(r)->r_type])
234 # define R_BITSIZE(r) (reloc_r_bitsize[(r)->r_type])
235 # define R_LENGTH(r) (reloc_r_length[(r)->r_type])
236 static int reloc_r_rightshift[] = {
237 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0,
239 static int reloc_r_bitsize[] = {
240 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16,
242 static int reloc_r_length[] = {
243 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
245 # define R_PCREL(r) \
246 ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22)
247 # define R_SYMBOL(r) ((r)->r_index)
248 #endif
250 #if defined(sequent)
251 #define R_SYMBOL(r) ((r)->r_symbolnum)
252 #define R_MEMORY_SUB(r) ((r)->r_bsr)
253 #define R_PCREL(r) ((r)->r_pcrel || (r)->r_bsr)
254 #define R_LENGTH(r) ((r)->r_length)
255 #endif
257 #ifndef R_SYMBOL
258 # define R_SYMBOL(r) ((r)->r_symbolnum)
259 # define R_MEMORY_SUB(r) 0
260 # define R_PCREL(r) ((r)->r_pcrel)
261 # define R_LENGTH(r) ((r)->r_length)
262 #endif
264 static struct relocation_info *
265 load_reloc(int fd, struct exec *hdrp, long disp)
267 struct relocation_info *reloc;
268 int size;
270 lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
271 size = hdrp->a_trsize + hdrp->a_drsize;
272 reloc = (struct relocation_info*)xmalloc(size);
273 if (reloc == NULL) {
274 dln_errno = errno;
275 return NULL;
278 if (read(fd, reloc, size) != size) {
279 dln_errno = errno;
280 free(reloc);
281 return NULL;
284 return reloc;
287 static struct nlist *
288 load_sym(int fd, struct exec *hdrp, long disp)
290 struct nlist * buffer;
291 struct nlist * sym;
292 struct nlist * end;
293 long displ;
294 int size;
296 lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0);
297 if (read(fd, &size, sizeof(int)) != sizeof(int)) {
298 goto err_noexec;
301 buffer = (struct nlist*)xmalloc(hdrp->a_syms + size);
302 if (buffer == NULL) {
303 dln_errno = errno;
304 return NULL;
307 lseek(fd, disp + N_SYMOFF(*hdrp), 0);
308 if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) {
309 free(buffer);
310 goto err_noexec;
313 sym = buffer;
314 end = sym + hdrp->a_syms / sizeof(struct nlist);
315 displ = (long)buffer + (long)(hdrp->a_syms);
317 while (sym < end) {
318 sym->n_un.n_name = (char*)sym->n_un.n_strx + displ;
319 sym++;
321 return buffer;
323 err_noexec:
324 dln_errno = DLN_ENOEXEC;
325 return NULL;
328 static st_table *
329 sym_hash(struct exec *hdrp, struct nlist *syms)
331 st_table *tbl;
332 struct nlist *sym = syms;
333 struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist));
335 tbl = st_init_strtable();
336 if (tbl == NULL) {
337 dln_errno = errno;
338 return NULL;
341 while (sym < end) {
342 st_insert(tbl, sym->n_un.n_name, sym);
343 sym++;
345 return tbl;
348 static int
349 dln_init(const char *prog)
351 char *file, fbuf[MAXPATHLEN];
352 int fd;
353 struct exec hdr;
354 struct nlist *syms;
356 if (dln_init_p == 1) return 0;
358 file = dln_find_exe_r(prog, NULL, fbuf, sizeof(fbuf));
359 if (file == NULL || (fd = open(file, O_RDONLY)) < 0) {
360 dln_errno = errno;
361 return -1;
364 if (load_header(fd, &hdr, 0) == -1) return -1;
365 syms = load_sym(fd, &hdr, 0);
366 if (syms == NULL) {
367 close(fd);
368 return -1;
370 sym_tbl = sym_hash(&hdr, syms);
371 if (sym_tbl == NULL) { /* file may be start with #! */
372 char c = '\0';
373 char buf[MAXPATHLEN];
374 char *p;
376 free(syms);
377 lseek(fd, 0L, 0);
378 if (read(fd, &c, 1) == -1) {
379 dln_errno = errno;
380 return -1;
382 if (c != '#') goto err_noexec;
383 if (read(fd, &c, 1) == -1) {
384 dln_errno = errno;
385 return -1;
387 if (c != '!') goto err_noexec;
389 p = buf;
390 /* skip forwarding spaces */
391 while (read(fd, &c, 1) == 1) {
392 if (c == '\n') goto err_noexec;
393 if (c != '\t' && c != ' ') {
394 *p++ = c;
395 break;
398 /* read in command name */
399 while (read(fd, p, 1) == 1) {
400 if (*p == '\n' || *p == '\t' || *p == ' ') break;
401 p++;
402 if (p-buf >= MAXPATHLEN) {
403 dln_errno = ENAMETOOLONG;
404 return -1;
407 *p = '\0';
409 return dln_init(buf);
411 dln_init_p = 1;
412 undef_tbl = st_init_strtable();
413 close(fd);
414 return 0;
416 err_noexec:
417 close(fd);
418 dln_errno = DLN_ENOEXEC;
419 return -1;
422 static long
423 load_text_data(int fd, struct exec *hdrp, int bss, long disp)
425 int size;
426 unsigned char* addr;
428 lseek(fd, disp + N_TXTOFF(*hdrp), 0);
429 size = hdrp->a_text + hdrp->a_data;
431 if (bss == -1) size += hdrp->a_bss;
432 else if (bss > 1) size += bss;
434 addr = (unsigned char*)xmalloc(size);
435 if (addr == NULL) {
436 dln_errno = errno;
437 return 0;
440 if (read(fd, addr, size) != size) {
441 dln_errno = errno;
442 free(addr);
443 return 0;
446 if (bss == -1) {
447 memset(addr + hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss);
449 else if (bss > 0) {
450 memset(addr + hdrp->a_text + hdrp->a_data, 0, bss);
453 return (long)addr;
456 static int
457 undef_print(char *key, char *value)
459 fprintf(stderr, " %s\n", key);
460 return ST_CONTINUE;
463 static void
464 dln_print_undef()
466 fprintf(stderr, " Undefined symbols:\n");
467 st_foreach(undef_tbl, undef_print, NULL);
470 static void
471 dln_undefined()
473 if (undef_tbl->num_entries > 0) {
474 fprintf(stderr, "dln: Calling undefined function\n");
475 dln_print_undef();
476 rb_exit(1);
480 struct undef {
481 char *name;
482 struct relocation_info reloc;
483 long base;
484 char *addr;
485 union {
486 char c;
487 short s;
488 long l;
489 } u;
492 static st_table *reloc_tbl = NULL;
493 static void
494 link_undef(const char *name, long base, struct relocation_info *reloc)
496 static int u_no = 0;
497 struct undef *obj;
498 char *addr = (char*)(reloc->r_address + base);
500 obj = (struct undef*)xmalloc(sizeof(struct undef));
501 obj->name = strdup(name);
502 obj->reloc = *reloc;
503 obj->base = base;
504 switch (R_LENGTH(reloc)) {
505 case 0: /* byte */
506 obj->u.c = *addr;
507 break;
508 case 1: /* word */
509 obj->u.s = *(short*)addr;
510 break;
511 case 2: /* long */
512 obj->u.l = *(long*)addr;
513 break;
515 if (reloc_tbl == NULL) {
516 reloc_tbl = st_init_numtable();
518 st_insert(reloc_tbl, u_no++, obj);
521 struct reloc_arg {
522 const char *name;
523 long value;
526 static int
527 reloc_undef(int no, struct undef *undef, struct reloc_arg *arg)
529 int datum;
530 char *address;
531 #if defined(sun) && defined(sparc)
532 unsigned int mask = 0;
533 #endif
535 if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE;
536 address = (char*)(undef->base + undef->reloc.r_address);
537 datum = arg->value;
539 if (R_PCREL(&(undef->reloc))) datum -= undef->base;
540 #if defined(sun) && defined(sparc)
541 datum += undef->reloc.r_addend;
542 datum >>= R_RIGHTSHIFT(&(undef->reloc));
543 mask = (1 << R_BITSIZE(&(undef->reloc))) - 1;
544 mask |= mask -1;
545 datum &= mask;
546 switch (R_LENGTH(&(undef->reloc))) {
547 case 0:
548 *address = undef->u.c;
549 *address &= ~mask;
550 *address |= datum;
551 break;
552 case 1:
553 *(short *)address = undef->u.s;
554 *(short *)address &= ~mask;
555 *(short *)address |= datum;
556 break;
557 case 2:
558 *(long *)address = undef->u.l;
559 *(long *)address &= ~mask;
560 *(long *)address |= datum;
561 break;
563 #else
564 switch (R_LENGTH(&(undef->reloc))) {
565 case 0: /* byte */
566 if (R_MEMORY_SUB(&(undef->reloc)))
567 *address = datum - *address;
568 else *address = undef->u.c + datum;
569 break;
570 case 1: /* word */
571 if (R_MEMORY_SUB(&(undef->reloc)))
572 *(short*)address = datum - *(short*)address;
573 else *(short*)address = undef->u.s + datum;
574 break;
575 case 2: /* long */
576 if (R_MEMORY_SUB(&(undef->reloc)))
577 *(long*)address = datum - *(long*)address;
578 else *(long*)address = undef->u.l + datum;
579 break;
581 #endif
582 free(undef->name);
583 free(undef);
584 return ST_DELETE;
587 static void
588 unlink_undef(const char *name, long value)
590 struct reloc_arg arg;
592 arg.name = name;
593 arg.value = value;
594 st_foreach(reloc_tbl, reloc_undef, &arg);
597 #ifdef N_INDR
598 struct indr_data {
599 char *name0, *name1;
602 static int
603 reloc_repl(int no, struct undef *undef, struct indr_data *data)
605 if (strcmp(data->name0, undef->name) == 0) {
606 free(undef->name);
607 undef->name = strdup(data->name1);
609 return ST_CONTINUE;
611 #endif
613 static int
614 load_1(int fd, long disp, const char *need_init)
616 static const char *libc = LIBC_NAME;
617 struct exec hdr;
618 struct relocation_info *reloc = NULL;
619 long block = 0;
620 long new_common = 0; /* Length of new common */
621 struct nlist *syms = NULL;
622 struct nlist *sym;
623 struct nlist *end;
624 int init_p = 0;
626 if (load_header(fd, &hdr, disp) == -1) return -1;
627 if (INVALID_OBJECT(hdr)) {
628 dln_errno = DLN_ENOEXEC;
629 return -1;
631 reloc = load_reloc(fd, &hdr, disp);
632 if (reloc == NULL) return -1;
634 syms = load_sym(fd, &hdr, disp);
635 if (syms == NULL) {
636 free(reloc);
637 return -1;
640 sym = syms;
641 end = syms + (hdr.a_syms / sizeof(struct nlist));
642 while (sym < end) {
643 struct nlist *old_sym;
644 int value = sym->n_value;
646 #ifdef N_INDR
647 if (sym->n_type == (N_INDR | N_EXT)) {
648 char *key = sym->n_un.n_name;
650 if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) {
651 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) {
652 unlink_undef(key, old_sym->n_value);
653 free(key);
656 else {
657 struct indr_data data;
659 data.name0 = sym->n_un.n_name;
660 data.name1 = sym[1].n_un.n_name;
661 st_foreach(reloc_tbl, reloc_repl, &data);
663 st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL);
664 if (st_delete(undef_tbl, (st_data_t*)&key, NULL)) {
665 free(key);
668 sym += 2;
669 continue;
671 #endif
672 if (sym->n_type == (N_UNDF | N_EXT)) {
673 if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) {
674 old_sym = NULL;
677 if (value) {
678 if (old_sym) {
679 sym->n_type = N_EXT | N_COMM;
680 sym->n_value = old_sym->n_value;
682 else {
683 int rnd =
684 value >= sizeof(double) ? sizeof(double) - 1
685 : value >= sizeof(long) ? sizeof(long) - 1
686 : sizeof(short) - 1;
688 sym->n_type = N_COMM;
689 new_common += rnd;
690 new_common &= ~(long)rnd;
691 sym->n_value = new_common;
692 new_common += value;
695 else {
696 if (old_sym) {
697 sym->n_type = N_EXT | N_COMM;
698 sym->n_value = old_sym->n_value;
700 else {
701 sym->n_value = (long)dln_undefined;
702 st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL);
706 sym++;
709 block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp);
710 if (block == 0) goto err_exit;
712 sym = syms;
713 while (sym < end) {
714 struct nlist *new_sym;
715 char *key;
717 switch (sym->n_type) {
718 case N_COMM:
719 sym->n_value += hdr.a_text + hdr.a_data;
720 case N_TEXT|N_EXT:
721 case N_DATA|N_EXT:
723 sym->n_value += block;
725 if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0
726 && new_sym->n_value != (long)dln_undefined) {
727 dln_errno = DLN_ECONFL;
728 goto err_exit;
731 key = sym->n_un.n_name;
732 if (st_delete(undef_tbl, (st_data_t*)&key, NULL) != 0) {
733 unlink_undef(key, sym->n_value);
734 free(key);
737 new_sym = (struct nlist*)xmalloc(sizeof(struct nlist));
738 *new_sym = *sym;
739 new_sym->n_un.n_name = strdup(sym->n_un.n_name);
740 st_insert(sym_tbl, new_sym->n_un.n_name, new_sym);
741 break;
743 case N_TEXT:
744 case N_DATA:
745 sym->n_value += block;
746 break;
748 sym++;
752 * First comes the text-relocation
755 struct relocation_info * rel = reloc;
756 struct relocation_info * rel_beg = reloc +
757 (hdr.a_trsize/sizeof(struct relocation_info));
758 struct relocation_info * rel_end = reloc +
759 (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info);
761 while (rel < rel_end) {
762 char *address = (char*)(rel->r_address + block);
763 long datum = 0;
764 #if defined(sun) && defined(sparc)
765 unsigned int mask = 0;
766 #endif
768 if(rel >= rel_beg)
769 address += hdr.a_text;
771 if (rel->r_extern) { /* Look it up in symbol-table */
772 sym = &(syms[R_SYMBOL(rel)]);
773 switch (sym->n_type) {
774 case N_EXT|N_UNDF:
775 link_undef(sym->n_un.n_name, block, rel);
776 case N_EXT|N_COMM:
777 case N_COMM:
778 datum = sym->n_value;
779 break;
780 default:
781 goto err_exit;
783 } /* end.. look it up */
784 else { /* is static */
785 switch (R_SYMBOL(rel)) {
786 case N_TEXT:
787 case N_DATA:
788 datum = block;
789 break;
790 case N_BSS:
791 datum = block + new_common;
792 break;
793 case N_ABS:
794 break;
796 } /* end .. is static */
797 if (R_PCREL(rel)) datum -= block;
799 #if defined(sun) && defined(sparc)
800 datum += rel->r_addend;
801 datum >>= R_RIGHTSHIFT(rel);
802 mask = (1 << R_BITSIZE(rel)) - 1;
803 mask |= mask -1;
804 datum &= mask;
806 switch (R_LENGTH(rel)) {
807 case 0:
808 *address &= ~mask;
809 *address |= datum;
810 break;
811 case 1:
812 *(short *)address &= ~mask;
813 *(short *)address |= datum;
814 break;
815 case 2:
816 *(long *)address &= ~mask;
817 *(long *)address |= datum;
818 break;
820 #else
821 switch (R_LENGTH(rel)) {
822 case 0: /* byte */
823 if (datum < -128 || datum > 127) goto err_exit;
824 *address += datum;
825 break;
826 case 1: /* word */
827 *(short *)address += datum;
828 break;
829 case 2: /* long */
830 *(long *)address += datum;
831 break;
833 #endif
834 rel++;
838 if (need_init) {
839 int len;
840 char **libs_to_be_linked = 0;
841 char *buf;
843 if (undef_tbl->num_entries > 0) {
844 if (load_lib(libc) == -1) goto err_exit;
847 init_funcname(&buf, need_init);
848 len = strlen(buf);
850 for (sym = syms; sym<end; sym++) {
851 char *name = sym->n_un.n_name;
852 if (name[0] == '_' && sym->n_value >= block) {
853 if (strcmp(name+1, "dln_libs_to_be_linked") == 0) {
854 libs_to_be_linked = (char**)sym->n_value;
856 else if (strcmp(name+1, buf) == 0) {
857 init_p = 1;
858 ((int (*)())sym->n_value)();
862 if (libs_to_be_linked && undef_tbl->num_entries > 0) {
863 while (*libs_to_be_linked) {
864 load_lib(*libs_to_be_linked);
865 libs_to_be_linked++;
869 free(reloc);
870 free(syms);
871 if (need_init) {
872 if (init_p == 0) {
873 dln_errno = DLN_ENOINIT;
874 return -1;
876 if (undef_tbl->num_entries > 0) {
877 if (load_lib(libc) == -1) goto err_exit;
878 if (undef_tbl->num_entries > 0) {
879 dln_errno = DLN_EUNDEF;
880 return -1;
884 return 0;
886 err_exit:
887 if (syms) free(syms);
888 if (reloc) free(reloc);
889 if (block) free((char*)block);
890 return -1;
893 static int target_offset;
894 static int
895 search_undef(const char *key, int value, st_table *lib_tbl)
897 long offset;
899 if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
900 target_offset = offset;
901 return ST_STOP;
904 struct symdef {
905 int rb_str_index;
906 int lib_offset;
909 char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH;
911 static int
912 load_lib(const char *lib)
914 char *path, *file, fbuf[MAXPATHLEN];
915 char armagic[SARMAG];
916 int fd, size;
917 struct ar_hdr ahdr;
918 st_table *lib_tbl = NULL;
919 int *data, nsym;
920 struct symdef *base;
921 char *name_base;
923 if (dln_init_p == 0) {
924 dln_errno = DLN_ENOINIT;
925 return -1;
928 if (undef_tbl->num_entries == 0) return 0;
929 dln_errno = DLN_EBADLIB;
931 if (lib[0] == '-' && lib[1] == 'l') {
932 long len = strlen(lib) + 4;
933 char *p = alloca(len);
934 snprintf(p, len, "lib%s.a", lib+2);
935 lib = p;
938 /* library search path: */
939 /* look for environment variable DLN_LIBRARY_PATH first. */
940 /* then variable dln_librrb_ary_path. */
941 /* if path is still NULL, use "." for path. */
942 path = getenv("DLN_LIBRARY_PATH");
943 if (path == NULL) path = dln_librrb_ary_path;
945 file = dln_find_file_r(lib, path, fbuf, sizeof(fbuf));
946 fd = open(file, O_RDONLY);
947 if (fd == -1) goto syserr;
948 size = read(fd, armagic, SARMAG);
949 if (size == -1) goto syserr;
951 if (size != SARMAG) {
952 dln_errno = DLN_ENOTLIB;
953 goto badlib;
955 size = read(fd, &ahdr, sizeof(ahdr));
956 if (size == -1) goto syserr;
957 if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) {
958 goto badlib;
961 if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) {
962 /* make hash table from __.SYMDEF */
964 lib_tbl = st_init_strtable();
965 data = (int*)xmalloc(size);
966 if (data == NULL) goto syserr;
967 size = read(fd, data, size);
968 nsym = *data / sizeof(struct symdef);
969 base = (struct symdef*)(data + 1);
970 name_base = (char*)(base + nsym) + sizeof(int);
971 while (nsym > 0) {
972 char *name = name_base + base->rb_str_index;
974 st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr));
975 nsym--;
976 base++;
978 for (;;) {
979 target_offset = -1;
980 st_foreach(undef_tbl, search_undef, lib_tbl);
981 if (target_offset == -1) break;
982 if (load_1(fd, target_offset, 0) == -1) {
983 st_free_table(lib_tbl);
984 free(data);
985 goto badlib;
987 if (undef_tbl->num_entries == 0) break;
989 free(data);
990 st_free_table(lib_tbl);
992 else {
993 /* linear library, need to scan (FUTURE) */
995 for (;;) {
996 int offset = SARMAG;
997 int found = 0;
998 struct exec hdr;
999 struct nlist *syms, *sym, *end;
1001 while (undef_tbl->num_entries > 0) {
1002 found = 0;
1003 lseek(fd, offset, 0);
1004 size = read(fd, &ahdr, sizeof(ahdr));
1005 if (size == -1) goto syserr;
1006 if (size == 0) break;
1007 if (size != sizeof(ahdr)
1008 || sscanf(ahdr.ar_size, "%d", &size) != 1) {
1009 goto badlib;
1011 offset += sizeof(ahdr);
1012 if (load_header(fd, &hdr, offset) == -1)
1013 goto badlib;
1014 syms = load_sym(fd, &hdr, offset);
1015 if (syms == NULL) goto badlib;
1016 sym = syms;
1017 end = syms + (hdr.a_syms / sizeof(struct nlist));
1018 while (sym < end) {
1019 if (sym->n_type == N_EXT|N_TEXT
1020 && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) {
1021 break;
1023 sym++;
1025 if (sym < end) {
1026 found++;
1027 free(syms);
1028 if (load_1(fd, offset, 0) == -1) {
1029 goto badlib;
1032 offset += size;
1033 if (offset & 1) offset++;
1035 if (found) break;
1038 close(fd);
1039 return 0;
1041 syserr:
1042 dln_errno = errno;
1043 badlib:
1044 if (fd >= 0) close(fd);
1045 return -1;
1048 static int
1049 load(const char *file)
1051 int fd;
1052 int result;
1054 if (dln_init_p == 0) {
1055 if (dln_init(dln_argv0) == -1) return -1;
1057 result = strlen(file);
1058 if (file[result-1] == 'a') {
1059 return load_lib(file);
1062 fd = open(file, O_RDONLY);
1063 if (fd == -1) {
1064 dln_errno = errno;
1065 return -1;
1067 result = load_1(fd, 0, file);
1068 close(fd);
1070 return result;
1073 void*
1074 dln_sym(const char *name)
1076 struct nlist *sym;
1078 if (st_lookup(sym_tbl, name, &sym))
1079 return (void*)sym->n_value;
1080 return NULL;
1083 #endif /* USE_DLN_A_OUT */
1085 #ifdef USE_DLN_DLOPEN
1086 # include <dlfcn.h>
1087 #endif
1089 #ifdef __hpux
1090 #include <errno.h>
1091 #include "dl.h"
1092 #endif
1094 #if defined(_AIX)
1095 #include <ctype.h> /* for isdigit() */
1096 #include <errno.h> /* for global errno */
1097 #include <sys/ldr.h>
1098 #endif
1100 #ifdef NeXT
1101 #if NS_TARGET_MAJOR < 4
1102 #include <mach-o/rld.h>
1103 #else
1104 #include <mach-o/dyld.h>
1105 #ifndef NSLINKMODULE_OPTION_BINDNOW
1106 #define NSLINKMODULE_OPTION_BINDNOW 1
1107 #endif
1108 #endif
1109 #else
1110 #ifdef MACOSX_DYLD
1111 #include <mach-o/dyld.h>
1112 #endif
1113 #endif
1115 #if defined _WIN32 && !defined __CYGWIN__
1116 #include <windows.h>
1117 #endif
1119 #ifdef _WIN32_WCE
1120 #undef FormatMessage
1121 #define FormatMessage FormatMessageA
1122 #undef LoadLibrary
1123 #define LoadLibrary LoadLibraryA
1124 #undef GetProcAddress
1125 #define GetProcAddress GetProcAddressA
1126 #endif
1128 static const char *
1129 dln_strerror(void)
1131 #ifdef USE_DLN_A_OUT
1132 char *strerror();
1134 switch (dln_errno) {
1135 case DLN_ECONFL:
1136 return "Symbol name conflict";
1137 case DLN_ENOINIT:
1138 return "No initializer given";
1139 case DLN_EUNDEF:
1140 return "Unresolved symbols";
1141 case DLN_ENOTLIB:
1142 return "Not a library file";
1143 case DLN_EBADLIB:
1144 return "Malformed library file";
1145 case DLN_EINIT:
1146 return "Not initialized";
1147 default:
1148 return strerror(dln_errno);
1150 #endif
1152 #ifdef USE_DLN_DLOPEN
1153 return (char*)dlerror();
1154 #endif
1156 #if defined _WIN32 && !defined __CYGWIN__
1157 static char message[1024];
1158 int error = GetLastError();
1159 char *p = message;
1160 p += sprintf(message, "%d: ", error);
1161 FormatMessage(
1162 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1163 NULL,
1164 error,
1165 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1167 sizeof message - strlen(message),
1168 NULL);
1170 for (p = message; *p; p++) {
1171 if (*p == '\n' || *p == '\r')
1172 *p = ' ';
1174 return message;
1175 #endif
1179 #if defined(_AIX) && ! defined(_IA64)
1180 static void
1181 aix_loaderror(const char *pathname)
1183 char *message[8], errbuf[1024];
1184 int i,j;
1186 struct errtab {
1187 int errnum;
1188 char *errstr;
1189 } load_errtab[] = {
1190 {L_ERROR_TOOMANY, "too many errors, rest skipped."},
1191 {L_ERROR_NOLIB, "can't load library:"},
1192 {L_ERROR_UNDEF, "can't find symbol in library:"},
1193 {L_ERROR_RLDBAD,
1194 "RLD index out of range or bad relocation type:"},
1195 {L_ERROR_FORMAT, "not a valid, executable xcoff file:"},
1196 {L_ERROR_MEMBER,
1197 "file not an archive or does not contain requested member:"},
1198 {L_ERROR_TYPE, "symbol table mismatch:"},
1199 {L_ERROR_ALIGN, "text alignment in file is wrong."},
1200 {L_ERROR_SYSTEM, "System error:"},
1201 {L_ERROR_ERRNO, NULL}
1204 #define LOAD_ERRTAB_LEN (sizeof(load_errtab)/sizeof(load_errtab[0]))
1205 #define ERRBUF_APPEND(s) strncat(errbuf, s, sizeof(errbuf)-strlen(errbuf)-1)
1207 snprintf(errbuf, 1024, "load failed - %s ", pathname);
1209 if (!loadquery(1, &message[0], sizeof(message)))
1210 ERRBUF_APPEND(strerror(errno));
1211 for(i = 0; message[i] && *message[i]; i++) {
1212 int nerr = atoi(message[i]);
1213 for (j=0; j<LOAD_ERRTAB_LEN; j++) {
1214 if (nerr == load_errtab[i].errnum && load_errtab[i].errstr)
1215 ERRBUF_APPEND(load_errtab[i].errstr);
1217 while (isdigit(*message[i])) message[i]++;
1218 ERRBUF_APPEND(message[i]);
1219 ERRBUF_APPEND("\n");
1221 errbuf[strlen(errbuf)-1] = '\0'; /* trim off last newline */
1222 rb_loaderror(errbuf);
1223 return;
1225 #endif
1227 #endif /* NO_DLN_LOAD */
1229 void*
1230 dln_load(const char *file)
1232 #ifdef NO_DLN_LOAD
1233 rb_raise(rb_eLoadError, "this executable file can't load extension libraries");
1234 #else
1236 #if !defined(_AIX) && !defined(NeXT)
1237 const char *error = 0;
1238 #define DLN_ERROR() (error = dln_strerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error))
1239 #endif
1241 #if defined _WIN32 && !defined __CYGWIN__
1242 HINSTANCE handle;
1243 char winfile[MAXPATHLEN];
1244 void (*init_fct)();
1245 char *buf;
1247 if (strlen(file) >= MAXPATHLEN) rb_loaderror("filename too long");
1249 /* Load the file as an object one */
1250 init_funcname(&buf, file);
1252 strcpy(winfile, file);
1254 /* Load file */
1255 if ((handle = LoadLibrary(winfile)) == NULL) {
1256 error = dln_strerror();
1257 goto failed;
1260 if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) {
1261 rb_loaderror("%s - %s\n%s", dln_strerror(), buf, file);
1264 /* Call the init code */
1265 (*init_fct)();
1266 return handle;
1267 #else
1268 #ifdef USE_DLN_A_OUT
1269 if (load(file) == -1) {
1270 error = dln_strerror();
1271 goto failed;
1273 return 0;
1274 #else
1276 char *buf;
1277 /* Load the file as an object one */
1278 init_funcname(&buf, file);
1280 #ifdef USE_DLN_DLOPEN
1281 #define DLN_DEFINED
1283 void *handle;
1284 void (*init_fct)();
1286 #ifndef RTLD_LAZY
1287 # define RTLD_LAZY 1
1288 #endif
1289 #ifdef __INTERIX
1290 # undef RTLD_GLOBAL
1291 #endif
1292 #ifndef RTLD_GLOBAL
1293 # define RTLD_GLOBAL 0
1294 #endif
1296 /* Load file */
1297 if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
1298 error = dln_strerror();
1299 goto failed;
1302 init_fct = (void(*)())dlsym(handle, buf);
1303 if (init_fct == NULL) {
1304 error = DLN_ERROR();
1305 dlclose(handle);
1306 goto failed;
1308 /* Call the init code */
1309 (*init_fct)();
1311 return handle;
1313 #endif /* USE_DLN_DLOPEN */
1315 #ifdef __hpux
1316 #define DLN_DEFINED
1318 shl_t lib = NULL;
1319 int flags;
1320 void (*init_fct)();
1322 flags = BIND_DEFERRED;
1323 lib = shl_load(file, flags, 0);
1324 if (lib == NULL) {
1325 extern int errno;
1326 rb_loaderror("%s - %s", strerror(errno), file);
1328 shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct);
1329 if (init_fct == NULL) {
1330 shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct);
1331 if (init_fct == NULL) {
1332 errno = ENOSYM;
1333 rb_loaderror("%s - %s", strerror(ENOSYM), file);
1336 (*init_fct)();
1337 return (void*)lib;
1339 #endif /* hpux */
1341 #if defined(_AIX) && ! defined(_IA64)
1342 #define DLN_DEFINED
1344 void (*init_fct)();
1346 init_fct = (void(*)())load((char*)file, 1, 0);
1347 if (init_fct == NULL) {
1348 aix_loaderror(file);
1350 if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) {
1351 aix_loaderror(file);
1353 (*init_fct)();
1354 return (void*)init_fct;
1356 #endif /* _AIX */
1358 #if defined(NeXT) || defined(MACOSX_DYLD)
1359 #define DLN_DEFINED
1360 /*----------------------------------------------------
1361 By SHIROYAMA Takayuki Psi@fortune.nest.or.jp
1363 Special Thanks...
1364 Yu tomoak-i@is.aist-nara.ac.jp,
1365 Mi hisho@tasihara.nest.or.jp,
1366 sunshine@sunshineco.com,
1367 and... Miss ARAI Akino(^^;)
1368 ----------------------------------------------------*/
1369 #if defined(NeXT) && (NS_TARGET_MAJOR < 4)/* NeXTSTEP rld functions */
1372 NXStream* s;
1373 unsigned long init_address;
1374 char *object_files[2] = {NULL, NULL};
1376 void (*init_fct)();
1378 object_files[0] = (char*)file;
1380 s = NXOpenFile(2,NX_WRITEONLY);
1382 /* Load object file, if return value ==0 , load failed*/
1383 if(rld_load(s, NULL, object_files, NULL) == 0) {
1384 NXFlush(s);
1385 NXClose(s);
1386 rb_loaderror("Failed to load %.200s", file);
1389 /* lookup the initial function */
1390 if(rld_lookup(s, buf, &init_address) == 0) {
1391 NXFlush(s);
1392 NXClose(s);
1393 rb_loaderror("Failed to lookup Init function %.200s", file);
1396 NXFlush(s);
1397 NXClose(s);
1399 /* Cannot call *init_address directory, so copy this value to
1400 funtion pointer */
1401 init_fct = (void(*)())init_address;
1402 (*init_fct)();
1403 return (void*)init_address;
1405 #else/* OPENSTEP dyld functions */
1407 int dyld_result;
1408 NSObjectFileImage obj_file; /* handle, but not use it */
1409 /* "file" is module file name .
1410 "buf" is pointer to initial function name with "_" . */
1412 void (*init_fct)();
1415 dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file);
1417 if (dyld_result != NSObjectFileImageSuccess) {
1418 rb_loaderror("Failed to load %.200s", file);
1421 NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW);
1423 /* lookup the initial function */
1424 if(!NSIsSymbolNameDefined(buf)) {
1425 rb_loaderror("Failed to lookup Init function %.200s",file);
1427 init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf));
1428 (*init_fct)();
1430 return (void*)init_fct;
1432 #endif /* rld or dyld */
1433 #endif
1435 #ifdef __BEOS__
1436 # define DLN_DEFINED
1438 status_t err_stat; /* BeOS error status code */
1439 image_id img_id; /* extention module unique id */
1440 void (*init_fct)(); /* initialize function for extention module */
1442 /* load extention module */
1443 img_id = load_add_on(file);
1444 if (img_id <= 0) {
1445 rb_loaderror("Failed to load %.200s", file);
1448 /* find symbol for module initialize function. */
1449 /* The Be Book KernelKit Images section described to use
1450 B_SYMBOL_TYPE_TEXT for symbol of function, not
1451 B_SYMBOL_TYPE_CODE. Why ? */
1452 /* strcat(init_fct_symname, "__Fv"); */ /* parameter nothing. */
1453 /* "__Fv" dont need! The Be Book Bug ? */
1454 err_stat = get_image_symbol(img_id, buf,
1455 B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
1457 if (err_stat != B_NO_ERROR) {
1458 char real_name[MAXPATHLEN];
1460 strcpy(real_name, buf);
1461 strcat(real_name, "__Fv");
1462 err_stat = get_image_symbol(img_id, real_name,
1463 B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
1466 if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) {
1467 unload_add_on(img_id);
1468 rb_loaderror("Failed to lookup Init function %.200s", file);
1470 else if (B_NO_ERROR != err_stat) {
1471 char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)";
1472 unload_add_on(img_id);
1473 rb_loaderror(errmsg, strerror(err_stat), buf);
1476 /* call module initialize function. */
1477 (*init_fct)();
1478 return (void*)img_id;
1480 #endif /* __BEOS__*/
1482 #ifdef __MACOS__ /* Mac OS 9 or before */
1483 # define DLN_DEFINED
1485 OSErr err;
1486 FSSpec libspec;
1487 CFragConnectionID connID;
1488 Ptr mainAddr;
1489 char errMessage[1024];
1490 Boolean isfolder, didsomething;
1491 Str63 fragname;
1492 Ptr symAddr;
1493 CFragSymbolClass class;
1494 void (*init_fct)();
1495 char fullpath[MAXPATHLEN];
1497 strcpy(fullpath, file);
1499 /* resolve any aliases to find the real file */
1500 c2pstr(fullpath);
1501 (void)FSMakeFSSpec(0, 0, fullpath, &libspec);
1502 err = ResolveAliasFile(&libspec, 1, &isfolder, &didsomething);
1503 if (err) {
1504 rb_loaderror("Unresolved Alias - %s", file);
1507 /* Load the fragment (or return the connID if it is already loaded */
1508 fragname[0] = 0;
1509 err = GetDiskFragment(&libspec, 0, 0, fragname,
1510 kLoadCFrag, &connID, &mainAddr,
1511 errMessage);
1512 if (err) {
1513 p2cstr(errMessage);
1514 rb_loaderror("%s - %s",errMessage , file);
1517 /* Locate the address of the correct init function */
1518 c2pstr(buf);
1519 err = FindSymbol(connID, buf, &symAddr, &class);
1520 if (err) {
1521 rb_loaderror("Unresolved symbols - %s" , file);
1523 init_fct = (void (*)())symAddr;
1524 (*init_fct)();
1525 return (void*)init_fct;
1527 #endif /* __MACOS__ */
1529 #if defined(__VMS)
1530 #define DLN_DEFINED
1532 void *handle, (*init_fct)();
1533 char *fname, *p1, *p2;
1535 fname = (char *)__alloca(strlen(file)+1);
1536 strcpy(fname,file);
1537 if (p1 = strrchr(fname,'/'))
1538 fname = p1 + 1;
1539 if (p2 = strrchr(fname,'.'))
1540 *p2 = '\0';
1542 if ((handle = (void*)dlopen(fname, 0)) == NULL) {
1543 error = dln_strerror();
1544 goto failed;
1547 if ((init_fct = (void (*)())dlsym(handle, buf)) == NULL) {
1548 error = DLN_ERROR();
1549 dlclose(handle);
1550 goto failed;
1552 /* Call the init code */
1553 (*init_fct)();
1554 return handle;
1556 #endif /* __VMS */
1558 #ifndef DLN_DEFINED
1559 rb_notimplement();
1560 #endif
1562 #endif /* USE_DLN_A_OUT */
1563 #endif
1564 #if !defined(_AIX) && !defined(NeXT)
1565 failed:
1566 rb_loaderror("%s - %s", error, file);
1567 #endif
1569 #endif /* NO_DLN_LOAD */
1570 return 0; /* dummy return */
1573 static char *dln_find_1(const char *fname, const char *path, char *buf, int size, int exe_flag);
1575 char *
1576 dln_find_exe_r(const char *fname, const char *path, char *buf, int size)
1578 if (!path) {
1579 path = getenv(PATH_ENV);
1582 if (!path) {
1583 #if defined(MSDOS) || defined(_WIN32) || defined(__human68k__) || defined(__MACOS__)
1584 path = "/usr/local/bin;/usr/ucb;/usr/bin;/bin;.";
1585 #else
1586 path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:.";
1587 #endif
1589 return dln_find_1(fname, path, buf, size, 1);
1592 char *
1593 dln_find_file_r(const char *fname, const char *path, char *buf, int size)
1595 #ifndef __MACOS__
1596 if (!path) path = ".";
1597 return dln_find_1(fname, path, buf, size, 0);
1598 #else
1599 if (!path) path = ".";
1600 return _macruby_path_conv_posix_to_macos(dln_find_1(fname, path, buf, size, 0));
1601 #endif
1604 static char fbuf[MAXPATHLEN];
1606 char *
1607 dln_find_exe(const char *fname, const char *path)
1609 return dln_find_exe_r(fname, path, fbuf, sizeof(fbuf));
1612 char *
1613 dln_find_file(const char *fname, const char *path)
1615 return dln_find_file_r(fname, path, fbuf, sizeof(fbuf));
1618 static char *
1619 dln_find_1(const char *fname, const char *path, char *fbuf, int size,
1620 int exe_flag /* non 0 if looking for executable. */)
1622 register const char *dp;
1623 register const char *ep;
1624 register char *bp;
1625 struct stat st;
1626 #ifdef __MACOS__
1627 const char* mac_fullpath;
1628 #endif
1630 #define RETURN_IF(expr) if (expr) return (char *)fname;
1632 RETURN_IF(!fname);
1633 RETURN_IF(fname[0] == '/');
1634 RETURN_IF(strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0);
1635 RETURN_IF(exe_flag && strchr(fname, '/'));
1636 #ifdef DOSISH
1637 RETURN_IF(fname[0] == '\\');
1638 # ifdef DOSISH_DRIVE_LETTER
1639 RETURN_IF(strlen(fname) > 2 && fname[1] == ':');
1640 # endif
1641 RETURN_IF(strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0);
1642 RETURN_IF(exe_flag && strchr(fname, '\\'));
1643 #endif
1645 #undef RETURN_IF
1647 for (dp = path;; dp = ++ep) {
1648 register int l;
1649 int i;
1650 int fspace;
1652 /* extract a component */
1653 ep = strchr(dp, PATH_SEP[0]);
1654 if (ep == NULL)
1655 ep = dp+strlen(dp);
1657 /* find the length of that component */
1658 l = ep - dp;
1659 bp = fbuf;
1660 fspace = size - 2;
1661 if (l > 0) {
1663 ** If the length of the component is zero length,
1664 ** start from the current directory. If the
1665 ** component begins with "~", start from the
1666 ** user's $HOME environment variable. Otherwise
1667 ** take the path literally.
1670 if (*dp == '~' && (l == 1 ||
1671 #if defined(DOSISH)
1672 dp[1] == '\\' ||
1673 #endif
1674 dp[1] == '/')) {
1675 char *home;
1677 home = getenv("HOME");
1678 if (home != NULL) {
1679 i = strlen(home);
1680 if ((fspace -= i) < 0)
1681 goto toolong;
1682 memcpy(bp, home, i);
1683 bp += i;
1685 dp++;
1686 l--;
1688 if (l > 0) {
1689 if ((fspace -= l) < 0)
1690 goto toolong;
1691 memcpy(bp, dp, l);
1692 bp += l;
1695 /* add a "/" between directory and filename */
1696 if (ep[-1] != '/')
1697 *bp++ = '/';
1700 /* now append the file name */
1701 i = strlen(fname);
1702 if ((fspace -= i) < 0) {
1703 toolong:
1704 fprintf(stderr, "openpath: pathname too long (ignored)\n");
1705 *bp = '\0';
1706 fprintf(stderr, "\tDirectory \"%s\"\n", fbuf);
1707 fprintf(stderr, "\tFile \"%s\"\n", fname);
1708 goto next;
1710 memcpy(bp, fname, i + 1);
1712 #if defined(DOSISH)
1713 if (exe_flag) {
1714 static const char extension[][5] = {
1715 #if defined(MSDOS)
1716 ".com", ".exe", ".bat",
1717 #if defined(DJGPP)
1718 ".btm", ".sh", ".ksh", ".pl", ".sed",
1719 #endif
1720 #elif defined(__EMX__) || defined(_WIN32)
1721 ".exe", ".com", ".cmd", ".bat",
1722 /* end of __EMX__ or _WIN32 */
1723 #else
1724 ".r", ".R", ".x", ".X", ".bat", ".BAT",
1725 /* __human68k__ */
1726 #endif
1728 int j;
1730 for (j = 0; j < sizeof(extension) / sizeof(extension[0]); j++) {
1731 if (fspace < strlen(extension[j])) {
1732 fprintf(stderr, "openpath: pathname too long (ignored)\n");
1733 fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf);
1734 fprintf(stderr, "\tFile \"%s%s\"\n", fname, extension[j]);
1735 continue;
1737 strcpy(bp + i, extension[j]);
1738 #ifndef __MACOS__
1739 if (stat(fbuf, &st) == 0)
1740 return fbuf;
1741 #else
1742 if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf))
1743 return mac_fullpath;
1745 #endif
1747 goto next;
1749 #endif /* MSDOS or _WIN32 or __human68k__ or __EMX__ */
1751 #ifndef __MACOS__
1752 if (stat(fbuf, &st) == 0) {
1753 if (exe_flag == 0) return fbuf;
1754 /* looking for executable */
1755 if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
1756 return fbuf;
1758 #else
1759 if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) {
1760 if (exe_flag == 0) return mac_fullpath;
1761 /* looking for executable */
1762 if (stat(mac_fullpath, &st) == 0) {
1763 if (!S_ISDIR(st.st_mode) && eaccess(mac_fullpath, X_OK) == 0)
1764 return mac_fullpath;
1767 #endif
1769 next:
1770 /* if not, and no other alternatives, life is bleak */
1771 if (*ep == '\0') {
1772 return NULL;
1775 /* otherwise try the next component in the search path */