00001
00002
00003
00004
00005 #include "ruby/ruby.h"
00006 #include "ruby/util.h"
00007 #include "internal.h"
00008 #include "dln.h"
00009 #include "eval_intern.h"
00010 #include "probes.h"
00011 #include "node.h"
00012
00013 VALUE ruby_dln_librefs;
00014
00015 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
00016
00017 #define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
00018 #define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
00019 #ifdef DLEXT2
00020 #define IS_DLEXT(e) (strcmp((e), DLEXT) == 0 || strcmp((e), DLEXT2) == 0)
00021 #else
00022 #define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
00023 #endif
00024
00025 static const char *const loadable_ext[] = {
00026 ".rb", DLEXT,
00027 #ifdef DLEXT2
00028 DLEXT2,
00029 #endif
00030 0
00031 };
00032
00033 VALUE
00034 rb_get_load_path(void)
00035 {
00036 VALUE load_path = GET_VM()->load_path;
00037 return load_path;
00038 }
00039
00040 enum expand_type {
00041 EXPAND_ALL,
00042 EXPAND_RELATIVE,
00043 EXPAND_HOME,
00044 EXPAND_NON_CACHE
00045 };
00046
00047
00048
00049
00050
00051
00052 static void
00053 rb_construct_expanded_load_path(int type, int *has_relative, int *has_non_cache)
00054 {
00055 rb_vm_t *vm = GET_VM();
00056 VALUE load_path = vm->load_path;
00057 VALUE expanded_load_path = vm->expanded_load_path;
00058 VALUE ary;
00059 long i;
00060 int level = rb_safe_level();
00061
00062 ary = rb_ary_tmp_new(RARRAY_LEN(load_path));
00063 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
00064 VALUE path, as_str, expanded_path;
00065 int is_string, non_cache;
00066 char *as_cstr;
00067 as_str = path = RARRAY_PTR(load_path)[i];
00068 is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0;
00069 non_cache = !is_string ? 1 : 0;
00070 as_str = rb_get_path_check_to_string(path, level);
00071 as_cstr = RSTRING_PTR(as_str);
00072
00073 if (!non_cache) {
00074 if ((type == EXPAND_RELATIVE &&
00075 rb_is_absolute_path(as_cstr)) ||
00076 (type == EXPAND_HOME &&
00077 (!as_cstr[0] || as_cstr[0] != '~')) ||
00078 (type == EXPAND_NON_CACHE)) {
00079
00080 rb_ary_push(ary, RARRAY_PTR(expanded_load_path)[i]);
00081 continue;
00082 }
00083 }
00084 if (!*has_relative && !rb_is_absolute_path(as_cstr))
00085 *has_relative = 1;
00086 if (!*has_non_cache && non_cache)
00087 *has_non_cache = 1;
00088
00089 if (is_string)
00090 rb_str_freeze(path);
00091 as_str = rb_get_path_check_convert(path, as_str, level);
00092 expanded_path = rb_file_expand_path_fast(as_str, Qnil);
00093 rb_str_freeze(expanded_path);
00094 rb_ary_push(ary, expanded_path);
00095 }
00096 rb_obj_freeze(ary);
00097 vm->expanded_load_path = ary;
00098 rb_ary_replace(vm->load_path_snapshot, vm->load_path);
00099 }
00100
00101 static VALUE
00102 load_path_getcwd(void)
00103 {
00104 char *cwd = my_getcwd();
00105 VALUE cwd_str = rb_filesystem_str_new_cstr(cwd);
00106 xfree(cwd);
00107 return cwd_str;
00108 }
00109
00110 VALUE
00111 rb_get_expanded_load_path(void)
00112 {
00113 rb_vm_t *vm = GET_VM();
00114 const VALUE non_cache = Qtrue;
00115
00116 if (!rb_ary_shared_with_p(vm->load_path_snapshot, vm->load_path)) {
00117
00118 int has_relative = 0, has_non_cache = 0;
00119 rb_construct_expanded_load_path(EXPAND_ALL, &has_relative, &has_non_cache);
00120 if (has_relative) {
00121 vm->load_path_check_cache = load_path_getcwd();
00122 }
00123 else if (has_non_cache) {
00124
00125 vm->load_path_check_cache = non_cache;
00126 }
00127 else {
00128 vm->load_path_check_cache = 0;
00129 }
00130 }
00131 else if (vm->load_path_check_cache == non_cache) {
00132 int has_relative = 1, has_non_cache = 1;
00133
00134 rb_construct_expanded_load_path(EXPAND_NON_CACHE,
00135 &has_relative, &has_non_cache);
00136 }
00137 else if (vm->load_path_check_cache) {
00138 int has_relative = 1, has_non_cache = 1;
00139 VALUE cwd = load_path_getcwd();
00140 if (!rb_str_equal(vm->load_path_check_cache, cwd)) {
00141
00142
00143 vm->load_path_check_cache = cwd;
00144 rb_construct_expanded_load_path(EXPAND_RELATIVE,
00145 &has_relative, &has_non_cache);
00146 }
00147 else {
00148
00149 rb_construct_expanded_load_path(EXPAND_HOME,
00150 &has_relative, &has_non_cache);
00151 }
00152 }
00153 return vm->expanded_load_path;
00154 }
00155
00156 static VALUE
00157 load_path_getter(ID id, rb_vm_t *vm)
00158 {
00159 return vm->load_path;
00160 }
00161
00162 static VALUE
00163 get_loaded_features(void)
00164 {
00165 return GET_VM()->loaded_features;
00166 }
00167
00168 static void
00169 reset_loaded_features_snapshot(void)
00170 {
00171 rb_vm_t *vm = GET_VM();
00172 rb_ary_replace(vm->loaded_features_snapshot, vm->loaded_features);
00173 }
00174
00175 static struct st_table *
00176 get_loaded_features_index_raw(void)
00177 {
00178 return GET_VM()->loaded_features_index;
00179 }
00180
00181 static st_table *
00182 get_loading_table(void)
00183 {
00184 return GET_VM()->loading_table;
00185 }
00186
00187 static void
00188 features_index_add_single(VALUE short_feature, VALUE offset)
00189 {
00190 struct st_table *features_index;
00191 VALUE this_feature_index = Qnil;
00192 char *short_feature_cstr;
00193
00194 Check_Type(offset, T_FIXNUM);
00195 Check_Type(short_feature, T_STRING);
00196 short_feature_cstr = StringValueCStr(short_feature);
00197
00198 features_index = get_loaded_features_index_raw();
00199 st_lookup(features_index, (st_data_t)short_feature_cstr, (st_data_t *)&this_feature_index);
00200
00201 if (NIL_P(this_feature_index)) {
00202 st_insert(features_index, (st_data_t)ruby_strdup(short_feature_cstr), (st_data_t)offset);
00203 }
00204 else if (RB_TYPE_P(this_feature_index, T_FIXNUM)) {
00205 VALUE feature_indexes[2];
00206 feature_indexes[0] = this_feature_index;
00207 feature_indexes[1] = offset;
00208 this_feature_index = rb_ary_tmp_new(numberof(feature_indexes));
00209 rb_ary_cat(this_feature_index, feature_indexes, numberof(feature_indexes));
00210 st_insert(features_index, (st_data_t)short_feature_cstr, (st_data_t)this_feature_index);
00211 }
00212 else {
00213 Check_Type(this_feature_index, T_ARRAY);
00214 rb_ary_push(this_feature_index, offset);
00215 }
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226 static void
00227 features_index_add(VALUE feature, VALUE offset)
00228 {
00229 VALUE short_feature;
00230 const char *feature_str, *feature_end, *ext, *p;
00231
00232 feature_str = StringValuePtr(feature);
00233 feature_end = feature_str + RSTRING_LEN(feature);
00234
00235 for (ext = feature_end; ext > feature_str; ext--)
00236 if (*ext == '.' || *ext == '/')
00237 break;
00238 if (*ext != '.')
00239 ext = NULL;
00240
00241
00242
00243 p = ext ? ext : feature_end;
00244 while (1) {
00245 p--;
00246 while (p >= feature_str && *p != '/')
00247 p--;
00248 if (p < feature_str)
00249 break;
00250
00251 short_feature = rb_str_subseq(feature, p + 1 - feature_str, feature_end - p - 1);
00252 features_index_add_single(short_feature, offset);
00253 if (ext) {
00254 short_feature = rb_str_subseq(feature, p + 1 - feature_str, ext - p - 1);
00255 features_index_add_single(short_feature, offset);
00256 }
00257 }
00258 features_index_add_single(feature, offset);
00259 if (ext) {
00260 short_feature = rb_str_subseq(feature, 0, ext - feature_str);
00261 features_index_add_single(short_feature, offset);
00262 }
00263 }
00264
00265 static int
00266 loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
00267 {
00268 xfree((char *)key);
00269 return ST_DELETE;
00270 }
00271
00272 static st_table *
00273 get_loaded_features_index(void)
00274 {
00275 VALUE features;
00276 int i;
00277 rb_vm_t *vm = GET_VM();
00278
00279 if (!rb_ary_shared_with_p(vm->loaded_features_snapshot, vm->loaded_features)) {
00280
00281
00282 st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
00283 features = vm->loaded_features;
00284 for (i = 0; i < RARRAY_LEN(features); i++) {
00285 VALUE entry, as_str;
00286 as_str = entry = rb_ary_entry(features, i);
00287 StringValue(as_str);
00288 if (as_str != entry)
00289 rb_ary_store(features, i, as_str);
00290 rb_str_freeze(as_str);
00291 features_index_add(as_str, INT2FIX(i));
00292 }
00293 reset_loaded_features_snapshot();
00294 }
00295 return vm->loaded_features_index;
00296 }
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309 static VALUE
00310 loaded_feature_path(const char *name, long vlen, const char *feature, long len,
00311 int type, VALUE load_path)
00312 {
00313 long i;
00314 long plen;
00315 const char *e;
00316
00317 if (vlen < len+1) return 0;
00318 if (!strncmp(name+(vlen-len), feature, len)) {
00319 plen = vlen - len;
00320 }
00321 else {
00322 for (e = name + vlen; name != e && *e != '.' && *e != '/'; --e);
00323 if (*e != '.' ||
00324 e-name < len ||
00325 strncmp(e-len, feature, len))
00326 return 0;
00327 plen = e - name - len;
00328 }
00329 if (plen > 0 && name[plen-1] != '/') {
00330 return 0;
00331 }
00332 if (type == 's' ? !IS_DLEXT(&name[plen+len]) :
00333 type == 'r' ? !IS_RBEXT(&name[plen+len]) :
00334 0) {
00335 return 0;
00336 }
00337
00338
00339
00340 if (plen > 0) --plen;
00341 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
00342 VALUE p = RARRAY_PTR(load_path)[i];
00343 const char *s = StringValuePtr(p);
00344 long n = RSTRING_LEN(p);
00345
00346 if (n != plen) continue;
00347 if (n && strncmp(name, s, n)) continue;
00348 return p;
00349 }
00350 return 0;
00351 }
00352
00353 struct loaded_feature_searching {
00354 const char *name;
00355 long len;
00356 int type;
00357 VALUE load_path;
00358 const char *result;
00359 };
00360
00361 static int
00362 loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
00363 {
00364 const char *s = (const char *)v;
00365 struct loaded_feature_searching *fp = (struct loaded_feature_searching *)f;
00366 VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len,
00367 fp->type, fp->load_path);
00368 if (!p) return ST_CONTINUE;
00369 fp->result = s;
00370 return ST_STOP;
00371 }
00372
00373 static int
00374 rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn)
00375 {
00376 VALUE features, this_feature_index = Qnil, v, p, load_path = 0;
00377 const char *f, *e;
00378 long i, len, elen, n;
00379 st_table *loading_tbl, *features_index;
00380 st_data_t data;
00381 int type;
00382
00383 if (fn) *fn = 0;
00384 if (ext) {
00385 elen = strlen(ext);
00386 len = strlen(feature) - elen;
00387 type = rb ? 'r' : 's';
00388 }
00389 else {
00390 len = strlen(feature);
00391 elen = 0;
00392 type = 0;
00393 }
00394 features = get_loaded_features();
00395 features_index = get_loaded_features_index();
00396
00397 st_lookup(features_index, (st_data_t)feature, (st_data_t *)&this_feature_index);
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424 for (i = 0; !NIL_P(this_feature_index); i++) {
00425 VALUE entry;
00426 long index;
00427 if (RB_TYPE_P(this_feature_index, T_ARRAY)) {
00428 if (i >= RARRAY_LEN(this_feature_index)) break;
00429 entry = RARRAY_PTR(this_feature_index)[i];
00430 }
00431 else {
00432 if (i > 0) break;
00433 entry = this_feature_index;
00434 }
00435 index = FIX2LONG(entry);
00436
00437 v = RARRAY_PTR(features)[index];
00438 f = StringValuePtr(v);
00439 if ((n = RSTRING_LEN(v)) < len) continue;
00440 if (strncmp(f, feature, len) != 0) {
00441 if (expanded) continue;
00442 if (!load_path) load_path = rb_get_expanded_load_path();
00443 if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
00444 continue;
00445 expanded = 1;
00446 f += RSTRING_LEN(p) + 1;
00447 }
00448 if (!*(e = f + len)) {
00449 if (ext) continue;
00450 return 'u';
00451 }
00452 if (*e != '.') continue;
00453 if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
00454 return 's';
00455 }
00456 if ((rb || !ext) && (IS_RBEXT(e))) {
00457 return 'r';
00458 }
00459 }
00460
00461 loading_tbl = get_loading_table();
00462 if (loading_tbl) {
00463 f = 0;
00464 if (!expanded) {
00465 struct loaded_feature_searching fs;
00466 fs.name = feature;
00467 fs.len = len;
00468 fs.type = type;
00469 fs.load_path = load_path ? load_path : rb_get_expanded_load_path();
00470 fs.result = 0;
00471 st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
00472 if ((f = fs.result) != 0) {
00473 if (fn) *fn = f;
00474 goto loading;
00475 }
00476 }
00477 if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
00478 if (fn) *fn = (const char*)data;
00479 loading:
00480 if (!ext) return 'u';
00481 return !IS_RBEXT(ext) ? 's' : 'r';
00482 }
00483 else {
00484 VALUE bufstr;
00485 char *buf;
00486 static const char so_ext[][4] = {
00487 ".so", ".o",
00488 };
00489
00490 if (ext && *ext) return 0;
00491 bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN);
00492 buf = RSTRING_PTR(bufstr);
00493 MEMCPY(buf, feature, char, len);
00494 for (i = 0; (e = loadable_ext[i]) != 0; i++) {
00495 strlcpy(buf + len, e, DLEXT_MAXLEN + 1);
00496 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
00497 rb_str_resize(bufstr, 0);
00498 if (fn) *fn = (const char*)data;
00499 return i ? 's' : 'r';
00500 }
00501 }
00502 for (i = 0; i < numberof(so_ext); i++) {
00503 strlcpy(buf + len, so_ext[i], DLEXT_MAXLEN + 1);
00504 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
00505 rb_str_resize(bufstr, 0);
00506 if (fn) *fn = (const char*)data;
00507 return 's';
00508 }
00509 }
00510 rb_str_resize(bufstr, 0);
00511 }
00512 }
00513 return 0;
00514 }
00515
00516 int
00517 rb_provided(const char *feature)
00518 {
00519 return rb_feature_provided(feature, 0);
00520 }
00521
00522 int
00523 rb_feature_provided(const char *feature, const char **loading)
00524 {
00525 const char *ext = strrchr(feature, '.');
00526 volatile VALUE fullpath = 0;
00527
00528 if (*feature == '.' &&
00529 (feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) {
00530 fullpath = rb_file_expand_path_fast(rb_get_path(rb_str_new2(feature)), Qnil);
00531 feature = RSTRING_PTR(fullpath);
00532 }
00533 if (ext && !strchr(ext, '/')) {
00534 if (IS_RBEXT(ext)) {
00535 if (rb_feature_p(feature, ext, TRUE, FALSE, loading)) return TRUE;
00536 return FALSE;
00537 }
00538 else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
00539 if (rb_feature_p(feature, ext, FALSE, FALSE, loading)) return TRUE;
00540 return FALSE;
00541 }
00542 }
00543 if (rb_feature_p(feature, 0, TRUE, FALSE, loading))
00544 return TRUE;
00545 return FALSE;
00546 }
00547
00548 static void
00549 rb_provide_feature(VALUE feature)
00550 {
00551 VALUE features;
00552
00553 features = get_loaded_features();
00554 if (OBJ_FROZEN(features)) {
00555 rb_raise(rb_eRuntimeError,
00556 "$LOADED_FEATURES is frozen; cannot append feature");
00557 }
00558 rb_str_freeze(feature);
00559
00560 rb_ary_push(features, feature);
00561 features_index_add(feature, INT2FIX(RARRAY_LEN(features)-1));
00562 reset_loaded_features_snapshot();
00563 }
00564
00565 void
00566 rb_provide(const char *feature)
00567 {
00568 rb_provide_feature(rb_usascii_str_new2(feature));
00569 }
00570
00571 NORETURN(static void load_failed(VALUE));
00572
00573 static void
00574 rb_load_internal(VALUE fname, int wrap)
00575 {
00576 int state;
00577 rb_thread_t *th = GET_THREAD();
00578 volatile VALUE wrapper = th->top_wrapper;
00579 volatile VALUE self = th->top_self;
00580 volatile int loaded = FALSE;
00581 volatile int mild_compile_error;
00582 #ifndef __GNUC__
00583 rb_thread_t *volatile th0 = th;
00584 #endif
00585
00586 th->errinfo = Qnil;
00587
00588 if (!wrap) {
00589 rb_secure(4);
00590 th->top_wrapper = 0;
00591 }
00592 else {
00593
00594 th->top_self = rb_obj_clone(rb_vm_top_self());
00595 th->top_wrapper = rb_module_new();
00596 rb_extend_object(th->top_self, th->top_wrapper);
00597 }
00598
00599 mild_compile_error = th->mild_compile_error;
00600 PUSH_TAG();
00601 state = EXEC_TAG();
00602 if (state == 0) {
00603 NODE *node;
00604 VALUE iseq;
00605
00606 th->mild_compile_error++;
00607 node = (NODE *)rb_load_file(RSTRING_PTR(fname));
00608 loaded = TRUE;
00609 iseq = rb_iseq_new_top(node, rb_str_new2("<top (required)>"), fname, rb_realpath_internal(Qnil, fname, 1), Qfalse);
00610 th->mild_compile_error--;
00611 rb_iseq_eval(iseq);
00612 }
00613 POP_TAG();
00614
00615 #ifndef __GNUC__
00616 th = th0;
00617 fname = RB_GC_GUARD(fname);
00618 #endif
00619 th->mild_compile_error = mild_compile_error;
00620 th->top_self = self;
00621 th->top_wrapper = wrapper;
00622
00623 if (!loaded && !FIXNUM_P(GET_THREAD()->errinfo)) {
00624
00625 rb_exc_raise(GET_THREAD()->errinfo);
00626 }
00627 if (state) {
00628 rb_vm_jump_tag_but_local_jump(state);
00629 }
00630
00631 if (!NIL_P(GET_THREAD()->errinfo)) {
00632
00633 rb_exc_raise(th->errinfo);
00634 }
00635 }
00636
00637 void
00638 rb_load(VALUE fname, int wrap)
00639 {
00640 VALUE tmp = rb_find_file(FilePathValue(fname));
00641 if (!tmp) load_failed(fname);
00642 rb_load_internal(tmp, wrap);
00643 }
00644
00645 void
00646 rb_load_protect(VALUE fname, int wrap, int *state)
00647 {
00648 int status;
00649
00650 PUSH_TAG();
00651 if ((status = EXEC_TAG()) == 0) {
00652 rb_load(fname, wrap);
00653 }
00654 POP_TAG();
00655 if (state)
00656 *state = status;
00657 }
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673 static VALUE
00674 rb_f_load(int argc, VALUE *argv)
00675 {
00676 VALUE fname, wrap, path;
00677
00678 rb_scan_args(argc, argv, "11", &fname, &wrap);
00679
00680 if (RUBY_DTRACE_LOAD_ENTRY_ENABLED()) {
00681 RUBY_DTRACE_LOAD_ENTRY(StringValuePtr(fname),
00682 rb_sourcefile(),
00683 rb_sourceline());
00684 }
00685
00686 path = rb_find_file(FilePathValue(fname));
00687 if (!path) {
00688 if (!rb_file_load_ok(RSTRING_PTR(fname)))
00689 load_failed(fname);
00690 path = fname;
00691 }
00692 rb_load_internal(path, RTEST(wrap));
00693
00694 if (RUBY_DTRACE_LOAD_RETURN_ENABLED()) {
00695 RUBY_DTRACE_LOAD_RETURN(StringValuePtr(fname),
00696 rb_sourcefile(),
00697 rb_sourceline());
00698 }
00699
00700 return Qtrue;
00701 }
00702
00703 static char *
00704 load_lock(const char *ftptr)
00705 {
00706 st_data_t data;
00707 st_table *loading_tbl = get_loading_table();
00708
00709 if (!loading_tbl || !st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
00710
00711 if (!loading_tbl) {
00712 GET_VM()->loading_table = loading_tbl = st_init_strtable();
00713 }
00714
00715 ftptr = ruby_strdup(ftptr);
00716 data = (st_data_t)rb_thread_shield_new();
00717 st_insert(loading_tbl, (st_data_t)ftptr, data);
00718 return (char *)ftptr;
00719 }
00720 else if (RB_TYPE_P((VALUE)data, T_NODE) && nd_type((VALUE)data) == NODE_MEMO) {
00721 NODE *memo = RNODE(data);
00722 void (*init)(void) = (void (*)(void))memo->nd_cfnc;
00723 data = (st_data_t)rb_thread_shield_new();
00724 st_insert(loading_tbl, (st_data_t)ftptr, data);
00725 (*init)();
00726 return (char *)"";
00727 }
00728 if (RTEST(ruby_verbose)) {
00729 rb_warning("loading in progress, circular require considered harmful - %s", ftptr);
00730
00731 rb_backtrace();
00732 }
00733 switch (rb_thread_shield_wait((VALUE)data)) {
00734 case Qfalse:
00735 data = (st_data_t)ftptr;
00736 st_insert(loading_tbl, data, (st_data_t)rb_thread_shield_new());
00737 return 0;
00738 case Qnil:
00739 return 0;
00740 }
00741 return (char *)ftptr;
00742 }
00743
00744 static int
00745 release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing)
00746 {
00747 VALUE thread_shield = (VALUE)*value;
00748 if (!existing) return ST_STOP;
00749 if (done ? rb_thread_shield_destroy(thread_shield) : rb_thread_shield_release(thread_shield)) {
00750
00751 return ST_CONTINUE;
00752 }
00753 xfree((char *)*key);
00754 return ST_DELETE;
00755 }
00756
00757 static void
00758 load_unlock(const char *ftptr, int done)
00759 {
00760 if (ftptr) {
00761 st_data_t key = (st_data_t)ftptr;
00762 st_table *loading_tbl = get_loading_table();
00763
00764 st_update(loading_tbl, key, release_thread_shield, done);
00765 }
00766 }
00767
00768
00769
00770
00771
00772
00773
00774
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803
00804
00805 VALUE
00806 rb_f_require(VALUE obj, VALUE fname)
00807 {
00808 return rb_require_safe(fname, rb_safe_level());
00809 }
00810
00811
00812
00813
00814
00815
00816
00817
00818
00819 VALUE
00820 rb_f_require_relative(VALUE obj, VALUE fname)
00821 {
00822 VALUE base = rb_current_realfilepath();
00823 if (NIL_P(base)) {
00824 rb_loaderror("cannot infer basepath");
00825 }
00826 base = rb_file_dirname(base);
00827 return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
00828 }
00829
00830 static int
00831 search_required(VALUE fname, volatile VALUE *path, int safe_level)
00832 {
00833 VALUE tmp;
00834 char *ext, *ftptr;
00835 int type, ft = 0;
00836 const char *loading;
00837
00838 *path = 0;
00839 ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
00840 if (ext && !strchr(ext, '/')) {
00841 if (IS_RBEXT(ext)) {
00842 if (rb_feature_p(ftptr, ext, TRUE, FALSE, &loading)) {
00843 if (loading) *path = rb_filesystem_str_new_cstr(loading);
00844 return 'r';
00845 }
00846 if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) {
00847 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
00848 if (!rb_feature_p(ftptr, ext, TRUE, TRUE, &loading) || loading)
00849 *path = tmp;
00850 return 'r';
00851 }
00852 return 0;
00853 }
00854 else if (IS_SOEXT(ext)) {
00855 if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) {
00856 if (loading) *path = rb_filesystem_str_new_cstr(loading);
00857 return 's';
00858 }
00859 tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
00860 #ifdef DLEXT2
00861 OBJ_FREEZE(tmp);
00862 if (rb_find_file_ext_safe(&tmp, loadable_ext + 1, safe_level)) {
00863 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
00864 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
00865 *path = tmp;
00866 return 's';
00867 }
00868 #else
00869 rb_str_cat2(tmp, DLEXT);
00870 OBJ_FREEZE(tmp);
00871 if ((tmp = rb_find_file_safe(tmp, safe_level)) != 0) {
00872 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
00873 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
00874 *path = tmp;
00875 return 's';
00876 }
00877 #endif
00878 }
00879 else if (IS_DLEXT(ext)) {
00880 if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) {
00881 if (loading) *path = rb_filesystem_str_new_cstr(loading);
00882 return 's';
00883 }
00884 if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) {
00885 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
00886 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
00887 *path = tmp;
00888 return 's';
00889 }
00890 }
00891 }
00892 else if ((ft = rb_feature_p(ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
00893 if (loading) *path = rb_filesystem_str_new_cstr(loading);
00894 return 'r';
00895 }
00896 tmp = fname;
00897 type = rb_find_file_ext_safe(&tmp, loadable_ext, safe_level);
00898 switch (type) {
00899 case 0:
00900 if (ft)
00901 goto statically_linked;
00902 ftptr = RSTRING_PTR(tmp);
00903 return rb_feature_p(ftptr, 0, FALSE, TRUE, 0);
00904
00905 default:
00906 if (ft) {
00907 statically_linked:
00908 if (loading) *path = rb_filesystem_str_new_cstr(loading);
00909 return ft;
00910 }
00911 case 1:
00912 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
00913 if (rb_feature_p(ftptr, ext, !--type, TRUE, &loading) && !loading)
00914 break;
00915 *path = tmp;
00916 }
00917 return type ? 's' : 'r';
00918 }
00919
00920 static void
00921 load_failed(VALUE fname)
00922 {
00923 rb_load_fail(fname, "cannot load such file");
00924 }
00925
00926 static VALUE
00927 load_ext(VALUE path)
00928 {
00929 SCOPE_SET(NOEX_PUBLIC);
00930 return (VALUE)dln_load(RSTRING_PTR(path));
00931 }
00932
00933 VALUE
00934 rb_require_safe(VALUE fname, int safe)
00935 {
00936 volatile VALUE result = Qnil;
00937 rb_thread_t *th = GET_THREAD();
00938 volatile VALUE errinfo = th->errinfo;
00939 int state;
00940 struct {
00941 int safe;
00942 } volatile saved;
00943 char *volatile ftptr = 0;
00944
00945 if (RUBY_DTRACE_REQUIRE_ENTRY_ENABLED()) {
00946 RUBY_DTRACE_REQUIRE_ENTRY(StringValuePtr(fname),
00947 rb_sourcefile(),
00948 rb_sourceline());
00949 }
00950
00951 PUSH_TAG();
00952 saved.safe = rb_safe_level();
00953 if ((state = EXEC_TAG()) == 0) {
00954 VALUE path;
00955 long handle;
00956 int found;
00957
00958 rb_set_safe_level_force(safe);
00959 FilePathValue(fname);
00960 rb_set_safe_level_force(0);
00961
00962 if (RUBY_DTRACE_FIND_REQUIRE_ENTRY_ENABLED()) {
00963 RUBY_DTRACE_FIND_REQUIRE_ENTRY(StringValuePtr(fname),
00964 rb_sourcefile(),
00965 rb_sourceline());
00966 }
00967
00968 found = search_required(fname, &path, safe);
00969
00970 if (RUBY_DTRACE_FIND_REQUIRE_RETURN_ENABLED()) {
00971 RUBY_DTRACE_FIND_REQUIRE_RETURN(StringValuePtr(fname),
00972 rb_sourcefile(),
00973 rb_sourceline());
00974 }
00975 if (found) {
00976 if (!path || !(ftptr = load_lock(RSTRING_PTR(path)))) {
00977 result = Qfalse;
00978 }
00979 else if (!*ftptr) {
00980 rb_provide_feature(path);
00981 result = Qtrue;
00982 }
00983 else {
00984 switch (found) {
00985 case 'r':
00986 rb_load_internal(path, 0);
00987 break;
00988
00989 case 's':
00990 handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
00991 path, 0, path);
00992 rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
00993 break;
00994 }
00995 rb_provide_feature(path);
00996 result = Qtrue;
00997 }
00998 }
00999 }
01000 POP_TAG();
01001 load_unlock(ftptr, !state);
01002
01003 rb_set_safe_level_force(saved.safe);
01004 if (state) {
01005 JUMP_TAG(state);
01006 }
01007
01008 if (NIL_P(result)) {
01009 load_failed(fname);
01010 }
01011
01012 th->errinfo = errinfo;
01013
01014 if (RUBY_DTRACE_REQUIRE_RETURN_ENABLED()) {
01015 RUBY_DTRACE_REQUIRE_RETURN(StringValuePtr(fname),
01016 rb_sourcefile(),
01017 rb_sourceline());
01018 }
01019
01020 return result;
01021 }
01022
01023 VALUE
01024 rb_require(const char *fname)
01025 {
01026 VALUE fn = rb_str_new2(fname);
01027 OBJ_FREEZE(fn);
01028 return rb_require_safe(fn, rb_safe_level());
01029 }
01030
01031 static int
01032 register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
01033 {
01034 const char *name = (char *)*key;
01035 if (existing) {
01036
01037 rb_warn("%s is already registered", name);
01038 }
01039 else {
01040 *value = (st_data_t)NEW_MEMO(init, 0, 0);
01041 *key = (st_data_t)ruby_strdup(name);
01042 }
01043 return ST_CONTINUE;
01044 }
01045
01046 RUBY_FUNC_EXPORTED void
01047 ruby_init_ext(const char *name, void (*init)(void))
01048 {
01049 st_table *loading_tbl = get_loading_table();
01050
01051 if (!loading_tbl) {
01052 GET_VM()->loading_table = loading_tbl = st_init_strtable();
01053 }
01054 st_update(loading_tbl, (st_data_t)name, register_init_ext, (st_data_t)init);
01055 }
01056
01057
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071 static VALUE
01072 rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
01073 {
01074 ID id = rb_to_id(sym);
01075
01076 FilePathValue(file);
01077 rb_autoload(mod, id, RSTRING_PTR(file));
01078 return Qnil;
01079 }
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094 static VALUE
01095 rb_mod_autoload_p(VALUE mod, VALUE sym)
01096 {
01097 ID id = rb_check_id(&sym);
01098 if (!id) {
01099 return Qnil;
01100 }
01101 return rb_autoload_p(mod, id);
01102 }
01103
01104
01105
01106
01107
01108
01109
01110
01111
01112
01113
01114
01115 static VALUE
01116 rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
01117 {
01118 VALUE klass = rb_class_real(rb_vm_cbase());
01119 if (NIL_P(klass)) {
01120 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
01121 }
01122 return rb_mod_autoload(klass, sym, file);
01123 }
01124
01125
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136 static VALUE
01137 rb_f_autoload_p(VALUE obj, VALUE sym)
01138 {
01139
01140 VALUE klass = rb_vm_cbase();
01141 if (NIL_P(klass)) {
01142 return Qnil;
01143 }
01144 return rb_mod_autoload_p(klass, sym);
01145 }
01146
01147 void
01148 Init_load()
01149 {
01150 #undef rb_intern
01151 #define rb_intern(str) rb_intern2((str), strlen(str))
01152 rb_vm_t *vm = GET_VM();
01153 static const char var_load_path[] = "$:";
01154 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
01155
01156 rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
01157 rb_alias_variable(rb_intern("$-I"), id_load_path);
01158 rb_alias_variable(rb_intern("$LOAD_PATH"), id_load_path);
01159 vm->load_path = rb_ary_new();
01160 vm->expanded_load_path = rb_ary_tmp_new(0);
01161 vm->load_path_snapshot = rb_ary_tmp_new(0);
01162 vm->load_path_check_cache = 0;
01163
01164 rb_define_virtual_variable("$\"", get_loaded_features, 0);
01165 rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
01166 vm->loaded_features = rb_ary_new();
01167 vm->loaded_features_snapshot = rb_ary_tmp_new(0);
01168 vm->loaded_features_index = st_init_strtable();
01169
01170 rb_define_global_function("load", rb_f_load, -1);
01171 rb_define_global_function("require", rb_f_require, 1);
01172 rb_define_global_function("require_relative", rb_f_require_relative, 1);
01173 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
01174 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, 1);
01175 rb_define_global_function("autoload", rb_f_autoload, 2);
01176 rb_define_global_function("autoload?", rb_f_autoload_p, 1);
01177
01178 ruby_dln_librefs = rb_ary_tmp_new(0);
01179 rb_gc_register_mark_object(ruby_dln_librefs);
01180 }
01181