dln.c
DEFINITIONS
This source file includes following functions.
- S_ISDIR
- init_funcname_len
- N_MAGIC
- load_header
- R_RIGHTSHIFT
- R_BITSIZE
- R_LENGTH
- R_PCREL
- R_SYMBOL
- R_SYMBOL
- R_MEMORY_SUB
- R_PCREL
- R_LENGTH
- load_reloc
- load_sym
- sym_hash
- dln_init
- load_text_data
- undef_print
- dln_print_undef
- dln_undefined
- link_undef
- reloc_undef
- unlink_undef
- reloc_repl
- load_1
- search_undef
- load_lib
- load
- dln_sym
- dln_strerror
- aix_loaderror
- dln_load
- dln_find_exe
- dln_find_file
- conv_to_posix_path
- dln_find_1
1
2
3
4
5
6
7
8
9
10
11
12
13 #include "ruby.h"
14 #include "dln.h"
15
16 #ifdef HAVE_STDLIB_H
17 # include <stdlib.h>
18 #endif
19
20 #ifdef __CHECKER__
21 #undef HAVE_DLOPEN
22 #undef USE_DLN_A_OUT
23 #undef USE_DLN_DLOPEN
24 #endif
25
26 #ifdef USE_DLN_A_OUT
27 char *dln_argv0;
28 #endif
29
30 #ifdef _AIX
31 #pragma alloca
32 #endif
33
34 #if defined(HAVE_ALLOCA_H) && !defined(__GNUC__)
35 #include <alloca.h>
36 #endif
37
38 #ifdef HAVE_STRING_H
39 # include <string.h>
40 #else
41 # include <strings.h>
42 #endif
43
44 #ifndef xmalloc
45 void *xmalloc();
46 void *xcalloc();
47 void *xrealloc();
48 #endif
49
50 #include <stdio.h>
51 #if defined(NT) || defined(__VMS)
52 #include "missing/file.h"
53 #endif
54 #include <sys/types.h>
55 #include <sys/stat.h>
56
57 #ifndef S_ISDIR
58 # define S_ISDIR(m) ((m & S_IFMT) == S_IFDIR)
59 #endif
60
61 #ifdef HAVE_SYS_PARAM_H
62 # include <sys/param.h>
63 #else
64 # define MAXPATHLEN 1024
65 #endif
66
67 #ifdef HAVE_UNISTD_H
68 # include <unistd.h>
69 #endif
70
71 #ifndef NT
72 char *getenv();
73 #endif
74
75 #if defined(__VMS)
76 #pragma builtins
77 #include <dlfcn.h>
78 #endif
79
80 #ifdef __MACOS__
81 # include <TextUtils.h>
82 # include <CodeFragments.h>
83 # include <Aliases.h>
84 # include "macruby_private.h"
85 #endif
86
87 #ifdef __BEOS__
88 # include <image.h>
89 #endif
90
91 int eaccess();
92
93 #if defined(HAVE_DLOPEN) && !defined(USE_DLN_A_OUT) && !defined(_AIX)
94
95 # define USE_DLN_DLOPEN
96 #endif
97
98 #ifndef FUNCNAME_PATTERN
99 # if defined(__hp9000s300) || (defined(__NetBSD__) && !defined(__ELF__)) || defined(__BORLANDC__) || (defined(__FreeBSD__) && !defined(__ELF__)) || defined(__OpenBSD__) || defined(NeXT) || defined(__WATCOMC__) || defined(__APPLE__)
100 # define FUNCNAME_PATTERN "_Init_%s"
101 # else
102 # define FUNCNAME_PATTERN "Init_%s"
103 # endif
104 #endif
105
106 static int
107 init_funcname_len(buf, file)
108 char **buf;
109 char *file;
110 {
111 char *p, *slash;
112
113
114 for (p = file, slash = p-1; *p; p++)
115 #ifdef __MACOS__
116 if (*p == ':') slash = p;
117 #else
118 if (*p == '/') slash = p;
119 #endif
120
121
122
123 #ifdef MAXPATHLEN
124 *buf = xmalloc(MAXPATHLEN);
125 snprintf(*buf, MAXPATHLEN, FUNCNAME_PATTERN, slash + 1);
126 #else
127 asprintf(buf, FUNCNAME_PATTERN, slash + 1);
128 #endif
129 for (p = *buf; *p; p++) {
130 if (*p == '.') {
131 *p = '\0'; break;
132 }
133 }
134 return p - *buf;
135 }
136
137 #define init_funcname(buf, file) do {\
138 int len = init_funcname_len(buf, file);\
139 char *tmp = ALLOCA_N(char, len+1);\
140 if (!tmp) {\
141 free(*buf);\
142 rb_memerror();\
143 }\
144 strcpy(tmp, *buf);\
145 free(*buf);\
146 *buf = tmp;\
147 } while (0)
148
149 #ifdef USE_DLN_A_OUT
150
151 #ifndef LIBC_NAME
152 # define LIBC_NAME "libc.a"
153 #endif
154
155 #ifndef DLN_DEFAULT_LIB_PATH
156 # define DLN_DEFAULT_LIB_PATH "/lib:/usr/lib:/usr/local/lib:."
157 #endif
158
159 #include <errno.h>
160
161 static int dln_errno;
162
163 #define DLN_ENOEXEC ENOEXEC
164 #define DLN_ECONFL 1201
165 #define DLN_ENOINIT 1202
166 #define DLN_EUNDEF 1203
167 #define DLN_ENOTLIB 1204
168 #define DLN_EBADLIB 1205
169 #define DLN_EINIT 1206
170
171 static int dln_init_p = 0;
172
173 #include <ar.h>
174 #include <a.out.h>
175 #ifndef N_COMM
176 # define N_COMM 0x12
177 #endif
178 #ifndef N_MAGIC
179 # define N_MAGIC(x) (x).a_magic
180 #endif
181
182 #define INVALID_OBJECT(h) (N_MAGIC(h) != OMAGIC)
183
184 #include "util.h"
185 #include "st.h"
186
187 static st_table *sym_tbl;
188 static st_table *undef_tbl;
189
190 static int load_lib();
191
192 static int
193 load_header(fd, hdrp, disp)
194 int fd;
195 struct exec *hdrp;
196 long disp;
197 {
198 int size;
199
200 lseek(fd, disp, 0);
201 size = read(fd, hdrp, sizeof(struct exec));
202 if (size == -1) {
203 dln_errno = errno;
204 return -1;
205 }
206 if (size != sizeof(struct exec) || N_BADMAG(*hdrp)) {
207 dln_errno = DLN_ENOEXEC;
208 return -1;
209 }
210 return 0;
211 }
212
213 #if defined(sequent)
214 #define RELOC_SYMBOL(r) ((r)->r_symbolnum)
215 #define RELOC_MEMORY_SUB_P(r) ((r)->r_bsr)
216 #define RELOC_PCREL_P(r) ((r)->r_pcrel || (r)->r_bsr)
217 #define RELOC_TARGET_SIZE(r) ((r)->r_length)
218 #endif
219
220
221 #ifndef RELOC_ADDRESS
222 #define RELOC_ADDRESS(r) ((r)->r_address)
223 #define RELOC_EXTERN_P(r) ((r)->r_extern)
224 #define RELOC_SYMBOL(r) ((r)->r_symbolnum)
225 #define RELOC_MEMORY_SUB_P(r) 0
226 #define RELOC_PCREL_P(r) ((r)->r_pcrel)
227 #define RELOC_TARGET_SIZE(r) ((r)->r_length)
228 #endif
229
230 #if defined(sun) && defined(sparc)
231
232 # undef relocation_info
233 # define relocation_info reloc_info_sparc
234 # define R_RIGHTSHIFT(r) (reloc_r_rightshift[(r)->r_type])
235 # define R_BITSIZE(r) (reloc_r_bitsize[(r)->r_type])
236 # define R_LENGTH(r) (reloc_r_length[(r)->r_type])
237 static int reloc_r_rightshift[] = {
238 0, 0, 0, 0, 0, 0, 2, 2, 10, 0, 0, 0, 0, 0, 0,
239 };
240 static int reloc_r_bitsize[] = {
241 8, 16, 32, 8, 16, 32, 30, 22, 22, 22, 13, 10, 32, 32, 16,
242 };
243 static int reloc_r_length[] = {
244 0, 1, 2, 0, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
245 };
246 # define R_PCREL(r) \
247 ((r)->r_type >= RELOC_DISP8 && (r)->r_type <= RELOC_WDISP22)
248 # define R_SYMBOL(r) ((r)->r_index)
249 #endif
250
251 #if defined(sequent)
252 #define R_SYMBOL(r) ((r)->r_symbolnum)
253 #define R_MEMORY_SUB(r) ((r)->r_bsr)
254 #define R_PCREL(r) ((r)->r_pcrel || (r)->r_bsr)
255 #define R_LENGTH(r) ((r)->r_length)
256 #endif
257
258 #ifndef R_SYMBOL
259 # define R_SYMBOL(r) ((r)->r_symbolnum)
260 # define R_MEMORY_SUB(r) 0
261 # define R_PCREL(r) ((r)->r_pcrel)
262 # define R_LENGTH(r) ((r)->r_length)
263 #endif
264
265 static struct relocation_info *
266 load_reloc(fd, hdrp, disp)
267 int fd;
268 struct exec *hdrp;
269 long disp;
270 {
271 struct relocation_info *reloc;
272 int size;
273
274 lseek(fd, disp + N_TXTOFF(*hdrp) + hdrp->a_text + hdrp->a_data, 0);
275 size = hdrp->a_trsize + hdrp->a_drsize;
276 reloc = (struct relocation_info*)xmalloc(size);
277 if (reloc == NULL) {
278 dln_errno = errno;
279 return NULL;
280 }
281
282 if (read(fd, reloc, size) != size) {
283 dln_errno = errno;
284 free(reloc);
285 return NULL;
286 }
287
288 return reloc;
289 }
290
291 static struct nlist *
292 load_sym(fd, hdrp, disp)
293 int fd;
294 struct exec *hdrp;
295 long disp;
296 {
297 struct nlist * buffer;
298 struct nlist * sym;
299 struct nlist * end;
300 long displ;
301 int size;
302
303 lseek(fd, N_SYMOFF(*hdrp) + hdrp->a_syms + disp, 0);
304 if (read(fd, &size, sizeof(int)) != sizeof(int)) {
305 goto err_noexec;
306 }
307
308 buffer = (struct nlist*)xmalloc(hdrp->a_syms + size);
309 if (buffer == NULL) {
310 dln_errno = errno;
311 return NULL;
312 }
313
314 lseek(fd, disp + N_SYMOFF(*hdrp), 0);
315 if (read(fd, buffer, hdrp->a_syms + size) != hdrp->a_syms + size) {
316 free(buffer);
317 goto err_noexec;
318 }
319
320 sym = buffer;
321 end = sym + hdrp->a_syms / sizeof(struct nlist);
322 displ = (long)buffer + (long)(hdrp->a_syms);
323
324 while (sym < end) {
325 sym->n_un.n_name = (char*)sym->n_un.n_strx + displ;
326 sym++;
327 }
328 return buffer;
329
330 err_noexec:
331 dln_errno = DLN_ENOEXEC;
332 return NULL;
333 }
334
335 static st_table *
336 sym_hash(hdrp, syms)
337 struct exec *hdrp;
338 struct nlist *syms;
339 {
340 st_table *tbl;
341 struct nlist *sym = syms;
342 struct nlist *end = syms + (hdrp->a_syms / sizeof(struct nlist));
343
344 tbl = st_init_strtable();
345 if (tbl == NULL) {
346 dln_errno = errno;
347 return NULL;
348 }
349
350 while (sym < end) {
351 st_insert(tbl, sym->n_un.n_name, sym);
352 sym++;
353 }
354 return tbl;
355 }
356
357 static int
358 dln_init(prog)
359 const char *prog;
360 {
361 char *file;
362 int fd;
363 struct exec hdr;
364 struct nlist *syms;
365
366 if (dln_init_p == 1) return 0;
367
368 file = dln_find_exe(prog, NULL);
369 if (file == NULL || (fd = open(file, O_RDONLY)) < 0) {
370 dln_errno = errno;
371 return -1;
372 }
373
374 if (load_header(fd, &hdr, 0) == -1) return -1;
375 syms = load_sym(fd, &hdr, 0);
376 if (syms == NULL) {
377 close(fd);
378 return -1;
379 }
380 sym_tbl = sym_hash(&hdr, syms);
381 if (sym_tbl == NULL) {
382 char c = '\0';
383 char buf[MAXPATHLEN];
384 char *p;
385
386 free(syms);
387 lseek(fd, 0L, 0);
388 if (read(fd, &c, 1) == -1) {
389 dln_errno = errno;
390 return -1;
391 }
392 if (c != '#') goto err_noexec;
393 if (read(fd, &c, 1) == -1) {
394 dln_errno = errno;
395 return -1;
396 }
397 if (c != '!') goto err_noexec;
398
399 p = buf;
400
401 while (read(fd, &c, 1) == 1) {
402 if (c == '\n') goto err_noexec;
403 if (c != '\t' && c != ' ') {
404 *p++ = c;
405 break;
406 }
407 }
408
409 while (read(fd, p, 1) == 1) {
410 if (*p == '\n' || *p == '\t' || *p == ' ') break;
411 p++;
412 if (p-buf >= MAXPATHLEN) {
413 dln_errno = ENAMETOOLONG;
414 return -1;
415 }
416 }
417 *p = '\0';
418
419 return dln_init(buf);
420 }
421 dln_init_p = 1;
422 undef_tbl = st_init_strtable();
423 close(fd);
424 return 0;
425
426 err_noexec:
427 close(fd);
428 dln_errno = DLN_ENOEXEC;
429 return -1;
430 }
431
432 static long
433 load_text_data(fd, hdrp, bss, disp)
434 int fd;
435 struct exec *hdrp;
436 int bss;
437 long disp;
438 {
439 int size;
440 unsigned char* addr;
441
442 lseek(fd, disp + N_TXTOFF(*hdrp), 0);
443 size = hdrp->a_text + hdrp->a_data;
444
445 if (bss == -1) size += hdrp->a_bss;
446 else if (bss > 1) size += bss;
447
448 addr = (unsigned char*)xmalloc(size);
449 if (addr == NULL) {
450 dln_errno = errno;
451 return 0;
452 }
453
454 if (read(fd, addr, size) != size) {
455 dln_errno = errno;
456 free(addr);
457 return 0;
458 }
459
460 if (bss == -1) {
461 memset(addr + hdrp->a_text + hdrp->a_data, 0, hdrp->a_bss);
462 }
463 else if (bss > 0) {
464 memset(addr + hdrp->a_text + hdrp->a_data, 0, bss);
465 }
466
467 return (long)addr;
468 }
469
470 static int
471 undef_print(key, value)
472 char *key, *value;
473 {
474 fprintf(stderr, " %s\n", key);
475 return ST_CONTINUE;
476 }
477
478 static void
479 dln_print_undef()
480 {
481 fprintf(stderr, " Undefined symbols:\n");
482 st_foreach(undef_tbl, undef_print, NULL);
483 }
484
485 static void
486 dln_undefined()
487 {
488 if (undef_tbl->num_entries > 0) {
489 fprintf(stderr, "dln: Calling undefined function\n");
490 dln_print_undef();
491 rb_exit(1);
492 }
493 }
494
495 struct undef {
496 char *name;
497 struct relocation_info reloc;
498 long base;
499 char *addr;
500 union {
501 char c;
502 short s;
503 long l;
504 } u;
505 };
506
507 static st_table *reloc_tbl = NULL;
508 static void
509 link_undef(name, base, reloc)
510 const char *name;
511 long base;
512 struct relocation_info *reloc;
513 {
514 static int u_no = 0;
515 struct undef *obj;
516 char *addr = (char*)(reloc->r_address + base);
517
518 obj = (struct undef*)xmalloc(sizeof(struct undef));
519 obj->name = strdup(name);
520 obj->reloc = *reloc;
521 obj->base = base;
522 switch (R_LENGTH(reloc)) {
523 case 0:
524 obj->u.c = *addr;
525 break;
526 case 1:
527 obj->u.s = *(short*)addr;
528 break;
529 case 2:
530 obj->u.l = *(long*)addr;
531 break;
532 }
533 if (reloc_tbl == NULL) {
534 reloc_tbl = st_init_numtable();
535 }
536 st_insert(reloc_tbl, u_no++, obj);
537 }
538
539 struct reloc_arg {
540 const char *name;
541 long value;
542 };
543
544 static int
545 reloc_undef(no, undef, arg)
546 int no;
547 struct undef *undef;
548 struct reloc_arg *arg;
549 {
550 int datum;
551 char *address;
552 #if defined(sun) && defined(sparc)
553 unsigned int mask = 0;
554 #endif
555
556 if (strcmp(arg->name, undef->name) != 0) return ST_CONTINUE;
557 address = (char*)(undef->base + undef->reloc.r_address);
558 datum = arg->value;
559
560 if (R_PCREL(&(undef->reloc))) datum -= undef->base;
561 #if defined(sun) && defined(sparc)
562 datum += undef->reloc.r_addend;
563 datum >>= R_RIGHTSHIFT(&(undef->reloc));
564 mask = (1 << R_BITSIZE(&(undef->reloc))) - 1;
565 mask |= mask -1;
566 datum &= mask;
567 switch (R_LENGTH(&(undef->reloc))) {
568 case 0:
569 *address = undef->u.c;
570 *address &= ~mask;
571 *address |= datum;
572 break;
573 case 1:
574 *(short *)address = undef->u.s;
575 *(short *)address &= ~mask;
576 *(short *)address |= datum;
577 break;
578 case 2:
579 *(long *)address = undef->u.l;
580 *(long *)address &= ~mask;
581 *(long *)address |= datum;
582 break;
583 }
584 #else
585 switch (R_LENGTH(&(undef->reloc))) {
586 case 0:
587 if (R_MEMORY_SUB(&(undef->reloc)))
588 *address = datum - *address;
589 else *address = undef->u.c + datum;
590 break;
591 case 1:
592 if (R_MEMORY_SUB(&(undef->reloc)))
593 *(short*)address = datum - *(short*)address;
594 else *(short*)address = undef->u.s + datum;
595 break;
596 case 2:
597 if (R_MEMORY_SUB(&(undef->reloc)))
598 *(long*)address = datum - *(long*)address;
599 else *(long*)address = undef->u.l + datum;
600 break;
601 }
602 #endif
603 free(undef->name);
604 free(undef);
605 return ST_DELETE;
606 }
607
608 static void
609 unlink_undef(name, value)
610 const char *name;
611 long value;
612 {
613 struct reloc_arg arg;
614
615 arg.name = name;
616 arg.value = value;
617 st_foreach(reloc_tbl, reloc_undef, &arg);
618 }
619
620 #ifdef N_INDR
621 struct indr_data {
622 char *name0, *name1;
623 };
624
625 static int
626 reloc_repl(no, undef, data)
627 int no;
628 struct undef *undef;
629 struct indr_data *data;
630 {
631 if (strcmp(data->name0, undef->name) == 0) {
632 free(undef->name);
633 undef->name = strdup(data->name1);
634 }
635 return ST_CONTINUE;
636 }
637 #endif
638
639 static int
640 load_1(fd, disp, need_init)
641 int fd;
642 long disp;
643 const char *need_init;
644 {
645 static char *libc = LIBC_NAME;
646 struct exec hdr;
647 struct relocation_info *reloc = NULL;
648 long block = 0;
649 long new_common = 0;
650 struct nlist *syms = NULL;
651 struct nlist *sym;
652 struct nlist *end;
653 int init_p = 0;
654
655 if (load_header(fd, &hdr, disp) == -1) return -1;
656 if (INVALID_OBJECT(hdr)) {
657 dln_errno = DLN_ENOEXEC;
658 return -1;
659 }
660 reloc = load_reloc(fd, &hdr, disp);
661 if (reloc == NULL) return -1;
662
663 syms = load_sym(fd, &hdr, disp);
664 if (syms == NULL) {
665 free(reloc);
666 return -1;
667 }
668
669 sym = syms;
670 end = syms + (hdr.a_syms / sizeof(struct nlist));
671 while (sym < end) {
672 struct nlist *old_sym;
673 int value = sym->n_value;
674
675 #ifdef N_INDR
676 if (sym->n_type == (N_INDR | N_EXT)) {
677 char *key = sym->n_un.n_name;
678
679 if (st_lookup(sym_tbl, sym[1].n_un.n_name, &old_sym)) {
680 if (st_delete(undef_tbl, &key, NULL)) {
681 unlink_undef(key, old_sym->n_value);
682 free(key);
683 }
684 }
685 else {
686 struct indr_data data;
687
688 data.name0 = sym->n_un.n_name;
689 data.name1 = sym[1].n_un.n_name;
690 st_foreach(reloc_tbl, reloc_repl, &data);
691
692 st_insert(undef_tbl, strdup(sym[1].n_un.n_name), NULL);
693 if (st_delete(undef_tbl, &key, NULL)) {
694 free(key);
695 }
696 }
697 sym += 2;
698 continue;
699 }
700 #endif
701 if (sym->n_type == (N_UNDF | N_EXT)) {
702 if (st_lookup(sym_tbl, sym->n_un.n_name, &old_sym) == 0) {
703 old_sym = NULL;
704 }
705
706 if (value) {
707 if (old_sym) {
708 sym->n_type = N_EXT | N_COMM;
709 sym->n_value = old_sym->n_value;
710 }
711 else {
712 int rnd =
713 value >= sizeof(double) ? sizeof(double) - 1
714 : value >= sizeof(long) ? sizeof(long) - 1
715 : sizeof(short) - 1;
716
717 sym->n_type = N_COMM;
718 new_common += rnd;
719 new_common &= ~(long)rnd;
720 sym->n_value = new_common;
721 new_common += value;
722 }
723 }
724 else {
725 if (old_sym) {
726 sym->n_type = N_EXT | N_COMM;
727 sym->n_value = old_sym->n_value;
728 }
729 else {
730 sym->n_value = (long)dln_undefined;
731 st_insert(undef_tbl, strdup(sym->n_un.n_name), NULL);
732 }
733 }
734 }
735 sym++;
736 }
737
738 block = load_text_data(fd, &hdr, hdr.a_bss + new_common, disp);
739 if (block == 0) goto err_exit;
740
741 sym = syms;
742 while (sym < end) {
743 struct nlist *new_sym;
744 char *key;
745
746 switch (sym->n_type) {
747 case N_COMM:
748 sym->n_value += hdr.a_text + hdr.a_data;
749 case N_TEXT|N_EXT:
750 case N_DATA|N_EXT:
751
752 sym->n_value += block;
753
754 if (st_lookup(sym_tbl, sym->n_un.n_name, &new_sym) != 0
755 && new_sym->n_value != (long)dln_undefined) {
756 dln_errno = DLN_ECONFL;
757 goto err_exit;
758 }
759
760 key = sym->n_un.n_name;
761 if (st_delete(undef_tbl, &key, NULL) != 0) {
762 unlink_undef(key, sym->n_value);
763 free(key);
764 }
765
766 new_sym = (struct nlist*)xmalloc(sizeof(struct nlist));
767 *new_sym = *sym;
768 new_sym->n_un.n_name = strdup(sym->n_un.n_name);
769 st_insert(sym_tbl, new_sym->n_un.n_name, new_sym);
770 break;
771
772 case N_TEXT:
773 case N_DATA:
774 sym->n_value += block;
775 break;
776 }
777 sym++;
778 }
779
780
781
782
783 {
784 struct relocation_info * rel = reloc;
785 struct relocation_info * rel_beg = reloc +
786 (hdr.a_trsize/sizeof(struct relocation_info));
787 struct relocation_info * rel_end = reloc +
788 (hdr.a_trsize+hdr.a_drsize)/sizeof(struct relocation_info);
789
790 while (rel < rel_end) {
791 char *address = (char*)(rel->r_address + block);
792 long datum = 0;
793 #if defined(sun) && defined(sparc)
794 unsigned int mask = 0;
795 #endif
796
797 if(rel >= rel_beg)
798 address += hdr.a_text;
799
800 if (rel->r_extern) {
801 sym = &(syms[R_SYMBOL(rel)]);
802 switch (sym->n_type) {
803 case N_EXT|N_UNDF:
804 link_undef(sym->n_un.n_name, block, rel);
805 case N_EXT|N_COMM:
806 case N_COMM:
807 datum = sym->n_value;
808 break;
809 default:
810 goto err_exit;
811 }
812 }
813 else {
814 switch (R_SYMBOL(rel)) {
815 case N_TEXT:
816 case N_DATA:
817 datum = block;
818 break;
819 case N_BSS:
820 datum = block + new_common;
821 break;
822 case N_ABS:
823 break;
824 }
825 }
826 if (R_PCREL(rel)) datum -= block;
827
828 #if defined(sun) && defined(sparc)
829 datum += rel->r_addend;
830 datum >>= R_RIGHTSHIFT(rel);
831 mask = (1 << R_BITSIZE(rel)) - 1;
832 mask |= mask -1;
833 datum &= mask;
834
835 switch (R_LENGTH(rel)) {
836 case 0:
837 *address &= ~mask;
838 *address |= datum;
839 break;
840 case 1:
841 *(short *)address &= ~mask;
842 *(short *)address |= datum;
843 break;
844 case 2:
845 *(long *)address &= ~mask;
846 *(long *)address |= datum;
847 break;
848 }
849 #else
850 switch (R_LENGTH(rel)) {
851 case 0:
852 if (datum < -128 || datum > 127) goto err_exit;
853 *address += datum;
854 break;
855 case 1:
856 *(short *)address += datum;
857 break;
858 case 2:
859 *(long *)address += datum;
860 break;
861 }
862 #endif
863 rel++;
864 }
865 }
866
867 if (need_init) {
868 int len;
869 char **libs_to_be_linked = 0;
870 char *buf;
871
872 if (undef_tbl->num_entries > 0) {
873 if (load_lib(libc) == -1) goto err_exit;
874 }
875
876 init_funcname(&buf, need_init);
877 len = strlen(buf);
878
879 for (sym = syms; sym<end; sym++) {
880 char *name = sym->n_un.n_name;
881 if (name[0] == '_' && sym->n_value >= block) {
882 if (strcmp(name+1, "dln_libs_to_be_linked") == 0) {
883 libs_to_be_linked = (char**)sym->n_value;
884 }
885 else if (strcmp(name+1, buf) == 0) {
886 init_p = 1;
887 ((int (*)())sym->n_value)();
888 }
889 }
890 }
891 if (libs_to_be_linked && undef_tbl->num_entries > 0) {
892 while (*libs_to_be_linked) {
893 load_lib(*libs_to_be_linked);
894 libs_to_be_linked++;
895 }
896 }
897 }
898 free(reloc);
899 free(syms);
900 if (need_init) {
901 if (init_p == 0) {
902 dln_errno = DLN_ENOINIT;
903 return -1;
904 }
905 if (undef_tbl->num_entries > 0) {
906 if (load_lib(libc) == -1) goto err_exit;
907 if (undef_tbl->num_entries > 0) {
908 dln_errno = DLN_EUNDEF;
909 return -1;
910 }
911 }
912 }
913 return 0;
914
915 err_exit:
916 if (syms) free(syms);
917 if (reloc) free(reloc);
918 if (block) free((char*)block);
919 return -1;
920 }
921
922 static int target_offset;
923 static int
924 search_undef(key, value, lib_tbl)
925 const char *key;
926 int value;
927 st_table *lib_tbl;
928 {
929 long offset;
930
931 if (st_lookup(lib_tbl, key, &offset) == 0) return ST_CONTINUE;
932 target_offset = offset;
933 return ST_STOP;
934 }
935
936 struct symdef {
937 int rb_str_index;
938 int lib_offset;
939 };
940
941 char *dln_librrb_ary_path = DLN_DEFAULT_LIB_PATH;
942
943 static int
944 load_lib(lib)
945 const char *lib;
946 {
947 char *path, *file;
948 char armagic[SARMAG];
949 int fd, size;
950 struct ar_hdr ahdr;
951 st_table *lib_tbl = NULL;
952 int *data, nsym;
953 struct symdef *base;
954 char *name_base;
955
956 if (dln_init_p == 0) {
957 dln_errno = DLN_ENOINIT;
958 return -1;
959 }
960
961 if (undef_tbl->num_entries == 0) return 0;
962 dln_errno = DLN_EBADLIB;
963
964 if (lib[0] == '-' && lib[1] == 'l') {
965 char *p = alloca(strlen(lib) + 4);
966 sprintf(p, "lib%s.a", lib+2);
967 lib = p;
968 }
969
970
971
972
973
974 path = getenv("DLN_LIBRARY_PATH");
975 if (path == NULL) path = dln_librrb_ary_path;
976
977 file = dln_find_file(lib, path);
978 fd = open(file, O_RDONLY);
979 if (fd == -1) goto syserr;
980 size = read(fd, armagic, SARMAG);
981 if (size == -1) goto syserr;
982
983 if (size != SARMAG) {
984 dln_errno = DLN_ENOTLIB;
985 goto badlib;
986 }
987 size = read(fd, &ahdr, sizeof(ahdr));
988 if (size == -1) goto syserr;
989 if (size != sizeof(ahdr) || sscanf(ahdr.ar_size, "%d", &size) != 1) {
990 goto badlib;
991 }
992
993 if (strncmp(ahdr.ar_name, "__.SYMDEF", 9) == 0) {
994
995
996 lib_tbl = st_init_strtable();
997 data = (int*)xmalloc(size);
998 if (data == NULL) goto syserr;
999 size = read(fd, data, size);
1000 nsym = *data / sizeof(struct symdef);
1001 base = (struct symdef*)(data + 1);
1002 name_base = (char*)(base + nsym) + sizeof(int);
1003 while (nsym > 0) {
1004 char *name = name_base + base->rb_str_index;
1005
1006 st_insert(lib_tbl, name, base->lib_offset + sizeof(ahdr));
1007 nsym--;
1008 base++;
1009 }
1010 for (;;) {
1011 target_offset = -1;
1012 st_foreach(undef_tbl, search_undef, lib_tbl);
1013 if (target_offset == -1) break;
1014 if (load_1(fd, target_offset, 0) == -1) {
1015 st_free_table(lib_tbl);
1016 free(data);
1017 goto badlib;
1018 }
1019 if (undef_tbl->num_entries == 0) break;
1020 }
1021 free(data);
1022 st_free_table(lib_tbl);
1023 }
1024 else {
1025
1026
1027 for (;;) {
1028 int offset = SARMAG;
1029 int found = 0;
1030 struct exec hdr;
1031 struct nlist *syms, *sym, *end;
1032
1033 while (undef_tbl->num_entries > 0) {
1034 found = 0;
1035 lseek(fd, offset, 0);
1036 size = read(fd, &ahdr, sizeof(ahdr));
1037 if (size == -1) goto syserr;
1038 if (size == 0) break;
1039 if (size != sizeof(ahdr)
1040 || sscanf(ahdr.ar_size, "%d", &size) != 1) {
1041 goto badlib;
1042 }
1043 offset += sizeof(ahdr);
1044 if (load_header(fd, &hdr, offset) == -1)
1045 goto badlib;
1046 syms = load_sym(fd, &hdr, offset);
1047 if (syms == NULL) goto badlib;
1048 sym = syms;
1049 end = syms + (hdr.a_syms / sizeof(struct nlist));
1050 while (sym < end) {
1051 if (sym->n_type == N_EXT|N_TEXT
1052 && st_lookup(undef_tbl, sym->n_un.n_name, NULL)) {
1053 break;
1054 }
1055 sym++;
1056 }
1057 if (sym < end) {
1058 found++;
1059 free(syms);
1060 if (load_1(fd, offset, 0) == -1) {
1061 goto badlib;
1062 }
1063 }
1064 offset += size;
1065 if (offset & 1) offset++;
1066 }
1067 if (found) break;
1068 }
1069 }
1070 close(fd);
1071 return 0;
1072
1073 syserr:
1074 dln_errno = errno;
1075 badlib:
1076 if (fd >= 0) close(fd);
1077 return -1;
1078 }
1079
1080 static int
1081 load(file)
1082 const char *file;
1083 {
1084 int fd;
1085 int result;
1086
1087 if (dln_init_p == 0) {
1088 if (dln_init(dln_argv0) == -1) return -1;
1089 }
1090 result = strlen(file);
1091 if (file[result-1] == 'a') {
1092 return load_lib(file);
1093 }
1094
1095 fd = open(file, O_RDONLY);
1096 if (fd == -1) {
1097 dln_errno = errno;
1098 return -1;
1099 }
1100 result = load_1(fd, 0, file);
1101 close(fd);
1102
1103 return result;
1104 }
1105
1106 void*
1107 dln_sym(name)
1108 const char *name;
1109 {
1110 struct nlist *sym;
1111
1112 if (st_lookup(sym_tbl, name, &sym))
1113 return (void*)sym->n_value;
1114 return NULL;
1115 }
1116
1117 #endif
1118
1119 #ifdef USE_DLN_DLOPEN
1120 # ifdef __NetBSD__
1121 # include <nlist.h>
1122 # include <link.h>
1123 # else
1124 # include <dlfcn.h>
1125 # endif
1126 #endif
1127
1128 #ifdef __hpux
1129 #include <errno.h>
1130 #include "dl.h"
1131 #endif
1132
1133 #if defined(_AIX)
1134 #include <ctype.h>
1135 #include <errno.h>
1136 #include <sys/ldr.h>
1137 #endif
1138
1139 #ifdef NeXT
1140 #if NS_TARGET_MAJOR < 4
1141 #include <mach-o/rld.h>
1142 #else
1143 #include <mach-o/dyld.h>
1144 #endif
1145 #endif
1146 #ifdef __APPLE__
1147 #include <mach-o/dyld.h>
1148 #endif
1149
1150
1151 #if defined _WIN32 && !defined __CYGWIN__
1152 #include <windows.h>
1153 #endif
1154
1155 static const char *
1156 dln_strerror()
1157 {
1158 #ifdef USE_DLN_A_OUT
1159 char *strerror();
1160
1161 switch (dln_errno) {
1162 case DLN_ECONFL:
1163 return "Symbol name conflict";
1164 case DLN_ENOINIT:
1165 return "No inititalizer given";
1166 case DLN_EUNDEF:
1167 return "Unresolved symbols";
1168 case DLN_ENOTLIB:
1169 return "Not a library file";
1170 case DLN_EBADLIB:
1171 return "Malformed library file";
1172 case DLN_EINIT:
1173 return "Not initialized";
1174 default:
1175 return strerror(dln_errno);
1176 }
1177 #endif
1178
1179 #ifdef USE_DLN_DLOPEN
1180 return (char*)dlerror();
1181 #endif
1182
1183 #if defined _WIN32 && !defined __CYGWIN__
1184 static char message[1024];
1185 int error = GetLastError();
1186 char *p = message;
1187 p += sprintf(message, "%d: ", error);
1188 FormatMessage(
1189 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1190 NULL,
1191 error,
1192 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
1193 p,
1194 sizeof message - strlen(message),
1195 NULL);
1196
1197 for (p = message; *p; p++) {
1198 if (*p == '\n' || *p == '\r')
1199 *p = ' ';
1200 }
1201 return message;
1202 #endif
1203 }
1204
1205
1206 #if defined(_AIX) && ! defined(_IA64)
1207 static void
1208 aix_loaderror(const char *pathname)
1209 {
1210 char *message[8], errbuf[1024];
1211 int i,j;
1212
1213 struct errtab {
1214 int errno;
1215 char *errstr;
1216 } load_errtab[] = {
1217 {L_ERROR_TOOMANY, "too many errors, rest skipped."},
1218 {L_ERROR_NOLIB, "can't load library:"},
1219 {L_ERROR_UNDEF, "can't find symbol in library:"},
1220 {L_ERROR_RLDBAD,
1221 "RLD index out of range or bad relocation type:"},
1222 {L_ERROR_FORMAT, "not a valid, executable xcoff file:"},
1223 {L_ERROR_MEMBER,
1224 "file not an archive or does not contain requested member:"},
1225 {L_ERROR_TYPE, "symbol table mismatch:"},
1226 {L_ERROR_ALIGN, "text allignment in file is wrong."},
1227 {L_ERROR_SYSTEM, "System error:"},
1228 {L_ERROR_ERRNO, NULL}
1229 };
1230
1231 #define LOAD_ERRTAB_LEN (sizeof(load_errtab)/sizeof(load_errtab[0]))
1232 #define ERRBUF_APPEND(s) strncat(errbuf, s, sizeof(errbuf)-strlen(errbuf)-1)
1233
1234 snprintf(errbuf, 1024, "load failed - %s ", pathname);
1235
1236 if (!loadquery(1, &message[0], sizeof(message)))
1237 ERRBUF_APPEND(strerror(errno));
1238 for(i = 0; message[i] && *message[i]; i++) {
1239 int nerr = atoi(message[i]);
1240 for (j=0; j<LOAD_ERRTAB_LEN; j++) {
1241 if (nerr == load_errtab[i].errno && load_errtab[i].errstr)
1242 ERRBUF_APPEND(load_errtab[i].errstr);
1243 }
1244 while (isdigit(*message[i])) message[i]++;
1245 ERRBUF_APPEND(message[i]);
1246 ERRBUF_APPEND("\n");
1247 }
1248 errbuf[strlen(errbuf)-1] = '\0';
1249 rb_loaderror(errbuf);
1250 return;
1251 }
1252 #endif
1253
1254 void*
1255 dln_load(file)
1256 const char *file;
1257 {
1258 #if !defined(_AIX) && !defined(NeXT)
1259 const char *error = 0;
1260 #define DLN_ERROR() (error = dln_strerror(), strcpy(ALLOCA_N(char, strlen(error) + 1), error))
1261 #endif
1262
1263 #if defined _WIN32 && !defined __CYGWIN__
1264 HINSTANCE handle;
1265 char winfile[MAXPATHLEN];
1266 void (*init_fct)();
1267 char *buf;
1268
1269 if (strlen(file) >= MAXPATHLEN) rb_loaderror("filename too long");
1270
1271
1272 init_funcname(&buf, file);
1273
1274 strcpy(winfile, file);
1275
1276
1277 if ((handle = LoadLibrary(winfile)) == NULL) {
1278 error = dln_strerror();
1279 goto failed;
1280 }
1281
1282 if ((init_fct = (void(*)())GetProcAddress(handle, buf)) == NULL) {
1283 rb_loaderror("%s - %s\n%s", dln_strerror(), buf, file);
1284 }
1285
1286
1287 (*init_fct)();
1288 return handle;
1289 #else
1290 #ifdef USE_DLN_A_OUT
1291 if (load(file) == -1) {
1292 error = dln_strerror();
1293 goto failed;
1294 }
1295 return 0;
1296 #else
1297
1298 char *buf;
1299
1300 init_funcname(&buf, file);
1301
1302 #ifdef USE_DLN_DLOPEN
1303 #define DLN_DEFINED
1304 {
1305 void *handle;
1306 void (*init_fct)();
1307
1308 #ifndef RTLD_LAZY
1309 # define RTLD_LAZY 1
1310 #endif
1311 #ifndef RTLD_GLOBAL
1312 # define RTLD_GLOBAL 0
1313 #endif
1314
1315
1316 if ((handle = (void*)dlopen(file, RTLD_LAZY|RTLD_GLOBAL)) == NULL) {
1317 error = dln_strerror();
1318 goto failed;
1319 }
1320
1321 init_fct = (void(*)())dlsym(handle, buf);
1322 if (init_fct == NULL) {
1323 error = DLN_ERROR();
1324 dlclose(handle);
1325 goto failed;
1326 }
1327
1328 (*init_fct)();
1329
1330 return handle;
1331 }
1332 #endif
1333
1334 #ifdef __hpux
1335 #define DLN_DEFINED
1336 {
1337 shl_t lib = NULL;
1338 int flags;
1339 void (*init_fct)();
1340
1341 flags = BIND_DEFERRED;
1342 lib = shl_load(file, flags, 0);
1343 if (lib == NULL) {
1344 extern int errno;
1345 rb_loaderror("%s - %s", strerror(errno), file);
1346 }
1347 shl_findsym(&lib, buf, TYPE_PROCEDURE, (void*)&init_fct);
1348 if (init_fct == NULL) {
1349 shl_findsym(&lib, buf, TYPE_UNDEFINED, (void*)&init_fct);
1350 if (init_fct == NULL) {
1351 errno = ENOSYM;
1352 rb_loaderror("%s - %s", strerror(ENOSYM), file);
1353 }
1354 }
1355 (*init_fct)();
1356 return (void*)lib;
1357 }
1358 #endif
1359
1360 #if defined(_AIX) && ! defined(_IA64)
1361 #define DLN_DEFINED
1362 {
1363 void (*init_fct)();
1364
1365 init_fct = (void(*)())load((char*)file, 1, 0);
1366 if (init_fct == NULL) {
1367 aix_loaderror(file);
1368 }
1369 if (loadbind(0, (void*)dln_load, (void*)init_fct) == -1) {
1370 aix_loaderror(file);
1371 }
1372 (*init_fct)();
1373 return (void*)init_fct;
1374 }
1375 #endif
1376
1377 #if defined(NeXT) || defined(__APPLE__)
1378 #define DLN_DEFINED
1379
1380
1381
1382
1383
1384
1385
1386
1387 #if defined(NeXT) && (NS_TARGET_MAJOR < 4)
1388
1389 {
1390 unsigned long init_address;
1391 char *object_files[2] = {NULL, NULL};
1392
1393 void (*init_fct)();
1394
1395 object_files[0] = file;
1396
1397
1398 if(rld_load(NULL, NULL, object_files, NULL) == 0) {
1399 rb_loaderror("Failed to load %.200s", file);
1400 }
1401
1402
1403 if(rld_lookup(NULL, buf, &init_address) == 0) {
1404 rb_loaderror("Failed to lookup Init function %.200s", file);
1405 }
1406
1407
1408
1409 init_fct = (void(*)())init_address;
1410 (*init_fct)();
1411 return (void*)init_address;
1412 }
1413 #else
1414 {
1415 int dyld_result;
1416 NSObjectFileImage obj_file;
1417
1418
1419
1420 void (*init_fct)();
1421
1422
1423 dyld_result = NSCreateObjectFileImageFromFile(file, &obj_file);
1424
1425 if (dyld_result != NSObjectFileImageSuccess) {
1426 rb_loaderror("Failed to load %.200s", file);
1427 }
1428
1429 NSLinkModule(obj_file, file, NSLINKMODULE_OPTION_BINDNOW);
1430
1431
1432
1433 if(NSIsSymbolNameDefined(buf + 1)) {
1434 rb_loaderror("Failed to lookup Init function %.200s",file);
1435 }
1436
1437
1438 init_fct = NSAddressOfSymbol(NSLookupAndBindSymbol(buf));
1439 (*init_fct)();
1440
1441 return (void*)init_fct;
1442 }
1443 #endif
1444 #endif
1445
1446 #ifdef __BEOS__
1447 # define DLN_DEFINED
1448 {
1449 status_t err_stat;
1450 image_id img_id;
1451 void (*init_fct)();
1452
1453
1454 img_id = load_add_on(file);
1455 if (img_id <= 0) {
1456 rb_loaderror("Failed to load %.200s", file);
1457 }
1458
1459
1460
1461
1462
1463
1464
1465 err_stat = get_image_symbol(img_id, buf,
1466 B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
1467
1468 if (err_stat != B_NO_ERROR) {
1469 char real_name[MAXPATHLEN];
1470
1471 strcpy(real_name, buf);
1472 strcat(real_name, "__Fv");
1473 err_stat = get_image_symbol(img_id, real_name,
1474 B_SYMBOL_TYPE_TEXT, (void **)&init_fct);
1475 }
1476
1477 if ((B_BAD_IMAGE_ID == err_stat) || (B_BAD_INDEX == err_stat)) {
1478 unload_add_on(img_id);
1479 rb_loaderror("Failed to lookup Init function %.200s", file);
1480 }
1481 else if (B_NO_ERROR != err_stat) {
1482 char errmsg[] = "Internal of BeOS version. %.200s (symbol_name = %s)";
1483 unload_add_on(img_id);
1484 rb_loaderror(errmsg, strerror(err_stat), buf);
1485 }
1486
1487
1488 (*init_fct)();
1489 return (void*)img_id;
1490 }
1491 #endif
1492
1493 #ifdef __MACOS__
1494 # define DLN_DEFINED
1495 {
1496 OSErr err;
1497 FSSpec libspec;
1498 CFragConnectionID connID;
1499 Ptr mainAddr;
1500 char errMessage[1024];
1501 Boolean isfolder, didsomething;
1502 Str63 fragname;
1503 Ptr symAddr;
1504 CFragSymbolClass class;
1505 void (*init_fct)();
1506 char fullpath[MAXPATHLEN];
1507
1508 strcpy(fullpath, file);
1509
1510
1511 c2pstr(fullpath);
1512 (void)FSMakeFSSpec(0, 0, fullpath, &libspec);
1513 err = ResolveAliasFile(&libspec, 1, &isfolder, &didsomething);
1514 if (err) {
1515 rb_loaderror("Unresolved Alias - %s", file);
1516 }
1517
1518
1519 fragname[0] = 0;
1520 err = GetDiskFragment(&libspec, 0, 0, fragname,
1521 kLoadCFrag, &connID, &mainAddr,
1522 errMessage);
1523 if (err) {
1524 p2cstr(errMessage);
1525 rb_loaderror("%s - %s",errMessage , file);
1526 }
1527
1528
1529 c2pstr(buf);
1530 err = FindSymbol(connID, buf, &symAddr, &class);
1531 if (err) {
1532 rb_loaderror("Unresolved symbols - %s" , file);
1533 }
1534 init_fct = (void (*)())symAddr;
1535 (*init_fct)();
1536 return (void*)init_fct;
1537 }
1538 #endif
1539
1540 #if defined(__VMS)
1541 #define DLN_DEFINED
1542 {
1543 void *handle, (*init_fct)();
1544 char *fname, *p1, *p2;
1545
1546 fname = (char *)__alloca(strlen(file)+1);
1547 strcpy(fname,file);
1548 if (p1 = strrchr(fname,'/'))
1549 fname = p1 + 1;
1550 if (p2 = strrchr(fname,'.'))
1551 *p2 = '\0';
1552
1553 if ((handle = (void*)dlopen(fname, 0)) == NULL) {
1554 error = dln_strerror();
1555 goto failed;
1556 }
1557
1558 if ((init_fct = (void (*)())dlsym(handle, buf)) == NULL) {
1559 error = DLN_ERROR();
1560 dlclose(handle);
1561 goto failed;
1562 }
1563
1564 (*init_fct)();
1565 return handle;
1566 }
1567 #endif
1568
1569 #ifndef DLN_DEFINED
1570 rb_notimplement();
1571 #endif
1572
1573 #endif
1574 #endif
1575 #if !defined(_AIX) && !defined(NeXT)
1576 failed:
1577 rb_loaderror("%s - %s", error, file);
1578 #endif
1579 return 0;
1580 }
1581
1582 static char *dln_find_1();
1583
1584 char *
1585 dln_find_exe(fname, path)
1586 const char *fname;
1587 const char *path;
1588 {
1589 if (!path) {
1590 #if defined(__human68k__)
1591 path = getenv("path");
1592 #else
1593 path = getenv("PATH");
1594 #endif
1595 }
1596
1597 if (!path) {
1598 #if defined(MSDOS) || defined(NT) || defined(__human68k__) || defined(__MACOS__)
1599 path = "/usr/local/bin;/usr/ucb;/usr/bin;/bin;.";
1600 #else
1601 path = "/usr/local/bin:/usr/ucb:/usr/bin:/bin:.";
1602 #endif
1603 }
1604 return dln_find_1(fname, path, 1);
1605 }
1606
1607 char *
1608 dln_find_file(fname, path)
1609 const char *fname;
1610 const char *path;
1611 {
1612 #ifndef __MACOS__
1613 if (!path) path = ".";
1614 return dln_find_1(fname, path, 0);
1615 #else
1616 if (!path) path = ".";
1617 return _macruby_path_conv_posix_to_macos(dln_find_1(fname, path, 0));
1618 #endif
1619 }
1620
1621 #if defined(__CYGWIN32__)
1622 const char *
1623 conv_to_posix_path(win32, posix, len)
1624 char *win32;
1625 char *posix;
1626 int len;
1627 {
1628 char *first = win32;
1629 char *p = win32;
1630 char *dst = posix;
1631
1632 for (p = win32; *p; p++)
1633 if (*p == ';') {
1634 *p = 0;
1635 cygwin32_conv_to_posix_path(first, posix);
1636 posix += strlen(posix);
1637 *posix++ = ':';
1638 first = p + 1;
1639 *p = ';';
1640 }
1641 if (len < strlen(first))
1642 fprintf(stderr, "PATH length too long: %s\n", first);
1643 else
1644 cygwin32_conv_to_posix_path(first, posix);
1645 return dst;
1646 }
1647 #endif
1648
1649 static char fbuf[MAXPATHLEN];
1650
1651 static char *
1652 dln_find_1(fname, path, exe_flag)
1653 char *fname;
1654 char *path;
1655 int exe_flag;
1656 {
1657 register char *dp;
1658 register char *ep;
1659 register char *bp;
1660 struct stat st;
1661 #ifdef __MACOS__
1662 const char* mac_fullpath;
1663 #endif
1664
1665 if (fname[0] == '/') return fname;
1666 if (strncmp("./", fname, 2) == 0 || strncmp("../", fname, 3) == 0)
1667 return fname;
1668 if (exe_flag && strchr(fname, '/')) return fname;
1669 #if defined(MSDOS) || defined(NT) || defined(__human68k__) || defined(__EMX__)
1670 if (fname[0] == '\\') return fname;
1671 if (strlen(fname) > 2 && fname[1] == ':') return fname;
1672 if (strncmp(".\\", fname, 2) == 0 || strncmp("..\\", fname, 3) == 0)
1673 return fname;
1674 if (exe_flag && strchr(fname, '\\')) return fname;
1675 #endif
1676
1677 for (dp = path;; dp = ++ep) {
1678 register int l;
1679 int i;
1680 int fspace;
1681
1682
1683 ep = strchr(dp, PATH_SEP[0]);
1684 if (ep == NULL)
1685 ep = dp+strlen(dp);
1686
1687
1688 l = ep - dp;
1689 bp = fbuf;
1690 fspace = sizeof fbuf - 2;
1691 if (l > 0) {
1692
1693
1694
1695
1696
1697
1698
1699
1700 if (*dp == '~' && (l == 1 ||
1701 #if defined(MSDOS) || defined(NT) || defined(__human68k__) || defined(__EMX__)
1702 dp[1] == '\\' ||
1703 #endif
1704 dp[1] == '/')) {
1705 char *home;
1706
1707 home = getenv("HOME");
1708 if (home != NULL) {
1709 i = strlen(home);
1710 if ((fspace -= i) < 0)
1711 goto toolong;
1712 memcpy(bp, home, i);
1713 bp += i;
1714 }
1715 dp++;
1716 l--;
1717 }
1718 if (l > 0) {
1719 if ((fspace -= l) < 0)
1720 goto toolong;
1721 memcpy(bp, dp, l);
1722 bp += l;
1723 }
1724
1725
1726 if (ep[-1] != '/')
1727 *bp++ = '/';
1728 }
1729
1730
1731 i = strlen(fname);
1732 if ((fspace -= i) < 0) {
1733 toolong:
1734 fprintf(stderr, "openpath: pathname too long (ignored)\n");
1735 *bp = '\0';
1736 fprintf(stderr, "\tDirectory \"%s\"\n", fbuf);
1737 fprintf(stderr, "\tFile \"%s\"\n", fname);
1738 continue;
1739 }
1740 memcpy(bp, fname, i + 1);
1741
1742 #ifndef __MACOS__
1743 if (stat(fbuf, &st) == 0) {
1744 if (exe_flag == 0) return fbuf;
1745
1746 if (!S_ISDIR(st.st_mode) && eaccess(fbuf, X_OK) == 0)
1747 return fbuf;
1748 }
1749 #else
1750 if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf)) {
1751 if (exe_flag == 0) return mac_fullpath;
1752
1753 if (stat(mac_fullpath, &st) == 0) {
1754 if (!S_ISDIR(st.st_mode) && eaccess(mac_fullpath, X_OK) == 0)
1755 return mac_fullpath;
1756 }
1757 }
1758 #endif
1759 #if defined(MSDOS) || defined(NT) || defined(__human68k__) || defined(__EMX__)
1760 if (exe_flag) {
1761 static const char *extension[] = {
1762 #if defined(MSDOS)
1763 ".com", ".exe", ".bat",
1764 #if defined(DJGPP)
1765 ".btm", ".sh", ".ksh", ".pl", ".sed",
1766 #endif
1767 #elif defined(__EMX__) || defined(NT)
1768 ".exe", ".com", ".cmd", ".bat",
1769
1770 #else
1771 ".r", ".R", ".x", ".X", ".bat", ".BAT",
1772
1773 #endif
1774 (char *) NULL
1775 };
1776 int j;
1777
1778 for (j = 0; extension[j]; j++) {
1779 if (fspace < strlen(extension[j])) {
1780 fprintf(stderr, "openpath: pathname too long (ignored)\n");
1781 fprintf(stderr, "\tDirectory \"%.*s\"\n", (int) (bp - fbuf), fbuf);
1782 fprintf(stderr, "\tFile \"%s%s\"\n", fname, extension[j]);
1783 continue;
1784 }
1785 strcpy(bp + i, extension[j]);
1786 #ifndef __MACOS__
1787 if (stat(fbuf, &st) == 0)
1788 return fbuf;
1789 #else
1790 if (mac_fullpath = _macruby_exist_file_in_libdir_as_posix_name(fbuf))
1791 return mac_fullpath;
1792 #endif
1793 }
1794 }
1795 #endif
1796
1797 if (*ep == '\0') {
1798 return NULL;
1799 }
1800
1801
1802 }
1803 }