Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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