Ruby
2.0.0p247(2013-06-27revision41674)
|
00001 /* 00002 * load methods from eval.c 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 00012 VALUE ruby_dln_librefs; 00013 00014 #define numberof(array) (int)(sizeof(array) / sizeof((array)[0])) 00015 00016 #define IS_RBEXT(e) (strcmp((e), ".rb") == 0) 00017 #define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0) 00018 #ifdef DLEXT2 00019 #define IS_DLEXT(e) (strcmp((e), DLEXT) == 0 || strcmp((e), DLEXT2) == 0) 00020 #else 00021 #define IS_DLEXT(e) (strcmp((e), DLEXT) == 0) 00022 #endif 00023 00024 static const char *const loadable_ext[] = { 00025 ".rb", DLEXT, 00026 #ifdef DLEXT2 00027 DLEXT2, 00028 #endif 00029 0 00030 }; 00031 00032 VALUE 00033 rb_get_load_path(void) 00034 { 00035 VALUE load_path = GET_VM()->load_path; 00036 return load_path; 00037 } 00038 00039 enum expand_type { 00040 EXPAND_ALL, 00041 EXPAND_RELATIVE, 00042 EXPAND_HOME, 00043 EXPAND_NON_CACHE 00044 }; 00045 00046 /* Construct expanded load path and store it to cache. 00047 We rebuild load path partially if the cache is invalid. 00048 We don't cache non string object and expand it every time. We ensure that 00049 string objects in $LOAD_PATH are frozen. 00050 */ 00051 static void 00052 rb_construct_expanded_load_path(int type, int *has_relative, int *has_non_cache) 00053 { 00054 rb_vm_t *vm = GET_VM(); 00055 VALUE load_path = vm->load_path; 00056 VALUE expanded_load_path = vm->expanded_load_path; 00057 VALUE ary; 00058 long i; 00059 int level = rb_safe_level(); 00060 00061 ary = rb_ary_tmp_new(RARRAY_LEN(load_path)); 00062 for (i = 0; i < RARRAY_LEN(load_path); ++i) { 00063 VALUE path, as_str, expanded_path; 00064 int is_string, non_cache; 00065 char *as_cstr; 00066 as_str = path = RARRAY_PTR(load_path)[i]; 00067 is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0; 00068 non_cache = !is_string ? 1 : 0; 00069 as_str = rb_get_path_check_to_string(path, level); 00070 as_cstr = RSTRING_PTR(as_str); 00071 00072 if (!non_cache) { 00073 if ((type == EXPAND_RELATIVE && 00074 rb_is_absolute_path(as_cstr)) || 00075 (type == EXPAND_HOME && 00076 (!as_cstr[0] || as_cstr[0] != '~')) || 00077 (type == EXPAND_NON_CACHE)) { 00078 /* Use cached expanded path. */ 00079 rb_ary_push(ary, RARRAY_PTR(expanded_load_path)[i]); 00080 continue; 00081 } 00082 } 00083 if (!*has_relative && !rb_is_absolute_path(as_cstr)) 00084 *has_relative = 1; 00085 if (!*has_non_cache && non_cache) 00086 *has_non_cache = 1; 00087 /* Freeze only string object. We expand other objects every time. */ 00088 if (is_string) 00089 rb_str_freeze(path); 00090 as_str = rb_get_path_check_convert(path, as_str, level); 00091 expanded_path = rb_file_expand_path_fast(as_str, Qnil); 00092 rb_str_freeze(expanded_path); 00093 rb_ary_push(ary, expanded_path); 00094 } 00095 rb_obj_freeze(ary); 00096 vm->expanded_load_path = ary; 00097 rb_ary_replace(vm->load_path_snapshot, vm->load_path); 00098 } 00099 00100 static VALUE 00101 load_path_getcwd(void) 00102 { 00103 char *cwd = my_getcwd(); 00104 VALUE cwd_str = rb_filesystem_str_new_cstr(cwd); 00105 xfree(cwd); 00106 return cwd_str; 00107 } 00108 00109 VALUE 00110 rb_get_expanded_load_path(void) 00111 { 00112 rb_vm_t *vm = GET_VM(); 00113 const VALUE non_cache = Qtrue; 00114 00115 if (!rb_ary_shared_with_p(vm->load_path_snapshot, vm->load_path)) { 00116 /* The load path was modified. Rebuild the expanded load path. */ 00117 int has_relative = 0, has_non_cache = 0; 00118 rb_construct_expanded_load_path(EXPAND_ALL, &has_relative, &has_non_cache); 00119 if (has_relative) { 00120 vm->load_path_check_cache = load_path_getcwd(); 00121 } 00122 else if (has_non_cache) { 00123 /* Non string object. */ 00124 vm->load_path_check_cache = non_cache; 00125 } 00126 else { 00127 vm->load_path_check_cache = 0; 00128 } 00129 } 00130 else if (vm->load_path_check_cache == non_cache) { 00131 int has_relative = 1, has_non_cache = 1; 00132 /* Expand only non-cacheable objects. */ 00133 rb_construct_expanded_load_path(EXPAND_NON_CACHE, 00134 &has_relative, &has_non_cache); 00135 } 00136 else if (vm->load_path_check_cache) { 00137 int has_relative = 1, has_non_cache = 1; 00138 VALUE cwd = load_path_getcwd(); 00139 if (!rb_str_equal(vm->load_path_check_cache, cwd)) { 00140 /* Current working directory or filesystem encoding was changed. 00141 Expand relative load path and non-cacheable objects again. */ 00142 vm->load_path_check_cache = cwd; 00143 rb_construct_expanded_load_path(EXPAND_RELATIVE, 00144 &has_relative, &has_non_cache); 00145 } 00146 else { 00147 /* Expand only tilde (User HOME) and non-cacheable objects. */ 00148 rb_construct_expanded_load_path(EXPAND_HOME, 00149 &has_relative, &has_non_cache); 00150 } 00151 } 00152 return vm->expanded_load_path; 00153 } 00154 00155 static VALUE 00156 load_path_getter(ID id, rb_vm_t *vm) 00157 { 00158 return vm->load_path; 00159 } 00160 00161 static VALUE 00162 get_loaded_features(void) 00163 { 00164 return GET_VM()->loaded_features; 00165 } 00166 00167 static void 00168 reset_loaded_features_snapshot(void) 00169 { 00170 rb_vm_t *vm = GET_VM(); 00171 rb_ary_replace(vm->loaded_features_snapshot, vm->loaded_features); 00172 } 00173 00174 static struct st_table * 00175 get_loaded_features_index_raw(void) 00176 { 00177 return GET_VM()->loaded_features_index; 00178 } 00179 00180 static st_table * 00181 get_loading_table(void) 00182 { 00183 return GET_VM()->loading_table; 00184 } 00185 00186 static void 00187 features_index_add_single(VALUE short_feature, VALUE offset) 00188 { 00189 struct st_table *features_index; 00190 VALUE this_feature_index = Qnil; 00191 char *short_feature_cstr; 00192 00193 Check_Type(offset, T_FIXNUM); 00194 Check_Type(short_feature, T_STRING); 00195 short_feature_cstr = StringValueCStr(short_feature); 00196 00197 features_index = get_loaded_features_index_raw(); 00198 st_lookup(features_index, (st_data_t)short_feature_cstr, (st_data_t *)&this_feature_index); 00199 00200 if (NIL_P(this_feature_index)) { 00201 st_insert(features_index, (st_data_t)ruby_strdup(short_feature_cstr), (st_data_t)offset); 00202 } 00203 else if (RB_TYPE_P(this_feature_index, T_FIXNUM)) { 00204 VALUE feature_indexes[2]; 00205 feature_indexes[0] = this_feature_index; 00206 feature_indexes[1] = offset; 00207 this_feature_index = rb_ary_tmp_new(numberof(feature_indexes)); 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 /* Add to the loaded-features index all the required entries for 00218 `feature`, located at `offset` in $LOADED_FEATURES. We add an 00219 index entry at each string `short_feature` for which 00220 feature == "#{prefix}#{short_feature}#{e}" 00221 where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty 00222 or ends in '/'. This maintains the invariant that `rb_feature_p()` 00223 relies on for its fast lookup. 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 /* Now `ext` points to the only string matching %r{^\.[^./]*$} that is 00240 at the end of `feature`, or is NULL if there is no such string. */ 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 /* Now *p == '/'. We reach this point for every '/' in `feature`. */ 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 xfree((char *)key); 00268 return ST_DELETE; 00269 } 00270 00271 static st_table * 00272 get_loaded_features_index(void) 00273 { 00274 VALUE features; 00275 int i; 00276 rb_vm_t *vm = GET_VM(); 00277 00278 if (!rb_ary_shared_with_p(vm->loaded_features_snapshot, vm->loaded_features)) { 00279 /* The sharing was broken; something (other than us in rb_provide_feature()) 00280 modified loaded_features. Rebuild the index. */ 00281 st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0); 00282 features = vm->loaded_features; 00283 for (i = 0; i < RARRAY_LEN(features); i++) { 00284 VALUE entry, as_str; 00285 as_str = entry = rb_ary_entry(features, i); 00286 StringValue(as_str); 00287 if (as_str != entry) 00288 rb_ary_store(features, i, as_str); 00289 rb_str_freeze(as_str); 00290 features_index_add(as_str, INT2FIX(i)); 00291 } 00292 reset_loaded_features_snapshot(); 00293 } 00294 return vm->loaded_features_index; 00295 } 00296 00297 /* This searches `load_path` for a value such that 00298 name == "#{load_path[i]}/#{feature}" 00299 if `feature` is a suffix of `name`, or otherwise 00300 name == "#{load_path[i]}/#{feature}#{ext}" 00301 for an acceptable string `ext`. It returns 00302 `load_path[i].to_str` if found, else 0. 00303 00304 If type is 's', then `ext` is acceptable only if IS_DLEXT(ext); 00305 if 'r', then only if IS_RBEXT(ext); otherwise `ext` may be absent 00306 or have any value matching `%r{^\.[^./]*$}`. 00307 */ 00308 static VALUE 00309 loaded_feature_path(const char *name, long vlen, const char *feature, long len, 00310 int type, VALUE load_path) 00311 { 00312 long i; 00313 long plen; 00314 const char *e; 00315 00316 if (vlen < len+1) return 0; 00317 if (!strncmp(name+(vlen-len), feature, len)) { 00318 plen = vlen - len; 00319 } 00320 else { 00321 for (e = name + vlen; name != e && *e != '.' && *e != '/'; --e); 00322 if (*e != '.' || 00323 e-name < len || 00324 strncmp(e-len, feature, len)) 00325 return 0; 00326 plen = e - name - len; 00327 } 00328 if (plen > 0 && name[plen-1] != '/') { 00329 return 0; 00330 } 00331 if (type == 's' ? !IS_DLEXT(&name[plen+len]) : 00332 type == 'r' ? !IS_RBEXT(&name[plen+len]) : 00333 0) { 00334 return 0; 00335 } 00336 /* Now name == "#{prefix}/#{feature}#{ext}" where ext is acceptable 00337 (possibly empty) and prefix is some string of length plen. */ 00338 00339 if (plen > 0) --plen; /* exclude '.' */ 00340 for (i = 0; i < RARRAY_LEN(load_path); ++i) { 00341 VALUE p = RARRAY_PTR(load_path)[i]; 00342 const char *s = StringValuePtr(p); 00343 long n = RSTRING_LEN(p); 00344 00345 if (n != plen) continue; 00346 if (n && strncmp(name, s, n)) continue; 00347 return p; 00348 } 00349 return 0; 00350 } 00351 00352 struct loaded_feature_searching { 00353 const char *name; 00354 long len; 00355 int type; 00356 VALUE load_path; 00357 const char *result; 00358 }; 00359 00360 static int 00361 loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f) 00362 { 00363 const char *s = (const char *)v; 00364 struct loaded_feature_searching *fp = (struct loaded_feature_searching *)f; 00365 VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len, 00366 fp->type, fp->load_path); 00367 if (!p) return ST_CONTINUE; 00368 fp->result = s; 00369 return ST_STOP; 00370 } 00371 00372 static int 00373 rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn) 00374 { 00375 VALUE features, this_feature_index = Qnil, v, p, load_path = 0; 00376 const char *f, *e; 00377 long i, len, elen, n; 00378 st_table *loading_tbl, *features_index; 00379 st_data_t data; 00380 int type; 00381 00382 if (fn) *fn = 0; 00383 if (ext) { 00384 elen = strlen(ext); 00385 len = strlen(feature) - elen; 00386 type = rb ? 'r' : 's'; 00387 } 00388 else { 00389 len = strlen(feature); 00390 elen = 0; 00391 type = 0; 00392 } 00393 features = get_loaded_features(); 00394 features_index = get_loaded_features_index(); 00395 00396 st_lookup(features_index, (st_data_t)feature, (st_data_t *)&this_feature_index); 00397 /* We search `features` for an entry such that either 00398 "#{features[i]}" == "#{load_path[j]}/#{feature}#{e}" 00399 for some j, or 00400 "#{features[i]}" == "#{feature}#{e}" 00401 Here `e` is an "allowed" extension -- either empty or one 00402 of the extensions accepted by IS_RBEXT, IS_SOEXT, or 00403 IS_DLEXT. Further, if `ext && rb` then `IS_RBEXT(e)`, 00404 and if `ext && !rb` then `IS_SOEXT(e) || IS_DLEXT(e)`. 00405 00406 If `expanded`, then only the latter form (without load_path[j]) 00407 is accepted. Otherwise either form is accepted, *unless* `ext` 00408 is false and an otherwise-matching entry of the first form is 00409 preceded by an entry of the form 00410 "#{features[i2]}" == "#{load_path[j2]}/#{feature}#{e2}" 00411 where `e2` matches %r{^\.[^./]*$} but is not an allowed extension. 00412 After a "distractor" entry of this form, only entries of the 00413 form "#{feature}#{e}" are accepted. 00414 00415 In `rb_provide_feature()` and `get_loaded_features_index()` we 00416 maintain an invariant that the array `this_feature_index` will 00417 point to every entry in `features` which has the form 00418 "#{prefix}#{feature}#{e}" 00419 where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty 00420 or ends in '/'. This includes both match forms above, as well 00421 as any distractors, so we may ignore all other entries in `features`. 00422 */ 00423 for (i = 0; !NIL_P(this_feature_index); i++) { 00424 VALUE entry; 00425 long index; 00426 if (RB_TYPE_P(this_feature_index, T_ARRAY)) { 00427 if (i >= RARRAY_LEN(this_feature_index)) break; 00428 entry = RARRAY_PTR(this_feature_index)[i]; 00429 } 00430 else { 00431 if (i > 0) break; 00432 entry = this_feature_index; 00433 } 00434 index = FIX2LONG(entry); 00435 00436 v = RARRAY_PTR(features)[index]; 00437 f = StringValuePtr(v); 00438 if ((n = RSTRING_LEN(v)) < len) continue; 00439 if (strncmp(f, feature, len) != 0) { 00440 if (expanded) continue; 00441 if (!load_path) load_path = rb_get_expanded_load_path(); 00442 if (!(p = loaded_feature_path(f, n, feature, len, type, load_path))) 00443 continue; 00444 expanded = 1; 00445 f += RSTRING_LEN(p) + 1; 00446 } 00447 if (!*(e = f + len)) { 00448 if (ext) continue; 00449 return 'u'; 00450 } 00451 if (*e != '.') continue; 00452 if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) { 00453 return 's'; 00454 } 00455 if ((rb || !ext) && (IS_RBEXT(e))) { 00456 return 'r'; 00457 } 00458 } 00459 00460 loading_tbl = get_loading_table(); 00461 if (loading_tbl) { 00462 f = 0; 00463 if (!expanded) { 00464 struct loaded_feature_searching fs; 00465 fs.name = feature; 00466 fs.len = len; 00467 fs.type = type; 00468 fs.load_path = load_path ? load_path : rb_get_expanded_load_path(); 00469 fs.result = 0; 00470 st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs); 00471 if ((f = fs.result) != 0) { 00472 if (fn) *fn = f; 00473 goto loading; 00474 } 00475 } 00476 if (st_get_key(loading_tbl, (st_data_t)feature, &data)) { 00477 if (fn) *fn = (const char*)data; 00478 loading: 00479 if (!ext) return 'u'; 00480 return !IS_RBEXT(ext) ? 's' : 'r'; 00481 } 00482 else { 00483 VALUE bufstr; 00484 char *buf; 00485 00486 if (ext && *ext) return 0; 00487 bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN); 00488 buf = RSTRING_PTR(bufstr); 00489 MEMCPY(buf, feature, char, len); 00490 for (i = 0; (e = loadable_ext[i]) != 0; i++) { 00491 strlcpy(buf + len, e, DLEXT_MAXLEN + 1); 00492 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) { 00493 rb_str_resize(bufstr, 0); 00494 if (fn) *fn = (const char*)data; 00495 return i ? 's' : 'r'; 00496 } 00497 } 00498 rb_str_resize(bufstr, 0); 00499 } 00500 } 00501 return 0; 00502 } 00503 00504 int 00505 rb_provided(const char *feature) 00506 { 00507 return rb_feature_provided(feature, 0); 00508 } 00509 00510 int 00511 rb_feature_provided(const char *feature, const char **loading) 00512 { 00513 const char *ext = strrchr(feature, '.'); 00514 volatile VALUE fullpath = 0; 00515 00516 if (*feature == '.' && 00517 (feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) { 00518 fullpath = rb_file_expand_path_fast(rb_get_path(rb_str_new2(feature)), Qnil); 00519 feature = RSTRING_PTR(fullpath); 00520 } 00521 if (ext && !strchr(ext, '/')) { 00522 if (IS_RBEXT(ext)) { 00523 if (rb_feature_p(feature, ext, TRUE, FALSE, loading)) return TRUE; 00524 return FALSE; 00525 } 00526 else if (IS_SOEXT(ext) || IS_DLEXT(ext)) { 00527 if (rb_feature_p(feature, ext, FALSE, FALSE, loading)) return TRUE; 00528 return FALSE; 00529 } 00530 } 00531 if (rb_feature_p(feature, 0, TRUE, FALSE, loading)) 00532 return TRUE; 00533 return FALSE; 00534 } 00535 00536 static void 00537 rb_provide_feature(VALUE feature) 00538 { 00539 VALUE features; 00540 00541 features = get_loaded_features(); 00542 if (OBJ_FROZEN(features)) { 00543 rb_raise(rb_eRuntimeError, 00544 "$LOADED_FEATURES is frozen; cannot append feature"); 00545 } 00546 rb_str_freeze(feature); 00547 00548 rb_ary_push(features, feature); 00549 features_index_add(feature, INT2FIX(RARRAY_LEN(features)-1)); 00550 reset_loaded_features_snapshot(); 00551 } 00552 00553 void 00554 rb_provide(const char *feature) 00555 { 00556 rb_provide_feature(rb_usascii_str_new2(feature)); 00557 } 00558 00559 NORETURN(static void load_failed(VALUE)); 00560 00561 static void 00562 rb_load_internal(VALUE fname, int wrap) 00563 { 00564 int state; 00565 rb_thread_t *th = GET_THREAD(); 00566 volatile VALUE wrapper = th->top_wrapper; 00567 volatile VALUE self = th->top_self; 00568 volatile int loaded = FALSE; 00569 volatile int mild_compile_error; 00570 #ifndef __GNUC__ 00571 rb_thread_t *volatile th0 = th; 00572 #endif 00573 00574 th->errinfo = Qnil; /* ensure */ 00575 00576 if (!wrap) { 00577 rb_secure(4); /* should alter global state */ 00578 th->top_wrapper = 0; 00579 } 00580 else { 00581 /* load in anonymous module as toplevel */ 00582 th->top_self = rb_obj_clone(rb_vm_top_self()); 00583 th->top_wrapper = rb_module_new(); 00584 rb_extend_object(th->top_self, th->top_wrapper); 00585 } 00586 00587 mild_compile_error = th->mild_compile_error; 00588 PUSH_TAG(); 00589 state = EXEC_TAG(); 00590 if (state == 0) { 00591 NODE *node; 00592 VALUE iseq; 00593 00594 th->mild_compile_error++; 00595 node = (NODE *)rb_load_file(RSTRING_PTR(fname)); 00596 loaded = TRUE; 00597 iseq = rb_iseq_new_top(node, rb_str_new2("<top (required)>"), fname, rb_realpath_internal(Qnil, fname, 1), Qfalse); 00598 th->mild_compile_error--; 00599 rb_iseq_eval(iseq); 00600 } 00601 POP_TAG(); 00602 00603 #ifndef __GNUC__ 00604 th = th0; 00605 fname = RB_GC_GUARD(fname); 00606 #endif 00607 th->mild_compile_error = mild_compile_error; 00608 th->top_self = self; 00609 th->top_wrapper = wrapper; 00610 00611 if (!loaded && !FIXNUM_P(GET_THREAD()->errinfo)) { 00612 /* an error on loading don't include INT2FIX(TAG_FATAL) see r35625 */ 00613 rb_exc_raise(GET_THREAD()->errinfo); 00614 } 00615 if (state) { 00616 rb_vm_jump_tag_but_local_jump(state); 00617 } 00618 00619 if (!NIL_P(GET_THREAD()->errinfo)) { 00620 /* exception during load */ 00621 rb_exc_raise(th->errinfo); 00622 } 00623 } 00624 00625 void 00626 rb_load(VALUE fname, int wrap) 00627 { 00628 VALUE tmp = rb_find_file(FilePathValue(fname)); 00629 if (!tmp) load_failed(fname); 00630 rb_load_internal(tmp, wrap); 00631 } 00632 00633 void 00634 rb_load_protect(VALUE fname, int wrap, int *state) 00635 { 00636 int status; 00637 00638 PUSH_TAG(); 00639 if ((status = EXEC_TAG()) == 0) { 00640 rb_load(fname, wrap); 00641 } 00642 POP_TAG(); 00643 if (state) 00644 *state = status; 00645 } 00646 00647 /* 00648 * call-seq: 00649 * load(filename, wrap=false) -> true 00650 * 00651 * Loads and executes the Ruby 00652 * program in the file _filename_. If the filename does not 00653 * resolve to an absolute path, the file is searched for in the library 00654 * directories listed in <code>$:</code>. If the optional _wrap_ 00655 * parameter is +true+, the loaded script will be executed 00656 * under an anonymous module, protecting the calling program's global 00657 * namespace. In no circumstance will any local variables in the loaded 00658 * file be propagated to the loading environment. 00659 */ 00660 00661 static VALUE 00662 rb_f_load(int argc, VALUE *argv) 00663 { 00664 VALUE fname, wrap, path; 00665 00666 rb_scan_args(argc, argv, "11", &fname, &wrap); 00667 00668 if (RUBY_DTRACE_LOAD_ENTRY_ENABLED()) { 00669 RUBY_DTRACE_LOAD_ENTRY(StringValuePtr(fname), 00670 rb_sourcefile(), 00671 rb_sourceline()); 00672 } 00673 00674 path = rb_find_file(FilePathValue(fname)); 00675 if (!path) { 00676 if (!rb_file_load_ok(RSTRING_PTR(fname))) 00677 load_failed(fname); 00678 path = fname; 00679 } 00680 rb_load_internal(path, RTEST(wrap)); 00681 00682 if (RUBY_DTRACE_LOAD_RETURN_ENABLED()) { 00683 RUBY_DTRACE_LOAD_RETURN(StringValuePtr(fname), 00684 rb_sourcefile(), 00685 rb_sourceline()); 00686 } 00687 00688 return Qtrue; 00689 } 00690 00691 static char * 00692 load_lock(const char *ftptr) 00693 { 00694 st_data_t data; 00695 st_table *loading_tbl = get_loading_table(); 00696 00697 if (!loading_tbl || !st_lookup(loading_tbl, (st_data_t)ftptr, &data)) { 00698 /* loading ruby library should be serialized. */ 00699 if (!loading_tbl) { 00700 GET_VM()->loading_table = loading_tbl = st_init_strtable(); 00701 } 00702 /* partial state */ 00703 ftptr = ruby_strdup(ftptr); 00704 data = (st_data_t)rb_thread_shield_new(); 00705 st_insert(loading_tbl, (st_data_t)ftptr, data); 00706 return (char *)ftptr; 00707 } 00708 if (RTEST(ruby_verbose)) { 00709 rb_warning("loading in progress, circular require considered harmful - %s", ftptr); 00710 /* TODO: display to $stderr, not stderr in C */ 00711 rb_backtrace(); 00712 } 00713 switch (rb_thread_shield_wait((VALUE)data)) { 00714 case Qfalse: 00715 data = (st_data_t)ftptr; 00716 st_insert(loading_tbl, data, (st_data_t)rb_thread_shield_new()); 00717 return 0; 00718 case Qnil: 00719 return 0; 00720 } 00721 return (char *)ftptr; 00722 } 00723 00724 static int 00725 release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing) 00726 { 00727 VALUE thread_shield = (VALUE)*value; 00728 if (!existing) return ST_STOP; 00729 if (done ? rb_thread_shield_destroy(thread_shield) : rb_thread_shield_release(thread_shield)) { 00730 /* still in-use */ 00731 return ST_CONTINUE; 00732 } 00733 xfree((char *)*key); 00734 return ST_DELETE; 00735 } 00736 00737 static void 00738 load_unlock(const char *ftptr, int done) 00739 { 00740 if (ftptr) { 00741 st_data_t key = (st_data_t)ftptr; 00742 st_table *loading_tbl = get_loading_table(); 00743 00744 st_update(loading_tbl, key, release_thread_shield, done); 00745 } 00746 } 00747 00748 00749 /* 00750 * call-seq: 00751 * require(name) -> true or false 00752 * 00753 * Loads the given +name+, returning +true+ if successful and +false+ if the 00754 * feature is already loaded. 00755 * 00756 * If the filename does not resolve to an absolute path, it will be searched 00757 * for in the directories listed in <code>$LOAD_PATH</code> (<code>$:</code>). 00758 * 00759 * If the filename has the extension ".rb", it is loaded as a source file; if 00760 * the extension is ".so", ".o", or ".dll", or the default shared library 00761 * extension on the current platform, Ruby loads the shared library as a 00762 * Ruby extension. Otherwise, Ruby tries adding ".rb", ".so", and so on 00763 * to the name until found. If the file named cannot be found, a LoadError 00764 * will be raised. 00765 * 00766 * For Ruby extensions the filename given may use any shared library 00767 * extension. For example, on Linux the socket extension is "socket.so" and 00768 * <code>require 'socket.dll'</code> will load the socket extension. 00769 * 00770 * The absolute path of the loaded file is added to 00771 * <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be 00772 * loaded again if its path already appears in <code>$"</code>. For example, 00773 * <code>require 'a'; require './a'</code> will not load <code>a.rb</code> 00774 * again. 00775 * 00776 * require "my-library.rb" 00777 * require "db-driver" 00778 * 00779 * Any constants or globals within the loaded source file will be available 00780 * in the calling program's global namespace. However, local variables will 00781 * not be propagated to the loading environment. 00782 * 00783 */ 00784 00785 VALUE 00786 rb_f_require(VALUE obj, VALUE fname) 00787 { 00788 return rb_require_safe(fname, rb_safe_level()); 00789 } 00790 00791 /* 00792 * call-seq: 00793 * require_relative(string) -> true or false 00794 * 00795 * Ruby tries to load the library named _string_ relative to the requiring 00796 * file's path. If the file's path cannot be determined a LoadError is raised. 00797 * If a file is loaded +true+ is returned and false otherwise. 00798 */ 00799 VALUE 00800 rb_f_require_relative(VALUE obj, VALUE fname) 00801 { 00802 VALUE base = rb_current_realfilepath(); 00803 if (NIL_P(base)) { 00804 rb_loaderror("cannot infer basepath"); 00805 } 00806 base = rb_file_dirname(base); 00807 return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level()); 00808 } 00809 00810 static int 00811 search_required(VALUE fname, volatile VALUE *path, int safe_level) 00812 { 00813 VALUE tmp; 00814 char *ext, *ftptr; 00815 int type, ft = 0; 00816 const char *loading; 00817 00818 *path = 0; 00819 ext = strrchr(ftptr = RSTRING_PTR(fname), '.'); 00820 if (ext && !strchr(ext, '/')) { 00821 if (IS_RBEXT(ext)) { 00822 if (rb_feature_p(ftptr, ext, TRUE, FALSE, &loading)) { 00823 if (loading) *path = rb_filesystem_str_new_cstr(loading); 00824 return 'r'; 00825 } 00826 if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) { 00827 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); 00828 if (!rb_feature_p(ftptr, ext, TRUE, TRUE, &loading) || loading) 00829 *path = tmp; 00830 return 'r'; 00831 } 00832 return 0; 00833 } 00834 else if (IS_SOEXT(ext)) { 00835 if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) { 00836 if (loading) *path = rb_filesystem_str_new_cstr(loading); 00837 return 's'; 00838 } 00839 tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname)); 00840 #ifdef DLEXT2 00841 OBJ_FREEZE(tmp); 00842 if (rb_find_file_ext_safe(&tmp, loadable_ext + 1, safe_level)) { 00843 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); 00844 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading) 00845 *path = tmp; 00846 return 's'; 00847 } 00848 #else 00849 rb_str_cat2(tmp, DLEXT); 00850 OBJ_FREEZE(tmp); 00851 if ((tmp = rb_find_file_safe(tmp, safe_level)) != 0) { 00852 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); 00853 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading) 00854 *path = tmp; 00855 return 's'; 00856 } 00857 #endif 00858 } 00859 else if (IS_DLEXT(ext)) { 00860 if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) { 00861 if (loading) *path = rb_filesystem_str_new_cstr(loading); 00862 return 's'; 00863 } 00864 if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) { 00865 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); 00866 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading) 00867 *path = tmp; 00868 return 's'; 00869 } 00870 } 00871 } 00872 else if ((ft = rb_feature_p(ftptr, 0, FALSE, FALSE, &loading)) == 'r') { 00873 if (loading) *path = rb_filesystem_str_new_cstr(loading); 00874 return 'r'; 00875 } 00876 tmp = fname; 00877 type = rb_find_file_ext_safe(&tmp, loadable_ext, safe_level); 00878 switch (type) { 00879 case 0: 00880 if (ft) 00881 break; 00882 ftptr = RSTRING_PTR(tmp); 00883 return rb_feature_p(ftptr, 0, FALSE, TRUE, 0); 00884 00885 default: 00886 if (ft) 00887 break; 00888 case 1: 00889 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.'); 00890 if (rb_feature_p(ftptr, ext, !--type, TRUE, &loading) && !loading) 00891 break; 00892 *path = tmp; 00893 } 00894 return type ? 's' : 'r'; 00895 } 00896 00897 static void 00898 load_failed(VALUE fname) 00899 { 00900 rb_load_fail(fname, "cannot load such file"); 00901 } 00902 00903 static VALUE 00904 load_ext(VALUE path) 00905 { 00906 SCOPE_SET(NOEX_PUBLIC); 00907 return (VALUE)dln_load(RSTRING_PTR(path)); 00908 } 00909 00910 VALUE 00911 rb_require_safe(VALUE fname, int safe) 00912 { 00913 volatile VALUE result = Qnil; 00914 rb_thread_t *th = GET_THREAD(); 00915 volatile VALUE errinfo = th->errinfo; 00916 int state; 00917 struct { 00918 int safe; 00919 } volatile saved; 00920 char *volatile ftptr = 0; 00921 00922 if (RUBY_DTRACE_REQUIRE_ENTRY_ENABLED()) { 00923 RUBY_DTRACE_REQUIRE_ENTRY(StringValuePtr(fname), 00924 rb_sourcefile(), 00925 rb_sourceline()); 00926 } 00927 00928 PUSH_TAG(); 00929 saved.safe = rb_safe_level(); 00930 if ((state = EXEC_TAG()) == 0) { 00931 VALUE path; 00932 long handle; 00933 int found; 00934 00935 rb_set_safe_level_force(safe); 00936 FilePathValue(fname); 00937 rb_set_safe_level_force(0); 00938 00939 if (RUBY_DTRACE_FIND_REQUIRE_ENTRY_ENABLED()) { 00940 RUBY_DTRACE_FIND_REQUIRE_ENTRY(StringValuePtr(fname), 00941 rb_sourcefile(), 00942 rb_sourceline()); 00943 } 00944 00945 found = search_required(fname, &path, safe); 00946 00947 if (RUBY_DTRACE_FIND_REQUIRE_RETURN_ENABLED()) { 00948 RUBY_DTRACE_FIND_REQUIRE_RETURN(StringValuePtr(fname), 00949 rb_sourcefile(), 00950 rb_sourceline()); 00951 } 00952 if (found) { 00953 if (!path || !(ftptr = load_lock(RSTRING_PTR(path)))) { 00954 result = Qfalse; 00955 } 00956 else { 00957 switch (found) { 00958 case 'r': 00959 rb_load_internal(path, 0); 00960 break; 00961 00962 case 's': 00963 handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext, 00964 path, 0, path); 00965 rb_ary_push(ruby_dln_librefs, LONG2NUM(handle)); 00966 break; 00967 } 00968 rb_provide_feature(path); 00969 result = Qtrue; 00970 } 00971 } 00972 } 00973 POP_TAG(); 00974 load_unlock(ftptr, !state); 00975 00976 rb_set_safe_level_force(saved.safe); 00977 if (state) { 00978 JUMP_TAG(state); 00979 } 00980 00981 if (NIL_P(result)) { 00982 load_failed(fname); 00983 } 00984 00985 th->errinfo = errinfo; 00986 00987 if (RUBY_DTRACE_REQUIRE_RETURN_ENABLED()) { 00988 RUBY_DTRACE_REQUIRE_RETURN(StringValuePtr(fname), 00989 rb_sourcefile(), 00990 rb_sourceline()); 00991 } 00992 00993 return result; 00994 } 00995 00996 VALUE 00997 rb_require(const char *fname) 00998 { 00999 VALUE fn = rb_str_new2(fname); 01000 OBJ_FREEZE(fn); 01001 return rb_require_safe(fn, rb_safe_level()); 01002 } 01003 01004 static VALUE 01005 init_ext_call(VALUE arg) 01006 { 01007 SCOPE_SET(NOEX_PUBLIC); 01008 (*(void (*)(void))arg)(); 01009 return Qnil; 01010 } 01011 01012 RUBY_FUNC_EXPORTED void 01013 ruby_init_ext(const char *name, void (*init)(void)) 01014 { 01015 char* const lock_key = load_lock(name); 01016 if (lock_key) { 01017 rb_vm_call_cfunc(rb_vm_top_self(), init_ext_call, (VALUE)init, 01018 0, rb_str_new2(name)); 01019 rb_provide(name); 01020 load_unlock(lock_key, 1); 01021 } 01022 } 01023 01024 /* 01025 * call-seq: 01026 * mod.autoload(module, filename) -> nil 01027 * 01028 * Registers _filename_ to be loaded (using <code>Kernel::require</code>) 01029 * the first time that _module_ (which may be a <code>String</code> or 01030 * a symbol) is accessed in the namespace of _mod_. 01031 * 01032 * module A 01033 * end 01034 * A.autoload(:B, "b") 01035 * A::B.doit # autoloads "b" 01036 */ 01037 01038 static VALUE 01039 rb_mod_autoload(VALUE mod, VALUE sym, VALUE file) 01040 { 01041 ID id = rb_to_id(sym); 01042 01043 FilePathValue(file); 01044 rb_autoload(mod, id, RSTRING_PTR(file)); 01045 return Qnil; 01046 } 01047 01048 /* 01049 * call-seq: 01050 * mod.autoload?(name) -> String or nil 01051 * 01052 * Returns _filename_ to be loaded if _name_ is registered as 01053 * +autoload+ in the namespace of _mod_. 01054 * 01055 * module A 01056 * end 01057 * A.autoload(:B, "b") 01058 * A.autoload?(:B) #=> "b" 01059 */ 01060 01061 static VALUE 01062 rb_mod_autoload_p(VALUE mod, VALUE sym) 01063 { 01064 ID id = rb_check_id(&sym); 01065 if (!id) { 01066 return Qnil; 01067 } 01068 return rb_autoload_p(mod, id); 01069 } 01070 01071 /* 01072 * call-seq: 01073 * autoload(module, filename) -> nil 01074 * 01075 * Registers _filename_ to be loaded (using <code>Kernel::require</code>) 01076 * the first time that _module_ (which may be a <code>String</code> or 01077 * a symbol) is accessed. 01078 * 01079 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb") 01080 */ 01081 01082 static VALUE 01083 rb_f_autoload(VALUE obj, VALUE sym, VALUE file) 01084 { 01085 VALUE klass = rb_class_real(rb_vm_cbase()); 01086 if (NIL_P(klass)) { 01087 rb_raise(rb_eTypeError, "Can not set autoload on singleton class"); 01088 } 01089 return rb_mod_autoload(klass, sym, file); 01090 } 01091 01092 /* 01093 * call-seq: 01094 * autoload?(name) -> String or nil 01095 * 01096 * Returns _filename_ to be loaded if _name_ is registered as 01097 * +autoload+. 01098 * 01099 * autoload(:B, "b") 01100 * autoload?(:B) #=> "b" 01101 */ 01102 01103 static VALUE 01104 rb_f_autoload_p(VALUE obj, VALUE sym) 01105 { 01106 /* use rb_vm_cbase() as same as rb_f_autoload. */ 01107 VALUE klass = rb_vm_cbase(); 01108 if (NIL_P(klass)) { 01109 return Qnil; 01110 } 01111 return rb_mod_autoload_p(klass, sym); 01112 } 01113 01114 void 01115 Init_load() 01116 { 01117 #undef rb_intern 01118 #define rb_intern(str) rb_intern2((str), strlen(str)) 01119 rb_vm_t *vm = GET_VM(); 01120 static const char var_load_path[] = "$:"; 01121 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1); 01122 01123 rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter); 01124 rb_alias_variable(rb_intern("$-I"), id_load_path); 01125 rb_alias_variable(rb_intern("$LOAD_PATH"), id_load_path); 01126 vm->load_path = rb_ary_new(); 01127 vm->expanded_load_path = rb_ary_tmp_new(0); 01128 vm->load_path_snapshot = rb_ary_tmp_new(0); 01129 vm->load_path_check_cache = 0; 01130 01131 rb_define_virtual_variable("$\"", get_loaded_features, 0); 01132 rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0); 01133 vm->loaded_features = rb_ary_new(); 01134 vm->loaded_features_snapshot = rb_ary_tmp_new(0); 01135 vm->loaded_features_index = st_init_strtable(); 01136 01137 rb_define_global_function("load", rb_f_load, -1); 01138 rb_define_global_function("require", rb_f_require, 1); 01139 rb_define_global_function("require_relative", rb_f_require_relative, 1); 01140 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2); 01141 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, 1); 01142 rb_define_global_function("autoload", rb_f_autoload, 2); 01143 rb_define_global_function("autoload?", rb_f_autoload_p, 1); 01144 01145 ruby_dln_librefs = rb_ary_tmp_new(0); 01146 rb_gc_register_mark_object(ruby_dln_librefs); 01147 } 01148