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