update comment.
[ruby-svn.git] / load.c
bloba6daff43f6715877498f810041fc30cec0706195
1 /*
2 * load methods from eval.c
3 */
5 #include "eval_intern.h"
7 VALUE ruby_dln_librefs;
9 #define IS_RBEXT(e) (strcmp(e, ".rb") == 0)
10 #define IS_SOEXT(e) (strcmp(e, ".so") == 0 || strcmp(e, ".o") == 0)
11 #ifdef DLEXT2
12 #define IS_DLEXT(e) (strcmp(e, DLEXT) == 0 || strcmp(e, DLEXT2) == 0)
13 #else
14 #define IS_DLEXT(e) (strcmp(e, DLEXT) == 0)
15 #endif
18 static const char *const loadable_ext[] = {
19 ".rb", DLEXT,
20 #ifdef DLEXT2
21 DLEXT2,
22 #endif
26 VALUE
27 rb_get_load_path(void)
29 VALUE load_path = GET_VM()->load_path;
30 VALUE ary = rb_ary_new2(RARRAY_LEN(load_path));
31 long i;
33 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
34 rb_ary_push(ary, rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil));
36 return ary;
39 static VALUE
40 load_path_getter(ID id, rb_vm_t *vm)
42 return vm->load_path;
45 static VALUE
46 get_loaded_features(void)
48 return GET_VM()->loaded_features;
51 static st_table *
52 get_loading_table(void)
54 return GET_VM()->loading_table;
57 static VALUE
58 loaded_feature_path(const char *name, long vlen, const char *feature, long len,
59 int type, VALUE load_path)
61 long i;
63 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
64 VALUE p = RARRAY_PTR(load_path)[i];
65 const char *s = StringValuePtr(p);
66 long n = RSTRING_LEN(p);
68 if (vlen < n + len + 1) continue;
69 if (n && (strncmp(name, s, n) || name[n] != '/')) continue;
70 if (strncmp(name + n + 1, feature, len)) continue;
71 if (name[n+len+1] && name[n+len+1] != '.') continue;
72 switch (type) {
73 case 's':
74 if (IS_DLEXT(&name[n+len+1])) return p;
75 break;
76 case 'r':
77 if (IS_RBEXT(&name[n+len+1])) return p;
78 break;
79 default:
80 return p;
83 return 0;
86 struct loaded_feature_searching {
87 const char *name;
88 long len;
89 int type;
90 VALUE load_path;
91 const char *result;
94 static int
95 loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
97 const char *s = (const char *)v;
98 struct loaded_feature_searching *fp = (struct loaded_feature_searching *)f;
99 VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len,
100 fp->type, fp->load_path);
101 if (!p) return ST_CONTINUE;
102 fp->result = s;
103 return ST_STOP;
106 static int
107 rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn)
109 VALUE v, features, p, load_path = 0;
110 const char *f, *e;
111 long i, len, elen, n;
112 st_table *loading_tbl;
113 st_data_t data;
114 int type;
116 if (fn) *fn = 0;
117 if (ext) {
118 len = ext - feature;
119 elen = strlen(ext);
120 type = rb ? 'r' : 's';
122 else {
123 len = strlen(feature);
124 elen = 0;
125 type = 0;
127 features = get_loaded_features();
128 for (i = 0; i < RARRAY_LEN(features); ++i) {
129 v = RARRAY_PTR(features)[i];
130 f = StringValuePtr(v);
131 if ((n = RSTRING_LEN(v)) < len) continue;
132 if (strncmp(f, feature, len) != 0) {
133 if (expanded) continue;
134 if (!load_path) load_path = rb_get_load_path();
135 if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
136 continue;
137 f += RSTRING_LEN(p) + 1;
139 if (!*(e = f + len)) {
140 if (ext) continue;
141 return 'u';
143 if (*e != '.') continue;
144 if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
145 return 's';
147 if ((rb || !ext) && (IS_RBEXT(e))) {
148 return 'r';
151 loading_tbl = get_loading_table();
152 if (loading_tbl) {
153 f = 0;
154 if (!expanded) {
155 struct loaded_feature_searching fs;
156 fs.name = feature;
157 fs.len = len;
158 fs.type = type;
159 fs.load_path = load_path ? load_path : rb_get_load_path();
160 fs.result = 0;
161 st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
162 if ((f = fs.result) != 0) {
163 if (fn) *fn = f;
164 goto loading;
167 if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
168 if (fn) *fn = (const char*)data;
169 loading:
170 if (!ext) return 'u';
171 return !IS_RBEXT(ext) ? 's' : 'r';
173 else {
174 VALUE bufstr;
175 char *buf;
177 if (ext && *ext) return 0;
178 bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN);
179 buf = RSTRING_PTR(bufstr);
180 MEMCPY(buf, feature, char, len);
181 for (i = 0; (e = loadable_ext[i]) != 0; i++) {
182 strncpy(buf + len, e, DLEXT_MAXLEN + 1);
183 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
184 rb_str_resize(bufstr, 0);
185 if (fn) *fn = (const char*)data;
186 return i ? 's' : 'r';
189 rb_str_resize(bufstr, 0);
192 return 0;
196 rb_provided(const char *feature)
198 const char *ext = strrchr(feature, '.');
199 volatile VALUE fullpath = 0;
201 if (*feature == '.' &&
202 (feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) {
203 fullpath = rb_file_expand_path(rb_str_new2(feature), Qnil);
204 feature = RSTRING_PTR(fullpath);
206 if (ext && !strchr(ext, '/')) {
207 if (IS_RBEXT(ext)) {
208 if (rb_feature_p(feature, ext, Qtrue, Qfalse, 0)) return Qtrue;
209 return Qfalse;
211 else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
212 if (rb_feature_p(feature, ext, Qfalse, Qfalse, 0)) return Qtrue;
213 return Qfalse;
216 if (rb_feature_p(feature, feature + strlen(feature), Qtrue, Qfalse, 0))
217 return Qtrue;
218 return Qfalse;
221 static void
222 rb_provide_feature(VALUE feature)
224 rb_ary_push(get_loaded_features(), feature);
227 void
228 rb_provide(const char *feature)
230 rb_provide_feature(rb_str_new2(feature));
233 NORETURN(static void load_failed(VALUE));
235 void
236 rb_load(VALUE fname, int wrap)
238 VALUE tmp;
239 int state;
240 rb_thread_t *th = GET_THREAD();
241 volatile VALUE wrapper = th->top_wrapper;
242 volatile VALUE self = th->top_self;
243 volatile int loaded = Qfalse;
244 volatile int mild_compile_error;
245 #ifndef __GNUC__
246 rb_thread_t *volatile th0 = th;
247 #endif
249 FilePathValue(fname);
250 fname = rb_str_new4(fname);
251 tmp = rb_find_file(fname);
252 if (!tmp) {
253 load_failed(fname);
255 RB_GC_GUARD(fname) = rb_str_new4(tmp);
257 th->errinfo = Qnil; /* ensure */
259 if (!wrap) {
260 rb_secure(4); /* should alter global state */
261 th->top_wrapper = 0;
263 else {
264 /* load in anonymous module as toplevel */
265 th->top_self = rb_obj_clone(rb_vm_top_self());
266 th->top_wrapper = rb_module_new();
267 rb_extend_object(th->top_self, th->top_wrapper);
270 mild_compile_error = th->mild_compile_error;
271 PUSH_TAG();
272 state = EXEC_TAG();
273 if (state == 0) {
274 NODE *node;
275 VALUE iseq;
277 th->mild_compile_error++;
278 node = (NODE *)rb_load_file(RSTRING_PTR(fname));
279 loaded = Qtrue;
280 iseq = rb_iseq_new(node, rb_str_new2("<top (required)>"),
281 fname, Qfalse, ISEQ_TYPE_TOP);
282 th->mild_compile_error--;
283 rb_iseq_eval(iseq);
285 POP_TAG();
287 #ifndef __GNUC__
288 th = th0;
289 fname = RB_GC_GUARD(fname);
290 #endif
291 th->mild_compile_error = mild_compile_error;
292 th->top_self = self;
293 th->top_wrapper = wrapper;
295 if (!loaded) {
296 rb_exc_raise(GET_THREAD()->errinfo);
298 if (state) {
299 vm_jump_tag_but_local_jump(state, Qundef);
302 if (!NIL_P(GET_THREAD()->errinfo)) {
303 /* exception during load */
304 rb_exc_raise(th->errinfo);
308 void
309 rb_load_protect(VALUE fname, int wrap, int *state)
311 int status;
313 PUSH_TAG();
314 if ((status = EXEC_TAG()) == 0) {
315 rb_load(fname, wrap);
317 POP_TAG();
318 if (state)
319 *state = status;
323 * call-seq:
324 * load(filename, wrap=false) => true
326 * Loads and executes the Ruby
327 * program in the file _filename_. If the filename does not
328 * resolve to an absolute path, the file is searched for in the library
329 * directories listed in <code>$:</code>. If the optional _wrap_
330 * parameter is +true+, the loaded script will be executed
331 * under an anonymous module, protecting the calling program's global
332 * namespace. In no circumstance will any local variables in the loaded
333 * file be propagated to the loading environment.
336 static VALUE
337 rb_f_load(int argc, VALUE *argv)
339 VALUE fname, wrap;
341 rb_scan_args(argc, argv, "11", &fname, &wrap);
342 rb_load(fname, RTEST(wrap));
343 return Qtrue;
346 static char *
347 load_lock(const char *ftptr)
349 st_data_t data;
350 st_table *loading_tbl = get_loading_table();
352 if (!loading_tbl || !st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
353 /* loading ruby library should be serialized. */
354 if (!loading_tbl) {
355 GET_VM()->loading_table = loading_tbl = st_init_strtable();
357 /* partial state */
358 ftptr = ruby_strdup(ftptr);
359 data = (st_data_t)rb_barrier_new();
360 st_insert(loading_tbl, (st_data_t)ftptr, data);
361 return (char *)ftptr;
363 return RTEST(rb_barrier_wait((VALUE)data)) ? (char *)ftptr : 0;
366 static void
367 load_unlock(const char *ftptr)
369 if (ftptr) {
370 st_data_t key = (st_data_t)ftptr;
371 st_data_t data;
372 st_table *loading_tbl = get_loading_table();
374 if (st_delete(loading_tbl, &key, &data)) {
375 xfree((char *)key);
376 rb_barrier_release((VALUE)data);
383 * call-seq:
384 * require(string) => true or false
386 * Ruby tries to load the library named _string_, returning
387 * +true+ if successful. If the filename does not resolve to
388 * an absolute path, it will be searched for in the directories listed
389 * in <code>$:</code>. If the file has the extension ``.rb'', it is
390 * loaded as a source file; if the extension is ``.so'', ``.o'', or
391 * ``.dll'', or whatever the default shared library extension is on
392 * the current platform, Ruby loads the shared library as a Ruby
393 * extension. Otherwise, Ruby tries adding ``.rb'', ``.so'', and so on
394 * to the name. The name of the loaded feature is added to the array in
395 * <code>$"</code>. A feature will not be loaded if it's name already
396 * appears in <code>$"</code>. However, the file name is not converted
397 * to an absolute path, so that ``<code>require 'a';require
398 * './a'</code>'' will load <code>a.rb</code> twice.
400 * require "my-library.rb"
401 * require "db-driver"
404 VALUE
405 rb_f_require(VALUE obj, VALUE fname)
407 return rb_require_safe(fname, rb_safe_level());
410 static int
411 search_required(VALUE fname, volatile VALUE *path)
413 VALUE tmp;
414 char *ext, *ftptr;
415 int type, ft = 0;
416 const char *loading;
418 *path = 0;
419 ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
420 if (ext && !strchr(ext, '/')) {
421 if (IS_RBEXT(ext)) {
422 if (rb_feature_p(ftptr, ext, Qtrue, Qfalse, &loading)) {
423 if (loading) *path = rb_str_new2(loading);
424 return 'r';
426 if ((tmp = rb_find_file(fname)) != 0) {
427 tmp = rb_file_expand_path(tmp, Qnil);
428 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
429 if (!rb_feature_p(ftptr, ext, Qtrue, Qtrue, 0))
430 *path = tmp;
431 return 'r';
433 return 0;
435 else if (IS_SOEXT(ext)) {
436 if (rb_feature_p(ftptr, ext, Qfalse, Qfalse, &loading)) {
437 if (loading) *path = rb_str_new2(loading);
438 return 's';
440 tmp = rb_str_new(RSTRING_PTR(fname), ext - RSTRING_PTR(fname));
441 #ifdef DLEXT2
442 OBJ_FREEZE(tmp);
443 if (rb_find_file_ext(&tmp, loadable_ext + 1)) {
444 tmp = rb_file_expand_path(tmp, Qnil);
445 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
446 if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0))
447 *path = tmp;
448 return 's';
450 #else
451 rb_str_cat2(tmp, DLEXT);
452 OBJ_FREEZE(tmp);
453 if ((tmp = rb_find_file(tmp)) != 0) {
454 tmp = rb_file_expand_path(tmp, Qnil);
455 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
456 if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0))
457 *path = tmp;
458 return 's';
460 #endif
462 else if (IS_DLEXT(ext)) {
463 if (rb_feature_p(ftptr, ext, Qfalse, Qfalse, &loading)) {
464 if (loading) *path = rb_str_new2(loading);
465 return 's';
467 if ((tmp = rb_find_file(fname)) != 0) {
468 tmp = rb_file_expand_path(tmp, Qnil);
469 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
470 if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0))
471 *path = tmp;
472 return 's';
476 else if ((ft = rb_feature_p(ftptr, 0, Qfalse, Qfalse, &loading)) == 'r') {
477 if (loading) *path = rb_str_new2(loading);
478 return 'r';
480 tmp = fname;
481 type = rb_find_file_ext(&tmp, loadable_ext);
482 tmp = rb_file_expand_path(tmp, Qnil);
483 switch (type) {
484 case 0:
485 if (ft)
486 break;
487 ftptr = RSTRING_PTR(tmp);
488 return rb_feature_p(ftptr, 0, Qfalse, Qtrue, 0);
490 default:
491 if (ft)
492 break;
493 case 1:
494 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
495 if (rb_feature_p(ftptr, ext, !--type, Qtrue, &loading) && !loading)
496 break;
497 *path = tmp;
499 return type ? 's' : 'r';
502 static void
503 load_failed(VALUE fname)
505 rb_raise(rb_eLoadError, "no such file to load -- %s",
506 RSTRING_PTR(fname));
509 static VALUE
510 load_ext(VALUE path)
512 SCOPE_SET(NOEX_PUBLIC);
513 return (VALUE)dln_load(RSTRING_PTR(path));
516 VALUE
517 rb_require_safe(VALUE fname, int safe)
519 VALUE result = Qnil;
520 rb_thread_t *th = GET_THREAD();
521 volatile VALUE errinfo = th->errinfo;
522 int state;
523 struct {
524 int safe;
525 } volatile saved;
526 char *volatile ftptr = 0;
528 PUSH_TAG();
529 saved.safe = rb_safe_level();
530 if ((state = EXEC_TAG()) == 0) {
531 VALUE path;
532 long handle;
533 int found;
535 rb_set_safe_level_force(safe);
536 FilePathValue(fname);
537 RB_GC_GUARD(fname) = rb_str_new4(fname);
538 found = search_required(fname, &path);
539 if (found) {
540 if (!path || !(ftptr = load_lock(RSTRING_PTR(path)))) {
541 result = Qfalse;
543 else {
544 rb_set_safe_level_force(0);
545 switch (found) {
546 case 'r':
547 rb_load(path, 0);
548 break;
550 case 's':
551 handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
552 path, 0, path);
553 rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
554 break;
556 rb_provide_feature(path);
557 result = Qtrue;
561 POP_TAG();
562 load_unlock(ftptr);
564 rb_set_safe_level_force(saved.safe);
565 if (state) {
566 JUMP_TAG(state);
569 if (NIL_P(result)) {
570 load_failed(fname);
573 th->errinfo = errinfo;
575 return result;
578 VALUE
579 rb_require(const char *fname)
581 VALUE fn = rb_str_new2(fname);
582 OBJ_FREEZE(fn);
583 return rb_require_safe(fn, rb_safe_level());
586 static VALUE
587 init_ext_call(VALUE arg)
589 SCOPE_SET(NOEX_PUBLIC);
590 (*(void (*)(void))arg)();
591 return Qnil;
594 void
595 ruby_init_ext(const char *name, void (*init)(void))
597 if (load_lock(name)) {
598 rb_vm_call_cfunc(rb_vm_top_self(), init_ext_call, (VALUE)init,
599 0, rb_str_new2(name));
600 rb_provide(name);
601 load_unlock(name);
606 * call-seq:
607 * mod.autoload(name, filename) => nil
609 * Registers _filename_ to be loaded (using <code>Kernel::require</code>)
610 * the first time that _module_ (which may be a <code>String</code> or
611 * a symbol) is accessed in the namespace of _mod_.
613 * module A
614 * end
615 * A.autoload(:B, "b")
616 * A::B.doit # autoloads "b"
619 static VALUE
620 rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
622 ID id = rb_to_id(sym);
624 Check_SafeStr(file);
625 rb_autoload(mod, id, RSTRING_PTR(file));
626 return Qnil;
630 * MISSING: documentation
633 static VALUE
634 rb_mod_autoload_p(VALUE mod, VALUE sym)
636 return rb_autoload_p(mod, rb_to_id(sym));
640 * call-seq:
641 * autoload(module, filename) => nil
643 * Registers _filename_ to be loaded (using <code>Kernel::require</code>)
644 * the first time that _module_ (which may be a <code>String</code> or
645 * a symbol) is accessed.
647 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
650 static VALUE
651 rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
653 VALUE klass = rb_vm_cbase();
654 if (NIL_P(klass)) {
655 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
657 return rb_mod_autoload(klass, sym, file);
661 * MISSING: documentation
664 static VALUE
665 rb_f_autoload_p(VALUE obj, VALUE sym)
667 /* use rb_vm_cbase() as same as rb_f_autoload. */
668 VALUE klass = rb_vm_cbase();
669 if (NIL_P(klass)) {
670 return Qnil;
672 return rb_mod_autoload_p(klass, sym);
675 void
676 Init_load()
678 #undef rb_intern
679 #define rb_intern(str) rb_intern2(str, strlen(str))
680 rb_vm_t *vm = GET_VM();
681 static const char var_load_path[] = "$:";
682 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
684 rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, 0);
685 rb_alias_variable(rb_intern("$-I"), id_load_path);
686 rb_alias_variable(rb_intern("$LOAD_PATH"), id_load_path);
687 vm->load_path = rb_ary_new();
689 rb_define_virtual_variable("$\"", get_loaded_features, 0);
690 rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
691 vm->loaded_features = rb_ary_new();
693 rb_define_global_function("load", rb_f_load, -1);
694 rb_define_global_function("require", rb_f_require, 1);
695 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
696 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, 1);
697 rb_define_global_function("autoload", rb_f_autoload, 2);
698 rb_define_global_function("autoload?", rb_f_autoload_p, 1);
700 ruby_dln_librefs = rb_ary_new();
701 rb_register_mark_object(ruby_dln_librefs);