1/*
2 * load methods from eval.c
3 */
4
5#include "ruby/ruby.h"
6#include "ruby/util.h"
7#include "internal.h"
8#include "dln.h"
9#include "eval_intern.h"
10#include "probes.h"
11#include "node.h"
12
13VALUE ruby_dln_librefs;
14
15#define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
16
17#define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
18#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
19#ifdef DLEXT2
20#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0 || strcmp((e), DLEXT2) == 0)
21#else
22#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
23#endif
24
25static const char *const loadable_ext[] = {
26    ".rb", DLEXT,
27#ifdef DLEXT2
28    DLEXT2,
29#endif
30    0
31};
32
33VALUE
34rb_get_load_path(void)
35{
36    VALUE load_path = GET_VM()->load_path;
37    return load_path;
38}
39
40enum expand_type {
41    EXPAND_ALL,
42    EXPAND_RELATIVE,
43    EXPAND_HOME,
44    EXPAND_NON_CACHE
45};
46
47/* Construct expanded load path and store it to cache.
48   We rebuild load path partially if the cache is invalid.
49   We don't cache non string object and expand it every time. We ensure that
50   string objects in $LOAD_PATH are frozen.
51 */
52static void
53rb_construct_expanded_load_path(int type, int *has_relative, int *has_non_cache)
54{
55    rb_vm_t *vm = GET_VM();
56    VALUE load_path = vm->load_path;
57    VALUE expanded_load_path = vm->expanded_load_path;
58    VALUE ary;
59    long i;
60    int level = rb_safe_level();
61
62    ary = rb_ary_tmp_new(RARRAY_LEN(load_path));
63    for (i = 0; i < RARRAY_LEN(load_path); ++i) {
64	VALUE path, as_str, expanded_path;
65	int is_string, non_cache;
66	char *as_cstr;
67	as_str = path = RARRAY_PTR(load_path)[i];
68	is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0;
69	non_cache = !is_string ? 1 : 0;
70	as_str = rb_get_path_check_to_string(path, level);
71	as_cstr = RSTRING_PTR(as_str);
72
73	if (!non_cache) {
74	    if ((type == EXPAND_RELATIVE &&
75		    rb_is_absolute_path(as_cstr)) ||
76		(type == EXPAND_HOME &&
77		    (!as_cstr[0] || as_cstr[0] != '~')) ||
78		(type == EXPAND_NON_CACHE)) {
79		    /* Use cached expanded path. */
80		    rb_ary_push(ary, RARRAY_PTR(expanded_load_path)[i]);
81		    continue;
82	    }
83	}
84	if (!*has_relative && !rb_is_absolute_path(as_cstr))
85	    *has_relative = 1;
86	if (!*has_non_cache && non_cache)
87	    *has_non_cache = 1;
88	/* Freeze only string object. We expand other objects every time. */
89	if (is_string)
90	    rb_str_freeze(path);
91	as_str = rb_get_path_check_convert(path, as_str, level);
92	expanded_path = rb_file_expand_path_fast(as_str, Qnil);
93	rb_str_freeze(expanded_path);
94	rb_ary_push(ary, expanded_path);
95    }
96    rb_obj_freeze(ary);
97    vm->expanded_load_path = ary;
98    rb_ary_replace(vm->load_path_snapshot, vm->load_path);
99}
100
101static VALUE
102load_path_getcwd(void)
103{
104    char *cwd = my_getcwd();
105    VALUE cwd_str = rb_filesystem_str_new_cstr(cwd);
106    xfree(cwd);
107    return cwd_str;
108}
109
110VALUE
111rb_get_expanded_load_path(void)
112{
113    rb_vm_t *vm = GET_VM();
114    const VALUE non_cache = Qtrue;
115
116    if (!rb_ary_shared_with_p(vm->load_path_snapshot, vm->load_path)) {
117	/* The load path was modified. Rebuild the expanded load path. */
118	int has_relative = 0, has_non_cache = 0;
119	rb_construct_expanded_load_path(EXPAND_ALL, &has_relative, &has_non_cache);
120	if (has_relative) {
121	    vm->load_path_check_cache = load_path_getcwd();
122	}
123	else if (has_non_cache) {
124	    /* Non string object. */
125	    vm->load_path_check_cache = non_cache;
126	}
127	else {
128	    vm->load_path_check_cache = 0;
129	}
130    }
131    else if (vm->load_path_check_cache == non_cache) {
132	int has_relative = 1, has_non_cache = 1;
133	/* Expand only non-cacheable objects. */
134	rb_construct_expanded_load_path(EXPAND_NON_CACHE,
135					&has_relative, &has_non_cache);
136    }
137    else if (vm->load_path_check_cache) {
138	int has_relative = 1, has_non_cache = 1;
139	VALUE cwd = load_path_getcwd();
140	if (!rb_str_equal(vm->load_path_check_cache, cwd)) {
141	    /* Current working directory or filesystem encoding was changed.
142	       Expand relative load path and non-cacheable objects again. */
143	    vm->load_path_check_cache = cwd;
144	    rb_construct_expanded_load_path(EXPAND_RELATIVE,
145					    &has_relative, &has_non_cache);
146	}
147	else {
148	    /* Expand only tilde (User HOME) and non-cacheable objects. */
149	    rb_construct_expanded_load_path(EXPAND_HOME,
150					    &has_relative, &has_non_cache);
151	}
152    }
153    return vm->expanded_load_path;
154}
155
156static VALUE
157load_path_getter(ID id, rb_vm_t *vm)
158{
159    return vm->load_path;
160}
161
162static VALUE
163get_loaded_features(void)
164{
165    return GET_VM()->loaded_features;
166}
167
168static void
169reset_loaded_features_snapshot(void)
170{
171    rb_vm_t *vm = GET_VM();
172    rb_ary_replace(vm->loaded_features_snapshot, vm->loaded_features);
173}
174
175static struct st_table *
176get_loaded_features_index_raw(void)
177{
178    return GET_VM()->loaded_features_index;
179}
180
181static st_table *
182get_loading_table(void)
183{
184    return GET_VM()->loading_table;
185}
186
187static void
188features_index_add_single(VALUE short_feature, VALUE offset)
189{
190    struct st_table *features_index;
191    VALUE this_feature_index = Qnil;
192    char *short_feature_cstr;
193
194    Check_Type(offset, T_FIXNUM);
195    Check_Type(short_feature, T_STRING);
196    short_feature_cstr = StringValueCStr(short_feature);
197
198    features_index = get_loaded_features_index_raw();
199    st_lookup(features_index, (st_data_t)short_feature_cstr, (st_data_t *)&this_feature_index);
200
201    if (NIL_P(this_feature_index)) {
202	st_insert(features_index, (st_data_t)ruby_strdup(short_feature_cstr), (st_data_t)offset);
203    }
204    else if (RB_TYPE_P(this_feature_index, T_FIXNUM)) {
205	VALUE feature_indexes[2];
206	feature_indexes[0] = this_feature_index;
207	feature_indexes[1] = offset;
208	this_feature_index = rb_ary_tmp_new(numberof(feature_indexes));
209	rb_ary_cat(this_feature_index, feature_indexes, numberof(feature_indexes));
210	st_insert(features_index, (st_data_t)short_feature_cstr, (st_data_t)this_feature_index);
211    }
212    else {
213	Check_Type(this_feature_index, T_ARRAY);
214	rb_ary_push(this_feature_index, offset);
215    }
216}
217
218/* Add to the loaded-features index all the required entries for
219   `feature`, located at `offset` in $LOADED_FEATURES.  We add an
220   index entry at each string `short_feature` for which
221     feature == "#{prefix}#{short_feature}#{e}"
222   where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
223   or ends in '/'.  This maintains the invariant that `rb_feature_p()`
224   relies on for its fast lookup.
225*/
226static void
227features_index_add(VALUE feature, VALUE offset)
228{
229    VALUE short_feature;
230    const char *feature_str, *feature_end, *ext, *p;
231
232    feature_str = StringValuePtr(feature);
233    feature_end = feature_str + RSTRING_LEN(feature);
234
235    for (ext = feature_end; ext > feature_str; ext--)
236      if (*ext == '.' || *ext == '/')
237	break;
238    if (*ext != '.')
239      ext = NULL;
240    /* Now `ext` points to the only string matching %r{^\.[^./]*$} that is
241       at the end of `feature`, or is NULL if there is no such string. */
242
243    p = ext ? ext : feature_end;
244    while (1) {
245	p--;
246	while (p >= feature_str && *p != '/')
247	    p--;
248	if (p < feature_str)
249	    break;
250	/* Now *p == '/'.  We reach this point for every '/' in `feature`. */
251	short_feature = rb_str_subseq(feature, p + 1 - feature_str, feature_end - p - 1);
252	features_index_add_single(short_feature, offset);
253	if (ext) {
254	    short_feature = rb_str_subseq(feature, p + 1 - feature_str, ext - p - 1);
255	    features_index_add_single(short_feature, offset);
256	}
257    }
258    features_index_add_single(feature, offset);
259    if (ext) {
260	short_feature = rb_str_subseq(feature, 0, ext - feature_str);
261	features_index_add_single(short_feature, offset);
262    }
263}
264
265static int
266loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
267{
268    xfree((char *)key);
269    return ST_DELETE;
270}
271
272static st_table *
273get_loaded_features_index(void)
274{
275    VALUE features;
276    int i;
277    rb_vm_t *vm = GET_VM();
278
279    if (!rb_ary_shared_with_p(vm->loaded_features_snapshot, vm->loaded_features)) {
280	/* The sharing was broken; something (other than us in rb_provide_feature())
281	   modified loaded_features.  Rebuild the index. */
282	st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
283	features = vm->loaded_features;
284	for (i = 0; i < RARRAY_LEN(features); i++) {
285	    VALUE entry, as_str;
286	    as_str = entry = rb_ary_entry(features, i);
287	    StringValue(as_str);
288	    if (as_str != entry)
289		rb_ary_store(features, i, as_str);
290	    rb_str_freeze(as_str);
291	    features_index_add(as_str, INT2FIX(i));
292	}
293	reset_loaded_features_snapshot();
294    }
295    return vm->loaded_features_index;
296}
297
298/* This searches `load_path` for a value such that
299     name == "#{load_path[i]}/#{feature}"
300   if `feature` is a suffix of `name`, or otherwise
301     name == "#{load_path[i]}/#{feature}#{ext}"
302   for an acceptable string `ext`.  It returns
303   `load_path[i].to_str` if found, else 0.
304
305   If type is 's', then `ext` is acceptable only if IS_DLEXT(ext);
306   if 'r', then only if IS_RBEXT(ext); otherwise `ext` may be absent
307   or have any value matching `%r{^\.[^./]*$}`.
308*/
309static VALUE
310loaded_feature_path(const char *name, long vlen, const char *feature, long len,
311		    int type, VALUE load_path)
312{
313    long i;
314    long plen;
315    const char *e;
316
317    if (vlen < len+1) return 0;
318    if (!strncmp(name+(vlen-len), feature, len)) {
319	plen = vlen - len;
320    }
321    else {
322	for (e = name + vlen; name != e && *e != '.' && *e != '/'; --e);
323	if (*e != '.' ||
324	    e-name < len ||
325	    strncmp(e-len, feature, len))
326	    return 0;
327	plen = e - name - len;
328    }
329    if (plen > 0 && name[plen-1] != '/') {
330	return 0;
331    }
332    if (type == 's' ? !IS_DLEXT(&name[plen+len]) :
333	type == 'r' ? !IS_RBEXT(&name[plen+len]) :
334	0) {
335	return 0;
336    }
337    /* Now name == "#{prefix}/#{feature}#{ext}" where ext is acceptable
338       (possibly empty) and prefix is some string of length plen. */
339
340    if (plen > 0) --plen;	/* exclude '.' */
341    for (i = 0; i < RARRAY_LEN(load_path); ++i) {
342	VALUE p = RARRAY_PTR(load_path)[i];
343	const char *s = StringValuePtr(p);
344	long n = RSTRING_LEN(p);
345
346	if (n != plen) continue;
347	if (n && strncmp(name, s, n)) continue;
348	return p;
349    }
350    return 0;
351}
352
353struct loaded_feature_searching {
354    const char *name;
355    long len;
356    int type;
357    VALUE load_path;
358    const char *result;
359};
360
361static int
362loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
363{
364    const char *s = (const char *)v;
365    struct loaded_feature_searching *fp = (struct loaded_feature_searching *)f;
366    VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len,
367				  fp->type, fp->load_path);
368    if (!p) return ST_CONTINUE;
369    fp->result = s;
370    return ST_STOP;
371}
372
373static int
374rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn)
375{
376    VALUE features, this_feature_index = Qnil, v, p, load_path = 0;
377    const char *f, *e;
378    long i, len, elen, n;
379    st_table *loading_tbl, *features_index;
380    st_data_t data;
381    int type;
382
383    if (fn) *fn = 0;
384    if (ext) {
385	elen = strlen(ext);
386	len = strlen(feature) - elen;
387	type = rb ? 'r' : 's';
388    }
389    else {
390	len = strlen(feature);
391	elen = 0;
392	type = 0;
393    }
394    features = get_loaded_features();
395    features_index = get_loaded_features_index();
396
397    st_lookup(features_index, (st_data_t)feature, (st_data_t *)&this_feature_index);
398    /* We search `features` for an entry such that either
399         "#{features[i]}" == "#{load_path[j]}/#{feature}#{e}"
400       for some j, or
401         "#{features[i]}" == "#{feature}#{e}"
402       Here `e` is an "allowed" extension -- either empty or one
403       of the extensions accepted by IS_RBEXT, IS_SOEXT, or
404       IS_DLEXT.  Further, if `ext && rb` then `IS_RBEXT(e)`,
405       and if `ext && !rb` then `IS_SOEXT(e) || IS_DLEXT(e)`.
406
407       If `expanded`, then only the latter form (without load_path[j])
408       is accepted.  Otherwise either form is accepted, *unless* `ext`
409       is false and an otherwise-matching entry of the first form is
410       preceded by an entry of the form
411         "#{features[i2]}" == "#{load_path[j2]}/#{feature}#{e2}"
412       where `e2` matches %r{^\.[^./]*$} but is not an allowed extension.
413       After a "distractor" entry of this form, only entries of the
414       form "#{feature}#{e}" are accepted.
415
416       In `rb_provide_feature()` and `get_loaded_features_index()` we
417       maintain an invariant that the array `this_feature_index` will
418       point to every entry in `features` which has the form
419         "#{prefix}#{feature}#{e}"
420       where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
421       or ends in '/'.  This includes both match forms above, as well
422       as any distractors, so we may ignore all other entries in `features`.
423     */
424    for (i = 0; !NIL_P(this_feature_index); i++) {
425	VALUE entry;
426	long index;
427	if (RB_TYPE_P(this_feature_index, T_ARRAY)) {
428	    if (i >= RARRAY_LEN(this_feature_index)) break;
429	    entry = RARRAY_PTR(this_feature_index)[i];
430	}
431	else {
432	    if (i > 0) break;
433	    entry = this_feature_index;
434	}
435	index = FIX2LONG(entry);
436
437	v = RARRAY_PTR(features)[index];
438	f = StringValuePtr(v);
439	if ((n = RSTRING_LEN(v)) < len) continue;
440	if (strncmp(f, feature, len) != 0) {
441	    if (expanded) continue;
442	    if (!load_path) load_path = rb_get_expanded_load_path();
443	    if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
444		continue;
445	    expanded = 1;
446	    f += RSTRING_LEN(p) + 1;
447	}
448	if (!*(e = f + len)) {
449	    if (ext) continue;
450	    return 'u';
451	}
452	if (*e != '.') continue;
453	if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
454	    return 's';
455	}
456	if ((rb || !ext) && (IS_RBEXT(e))) {
457	    return 'r';
458	}
459    }
460
461    loading_tbl = get_loading_table();
462    if (loading_tbl) {
463	f = 0;
464	if (!expanded) {
465	    struct loaded_feature_searching fs;
466	    fs.name = feature;
467	    fs.len = len;
468	    fs.type = type;
469	    fs.load_path = load_path ? load_path : rb_get_expanded_load_path();
470	    fs.result = 0;
471	    st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
472	    if ((f = fs.result) != 0) {
473		if (fn) *fn = f;
474		goto loading;
475	    }
476	}
477	if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
478	    if (fn) *fn = (const char*)data;
479	  loading:
480	    if (!ext) return 'u';
481	    return !IS_RBEXT(ext) ? 's' : 'r';
482	}
483	else {
484	    VALUE bufstr;
485	    char *buf;
486	    static const char so_ext[][4] = {
487		".so", ".o",
488	    };
489
490	    if (ext && *ext) return 0;
491	    bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN);
492	    buf = RSTRING_PTR(bufstr);
493	    MEMCPY(buf, feature, char, len);
494	    for (i = 0; (e = loadable_ext[i]) != 0; i++) {
495		strlcpy(buf + len, e, DLEXT_MAXLEN + 1);
496		if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
497		    rb_str_resize(bufstr, 0);
498		    if (fn) *fn = (const char*)data;
499		    return i ? 's' : 'r';
500		}
501	    }
502	    for (i = 0; i < numberof(so_ext); i++) {
503		strlcpy(buf + len, so_ext[i], DLEXT_MAXLEN + 1);
504		if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
505		    rb_str_resize(bufstr, 0);
506		    if (fn) *fn = (const char*)data;
507		    return 's';
508		}
509	    }
510	    rb_str_resize(bufstr, 0);
511	}
512    }
513    return 0;
514}
515
516int
517rb_provided(const char *feature)
518{
519    return rb_feature_provided(feature, 0);
520}
521
522int
523rb_feature_provided(const char *feature, const char **loading)
524{
525    const char *ext = strrchr(feature, '.');
526    volatile VALUE fullpath = 0;
527
528    if (*feature == '.' &&
529	(feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) {
530	fullpath = rb_file_expand_path_fast(rb_get_path(rb_str_new2(feature)), Qnil);
531	feature = RSTRING_PTR(fullpath);
532    }
533    if (ext && !strchr(ext, '/')) {
534	if (IS_RBEXT(ext)) {
535	    if (rb_feature_p(feature, ext, TRUE, FALSE, loading)) return TRUE;
536	    return FALSE;
537	}
538	else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
539	    if (rb_feature_p(feature, ext, FALSE, FALSE, loading)) return TRUE;
540	    return FALSE;
541	}
542    }
543    if (rb_feature_p(feature, 0, TRUE, FALSE, loading))
544	return TRUE;
545    return FALSE;
546}
547
548static void
549rb_provide_feature(VALUE feature)
550{
551    VALUE features;
552
553    features = get_loaded_features();
554    if (OBJ_FROZEN(features)) {
555	rb_raise(rb_eRuntimeError,
556		 "$LOADED_FEATURES is frozen; cannot append feature");
557    }
558    rb_str_freeze(feature);
559
560    rb_ary_push(features, feature);
561    features_index_add(feature, INT2FIX(RARRAY_LEN(features)-1));
562    reset_loaded_features_snapshot();
563}
564
565void
566rb_provide(const char *feature)
567{
568    rb_provide_feature(rb_usascii_str_new2(feature));
569}
570
571NORETURN(static void load_failed(VALUE));
572
573static void
574rb_load_internal(VALUE fname, int wrap)
575{
576    int state;
577    rb_thread_t *th = GET_THREAD();
578    volatile VALUE wrapper = th->top_wrapper;
579    volatile VALUE self = th->top_self;
580    volatile int loaded = FALSE;
581    volatile int mild_compile_error;
582#ifndef __GNUC__
583    rb_thread_t *volatile th0 = th;
584#endif
585
586    th->errinfo = Qnil; /* ensure */
587
588    if (!wrap) {
589	rb_secure(4);		/* should alter global state */
590	th->top_wrapper = 0;
591    }
592    else {
593	/* load in anonymous module as toplevel */
594	th->top_self = rb_obj_clone(rb_vm_top_self());
595	th->top_wrapper = rb_module_new();
596	rb_extend_object(th->top_self, th->top_wrapper);
597    }
598
599    mild_compile_error = th->mild_compile_error;
600    PUSH_TAG();
601    state = EXEC_TAG();
602    if (state == 0) {
603	NODE *node;
604	VALUE iseq;
605
606	th->mild_compile_error++;
607	node = (NODE *)rb_load_file(RSTRING_PTR(fname));
608	loaded = TRUE;
609	iseq = rb_iseq_new_top(node, rb_str_new2("<top (required)>"), fname, rb_realpath_internal(Qnil, fname, 1), Qfalse);
610	th->mild_compile_error--;
611	rb_iseq_eval(iseq);
612    }
613    POP_TAG();
614
615#ifndef __GNUC__
616    th = th0;
617    fname = RB_GC_GUARD(fname);
618#endif
619    th->mild_compile_error = mild_compile_error;
620    th->top_self = self;
621    th->top_wrapper = wrapper;
622
623    if (!loaded && !FIXNUM_P(GET_THREAD()->errinfo)) {
624	/* an error on loading don't include INT2FIX(TAG_FATAL) see r35625 */
625	rb_exc_raise(GET_THREAD()->errinfo);
626    }
627    if (state) {
628	rb_vm_jump_tag_but_local_jump(state);
629    }
630
631    if (!NIL_P(GET_THREAD()->errinfo)) {
632	/* exception during load */
633	rb_exc_raise(th->errinfo);
634    }
635}
636
637void
638rb_load(VALUE fname, int wrap)
639{
640    VALUE tmp = rb_find_file(FilePathValue(fname));
641    if (!tmp) load_failed(fname);
642    rb_load_internal(tmp, wrap);
643}
644
645void
646rb_load_protect(VALUE fname, int wrap, int *state)
647{
648    int status;
649
650    PUSH_TAG();
651    if ((status = EXEC_TAG()) == 0) {
652	rb_load(fname, wrap);
653    }
654    POP_TAG();
655    if (state)
656	*state = status;
657}
658
659/*
660 *  call-seq:
661 *     load(filename, wrap=false)   -> true
662 *
663 *  Loads and executes the Ruby
664 *  program in the file _filename_. If the filename does not
665 *  resolve to an absolute path, the file is searched for in the library
666 *  directories listed in <code>$:</code>. If the optional _wrap_
667 *  parameter is +true+, the loaded script will be executed
668 *  under an anonymous module, protecting the calling program's global
669 *  namespace. In no circumstance will any local variables in the loaded
670 *  file be propagated to the loading environment.
671 */
672
673static VALUE
674rb_f_load(int argc, VALUE *argv)
675{
676    VALUE fname, wrap, path;
677
678    rb_scan_args(argc, argv, "11", &fname, &wrap);
679
680    if (RUBY_DTRACE_LOAD_ENTRY_ENABLED()) {
681	RUBY_DTRACE_LOAD_ENTRY(StringValuePtr(fname),
682			       rb_sourcefile(),
683			       rb_sourceline());
684    }
685
686    path = rb_find_file(FilePathValue(fname));
687    if (!path) {
688	if (!rb_file_load_ok(RSTRING_PTR(fname)))
689	    load_failed(fname);
690	path = fname;
691    }
692    rb_load_internal(path, RTEST(wrap));
693
694    if (RUBY_DTRACE_LOAD_RETURN_ENABLED()) {
695	RUBY_DTRACE_LOAD_RETURN(StringValuePtr(fname),
696			       rb_sourcefile(),
697			       rb_sourceline());
698    }
699
700    return Qtrue;
701}
702
703static char *
704load_lock(const char *ftptr)
705{
706    st_data_t data;
707    st_table *loading_tbl = get_loading_table();
708
709    if (!loading_tbl || !st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
710	/* loading ruby library should be serialized. */
711	if (!loading_tbl) {
712	    GET_VM()->loading_table = loading_tbl = st_init_strtable();
713	}
714	/* partial state */
715	ftptr = ruby_strdup(ftptr);
716	data = (st_data_t)rb_thread_shield_new();
717	st_insert(loading_tbl, (st_data_t)ftptr, data);
718	return (char *)ftptr;
719    }
720    else if (RB_TYPE_P((VALUE)data, T_NODE) && nd_type((VALUE)data) == NODE_MEMO) {
721	NODE *memo = RNODE(data);
722	void (*init)(void) = (void (*)(void))memo->nd_cfnc;
723	data = (st_data_t)rb_thread_shield_new();
724	st_insert(loading_tbl, (st_data_t)ftptr, data);
725	(*init)();
726	return (char *)"";
727    }
728    if (RTEST(ruby_verbose)) {
729	rb_warning("loading in progress, circular require considered harmful - %s", ftptr);
730	/* TODO: display to $stderr, not stderr in C */
731	rb_backtrace();
732    }
733    switch (rb_thread_shield_wait((VALUE)data)) {
734      case Qfalse:
735	data = (st_data_t)ftptr;
736	st_insert(loading_tbl, data, (st_data_t)rb_thread_shield_new());
737	return 0;
738      case Qnil:
739	return 0;
740    }
741    return (char *)ftptr;
742}
743
744static int
745release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing)
746{
747    VALUE thread_shield = (VALUE)*value;
748    if (!existing) return ST_STOP;
749    if (done ? rb_thread_shield_destroy(thread_shield) : rb_thread_shield_release(thread_shield)) {
750	/* still in-use */
751	return ST_CONTINUE;
752    }
753    xfree((char *)*key);
754    return ST_DELETE;
755}
756
757static void
758load_unlock(const char *ftptr, int done)
759{
760    if (ftptr) {
761	st_data_t key = (st_data_t)ftptr;
762	st_table *loading_tbl = get_loading_table();
763
764	st_update(loading_tbl, key, release_thread_shield, done);
765    }
766}
767
768
769/*
770 *  call-seq:
771 *     require(name)    -> true or false
772 *
773 *  Loads the given +name+, returning +true+ if successful and +false+ if the
774 *  feature is already loaded.
775 *
776 *  If the filename does not resolve to an absolute path, it will be searched
777 *  for in the directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
778 *
779 *  If the filename has the extension ".rb", it is loaded as a source file; if
780 *  the extension is ".so", ".o", or ".dll", or the default shared library
781 *  extension on the current platform, Ruby loads the shared library as a
782 *  Ruby extension.  Otherwise, Ruby tries adding ".rb", ".so", and so on
783 *  to the name until found.  If the file named cannot be found, a LoadError
784 *  will be raised.
785 *
786 *  For Ruby extensions the filename given may use any shared library
787 *  extension.  For example, on Linux the socket extension is "socket.so" and
788 *  <code>require 'socket.dll'</code> will load the socket extension.
789 *
790 *  The absolute path of the loaded file is added to
791 *  <code>$LOADED_FEATURES</code> (<code>$"</code>).  A file will not be
792 *  loaded again if its path already appears in <code>$"</code>.  For example,
793 *  <code>require 'a'; require './a'</code> will not load <code>a.rb</code>
794 *  again.
795 *
796 *    require "my-library.rb"
797 *    require "db-driver"
798 *
799 *  Any constants or globals within the loaded source file will be available
800 *  in the calling program's global namespace. However, local variables will
801 *  not be propagated to the loading environment.
802 *
803 */
804
805VALUE
806rb_f_require(VALUE obj, VALUE fname)
807{
808    return rb_require_safe(fname, rb_safe_level());
809}
810
811/*
812 * call-seq:
813 *   require_relative(string) -> true or false
814 *
815 * Ruby tries to load the library named _string_ relative to the requiring
816 * file's path.  If the file's path cannot be determined a LoadError is raised.
817 * If a file is loaded +true+ is returned and false otherwise.
818 */
819VALUE
820rb_f_require_relative(VALUE obj, VALUE fname)
821{
822    VALUE base = rb_current_realfilepath();
823    if (NIL_P(base)) {
824	rb_loaderror("cannot infer basepath");
825    }
826    base = rb_file_dirname(base);
827    return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
828}
829
830static int
831search_required(VALUE fname, volatile VALUE *path, int safe_level)
832{
833    VALUE tmp;
834    char *ext, *ftptr;
835    int type, ft = 0;
836    const char *loading;
837
838    *path = 0;
839    ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
840    if (ext && !strchr(ext, '/')) {
841	if (IS_RBEXT(ext)) {
842	    if (rb_feature_p(ftptr, ext, TRUE, FALSE, &loading)) {
843		if (loading) *path = rb_filesystem_str_new_cstr(loading);
844		return 'r';
845	    }
846	    if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) {
847		ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
848		if (!rb_feature_p(ftptr, ext, TRUE, TRUE, &loading) || loading)
849		    *path = tmp;
850		return 'r';
851	    }
852	    return 0;
853	}
854	else if (IS_SOEXT(ext)) {
855	    if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) {
856		if (loading) *path = rb_filesystem_str_new_cstr(loading);
857		return 's';
858	    }
859	    tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
860#ifdef DLEXT2
861	    OBJ_FREEZE(tmp);
862	    if (rb_find_file_ext_safe(&tmp, loadable_ext + 1, safe_level)) {
863		ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
864		if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
865		    *path = tmp;
866		return 's';
867	    }
868#else
869	    rb_str_cat2(tmp, DLEXT);
870	    OBJ_FREEZE(tmp);
871	    if ((tmp = rb_find_file_safe(tmp, safe_level)) != 0) {
872		ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
873		if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
874		    *path = tmp;
875		return 's';
876	    }
877#endif
878	}
879	else if (IS_DLEXT(ext)) {
880	    if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) {
881		if (loading) *path = rb_filesystem_str_new_cstr(loading);
882		return 's';
883	    }
884	    if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) {
885		ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
886		if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
887		    *path = tmp;
888		return 's';
889	    }
890	}
891    }
892    else if ((ft = rb_feature_p(ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
893	if (loading) *path = rb_filesystem_str_new_cstr(loading);
894	return 'r';
895    }
896    tmp = fname;
897    type = rb_find_file_ext_safe(&tmp, loadable_ext, safe_level);
898    switch (type) {
899      case 0:
900	if (ft)
901	    goto statically_linked;
902	ftptr = RSTRING_PTR(tmp);
903	return rb_feature_p(ftptr, 0, FALSE, TRUE, 0);
904
905      default:
906	if (ft) {
907	  statically_linked:
908	    if (loading) *path = rb_filesystem_str_new_cstr(loading);
909	    return ft;
910	}
911      case 1:
912	ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
913	if (rb_feature_p(ftptr, ext, !--type, TRUE, &loading) && !loading)
914	    break;
915	*path = tmp;
916    }
917    return type ? 's' : 'r';
918}
919
920static void
921load_failed(VALUE fname)
922{
923    rb_load_fail(fname, "cannot load such file");
924}
925
926static VALUE
927load_ext(VALUE path)
928{
929    SCOPE_SET(NOEX_PUBLIC);
930    return (VALUE)dln_load(RSTRING_PTR(path));
931}
932
933VALUE
934rb_require_safe(VALUE fname, int safe)
935{
936    volatile VALUE result = Qnil;
937    rb_thread_t *th = GET_THREAD();
938    volatile VALUE errinfo = th->errinfo;
939    int state;
940    struct {
941	int safe;
942    } volatile saved;
943    char *volatile ftptr = 0;
944
945    if (RUBY_DTRACE_REQUIRE_ENTRY_ENABLED()) {
946	RUBY_DTRACE_REQUIRE_ENTRY(StringValuePtr(fname),
947				  rb_sourcefile(),
948				  rb_sourceline());
949    }
950
951    PUSH_TAG();
952    saved.safe = rb_safe_level();
953    if ((state = EXEC_TAG()) == 0) {
954	VALUE path;
955	long handle;
956	int found;
957
958	rb_set_safe_level_force(safe);
959	FilePathValue(fname);
960	rb_set_safe_level_force(0);
961
962	if (RUBY_DTRACE_FIND_REQUIRE_ENTRY_ENABLED()) {
963	    RUBY_DTRACE_FIND_REQUIRE_ENTRY(StringValuePtr(fname),
964					   rb_sourcefile(),
965					   rb_sourceline());
966	}
967
968	found = search_required(fname, &path, safe);
969
970	if (RUBY_DTRACE_FIND_REQUIRE_RETURN_ENABLED()) {
971	    RUBY_DTRACE_FIND_REQUIRE_RETURN(StringValuePtr(fname),
972					    rb_sourcefile(),
973					    rb_sourceline());
974	}
975	if (found) {
976	    if (!path || !(ftptr = load_lock(RSTRING_PTR(path)))) {
977		result = Qfalse;
978	    }
979	    else if (!*ftptr) {
980		rb_provide_feature(path);
981		result = Qtrue;
982	    }
983	    else {
984		switch (found) {
985		  case 'r':
986		    rb_load_internal(path, 0);
987		    break;
988
989		  case 's':
990		    handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
991						    path, 0, path);
992		    rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
993		    break;
994		}
995		rb_provide_feature(path);
996		result = Qtrue;
997	    }
998	}
999    }
1000    POP_TAG();
1001    load_unlock(ftptr, !state);
1002
1003    rb_set_safe_level_force(saved.safe);
1004    if (state) {
1005	JUMP_TAG(state);
1006    }
1007
1008    if (NIL_P(result)) {
1009	load_failed(fname);
1010    }
1011
1012    th->errinfo = errinfo;
1013
1014    if (RUBY_DTRACE_REQUIRE_RETURN_ENABLED()) {
1015	RUBY_DTRACE_REQUIRE_RETURN(StringValuePtr(fname),
1016				  rb_sourcefile(),
1017				  rb_sourceline());
1018    }
1019
1020    return result;
1021}
1022
1023VALUE
1024rb_require(const char *fname)
1025{
1026    VALUE fn = rb_str_new2(fname);
1027    OBJ_FREEZE(fn);
1028    return rb_require_safe(fn, rb_safe_level());
1029}
1030
1031static int
1032register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1033{
1034    const char *name = (char *)*key;
1035    if (existing) {
1036	/* already registered */
1037	rb_warn("%s is already registered", name);
1038    }
1039    else {
1040	*value = (st_data_t)NEW_MEMO(init, 0, 0);
1041	*key = (st_data_t)ruby_strdup(name);
1042    }
1043    return ST_CONTINUE;
1044}
1045
1046RUBY_FUNC_EXPORTED void
1047ruby_init_ext(const char *name, void (*init)(void))
1048{
1049    st_table *loading_tbl = get_loading_table();
1050
1051    if (!loading_tbl) {
1052	GET_VM()->loading_table = loading_tbl = st_init_strtable();
1053    }
1054    st_update(loading_tbl, (st_data_t)name, register_init_ext, (st_data_t)init);
1055}
1056
1057/*
1058 *  call-seq:
1059 *     mod.autoload(module, filename)   -> nil
1060 *
1061 *  Registers _filename_ to be loaded (using <code>Kernel::require</code>)
1062 *  the first time that _module_ (which may be a <code>String</code> or
1063 *  a symbol) is accessed in the namespace of _mod_.
1064 *
1065 *     module A
1066 *     end
1067 *     A.autoload(:B, "b")
1068 *     A::B.doit            # autoloads "b"
1069 */
1070
1071static VALUE
1072rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1073{
1074    ID id = rb_to_id(sym);
1075
1076    FilePathValue(file);
1077    rb_autoload(mod, id, RSTRING_PTR(file));
1078    return Qnil;
1079}
1080
1081/*
1082 *  call-seq:
1083 *     mod.autoload?(name)   -> String or nil
1084 *
1085 *  Returns _filename_ to be loaded if _name_ is registered as
1086 *  +autoload+ in the namespace of _mod_.
1087 *
1088 *     module A
1089 *     end
1090 *     A.autoload(:B, "b")
1091 *     A.autoload?(:B)            #=> "b"
1092 */
1093
1094static VALUE
1095rb_mod_autoload_p(VALUE mod, VALUE sym)
1096{
1097    ID id = rb_check_id(&sym);
1098    if (!id) {
1099	return Qnil;
1100    }
1101    return rb_autoload_p(mod, id);
1102}
1103
1104/*
1105 *  call-seq:
1106 *     autoload(module, filename)   -> nil
1107 *
1108 *  Registers _filename_ to be loaded (using <code>Kernel::require</code>)
1109 *  the first time that _module_ (which may be a <code>String</code> or
1110 *  a symbol) is accessed.
1111 *
1112 *     autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1113 */
1114
1115static VALUE
1116rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1117{
1118    VALUE klass = rb_class_real(rb_vm_cbase());
1119    if (NIL_P(klass)) {
1120	rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1121    }
1122    return rb_mod_autoload(klass, sym, file);
1123}
1124
1125/*
1126 *  call-seq:
1127 *     autoload?(name)   -> String or nil
1128 *
1129 *  Returns _filename_ to be loaded if _name_ is registered as
1130 *  +autoload+.
1131 *
1132 *     autoload(:B, "b")
1133 *     autoload?(:B)            #=> "b"
1134 */
1135
1136static VALUE
1137rb_f_autoload_p(VALUE obj, VALUE sym)
1138{
1139    /* use rb_vm_cbase() as same as rb_f_autoload. */
1140    VALUE klass = rb_vm_cbase();
1141    if (NIL_P(klass)) {
1142	return Qnil;
1143    }
1144    return rb_mod_autoload_p(klass, sym);
1145}
1146
1147void
1148Init_load()
1149{
1150#undef rb_intern
1151#define rb_intern(str) rb_intern2((str), strlen(str))
1152    rb_vm_t *vm = GET_VM();
1153    static const char var_load_path[] = "$:";
1154    ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1155
1156    rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
1157    rb_alias_variable(rb_intern("$-I"), id_load_path);
1158    rb_alias_variable(rb_intern("$LOAD_PATH"), id_load_path);
1159    vm->load_path = rb_ary_new();
1160    vm->expanded_load_path = rb_ary_tmp_new(0);
1161    vm->load_path_snapshot = rb_ary_tmp_new(0);
1162    vm->load_path_check_cache = 0;
1163
1164    rb_define_virtual_variable("$\"", get_loaded_features, 0);
1165    rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
1166    vm->loaded_features = rb_ary_new();
1167    vm->loaded_features_snapshot = rb_ary_tmp_new(0);
1168    vm->loaded_features_index = st_init_strtable();
1169
1170    rb_define_global_function("load", rb_f_load, -1);
1171    rb_define_global_function("require", rb_f_require, 1);
1172    rb_define_global_function("require_relative", rb_f_require_relative, 1);
1173    rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1174    rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, 1);
1175    rb_define_global_function("autoload", rb_f_autoload, 2);
1176    rb_define_global_function("autoload?", rb_f_autoload_p, 1);
1177
1178    ruby_dln_librefs = rb_ary_tmp_new(0);
1179    rb_gc_register_mark_object(ruby_dln_librefs);
1180}
1181