|
Ruby
2.0.0p481(2014-05-08revision45883)
|
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 #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 /* Construct expanded load path and store it to cache. 00048 We rebuild load path partially if the cache is invalid. 00049 We don't cache non string object and expand it every time. We ensure that 00050 string objects in $LOAD_PATH are frozen. 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 /* Use cached expanded path. */ 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 /* Freeze only string object. We expand other objects every time. */ 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 /* The load path was modified. Rebuild the expanded load path. */ 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 /* Non string object. */ 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 /* Expand only non-cacheable objects. */ 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 /* Current working directory or filesystem encoding was changed. 00142 Expand relative load path and non-cacheable objects again. */ 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 /* Expand only tilde (User HOME) and non-cacheable objects. */ 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 /* Add to the loaded-features index all the required entries for 00219 `feature`, located at `offset` in $LOADED_FEATURES. We add an 00220 index entry at each string `short_feature` for which 00221 feature == "#{prefix}#{short_feature}#{e}" 00222 where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty 00223 or ends in '/'. This maintains the invariant that `rb_feature_p()` 00224 relies on for its fast lookup. 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 /* Now `ext` points to the only string matching %r{^\.[^./]*$} that is 00241 at the end of `feature`, or is NULL if there is no such string. */ 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 /* Now *p == '/'. We reach this point for every '/' in `feature`. */ 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 /* The sharing was broken; something (other than us in rb_provide_feature()) 00281 modified loaded_features. Rebuild the index. */ 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 /* This searches `load_path` for a value such that 00299 name == "#{load_path[i]}/#{feature}" 00300 if `feature` is a suffix of `name`, or otherwise 00301 name == "#{load_path[i]}/#{feature}#{ext}" 00302 for an acceptable string `ext`. It returns 00303 `load_path[i].to_str` if found, else 0. 00304 00305 If type is 's', then `ext` is acceptable only if IS_DLEXT(ext); 00306 if 'r', then only if IS_RBEXT(ext); otherwise `ext` may be absent 00307 or have any value matching `%r{^\.[^./]*$}`. 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 /* Now name == "#{prefix}/#{feature}#{ext}" where ext is acceptable 00338 (possibly empty) and prefix is some string of length plen. */ 00339 00340 if (plen > 0) --plen; /* exclude '.' */ 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 /* We search `features` for an entry such that either 00399 "#{features[i]}" == "#{load_path[j]}/#{feature}#{e}" 00400 for some j, or 00401 "#{features[i]}" == "#{feature}#{e}" 00402 Here `e` is an "allowed" extension -- either empty or one 00403 of the extensions accepted by IS_RBEXT, IS_SOEXT, or 00404 IS_DLEXT. Further, if `ext && rb` then `IS_RBEXT(e)`, 00405 and if `ext && !rb` then `IS_SOEXT(e) || IS_DLEXT(e)`. 00406 00407 If `expanded`, then only the latter form (without load_path[j]) 00408 is accepted. Otherwise either form is accepted, *unless* `ext` 00409 is false and an otherwise-matching entry of the first form is 00410 preceded by an entry of the form 00411 "#{features[i2]}" == "#{load_path[j2]}/#{feature}#{e2}" 00412 where `e2` matches %r{^\.[^./]*$} but is not an allowed extension. 00413 After a "distractor" entry of this form, only entries of the 00414 form "#{feature}#{e}" are accepted. 00415 00416 In `rb_provide_feature()` and `get_loaded_features_index()` we 00417 maintain an invariant that the array `this_feature_index` will 00418 point to every entry in `features` which has the form 00419 "#{prefix}#{feature}#{e}" 00420 where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty 00421 or ends in '/'. This includes both match forms above, as well 00422 as any distractors, so we may ignore all other entries in `features`. 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; /* ensure */ 00587 00588 if (!wrap) { 00589 rb_secure(4); /* should alter global state */ 00590 th->top_wrapper = 0; 00591 } 00592 else { 00593 /* load in anonymous module as toplevel */ 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 /* an error on loading don't include INT2FIX(TAG_FATAL) see r35625 */ 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 /* exception during load */ 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 * call-seq: 00661 * load(filename, wrap=false) -> true 00662 * 00663 * Loads and executes the Ruby 00664 * program in the file _filename_. If the filename does not 00665 * resolve to an absolute path, the file is searched for in the library 00666 * directories listed in <code>$:</code>. If the optional _wrap_ 00667 * parameter is +true+, the loaded script will be executed 00668 * under an anonymous module, protecting the calling program's global 00669 * namespace. In no circumstance will any local variables in the loaded 00670 * file be propagated to the loading environment. 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 /* loading ruby library should be serialized. */ 00711 if (!loading_tbl) { 00712 GET_VM()->loading_table = loading_tbl = st_init_strtable(); 00713 } 00714 /* partial state */ 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 /* TODO: display to $stderr, not stderr in C */ 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 /* still in-use */ 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 * call-seq: 00771 * require(name) -> true or false 00772 * 00773 * Loads the given +name+, returning +true+ if successful and +false+ if the 00774 * feature is already loaded. 00775 * 00776 * If the filename does not resolve to an absolute path, it will be searched 00777 * for in the directories listed in <code>$LOAD_PATH</code> (<code>$:</code>). 00778 * 00779 * If the filename has the extension ".rb", it is loaded as a source file; if 00780 * the extension is ".so", ".o", or ".dll", or the default shared library 00781 * extension on the current platform, Ruby loads the shared library as a 00782 * Ruby extension. Otherwise, Ruby tries adding ".rb", ".so", and so on 00783 * to the name until found. If the file named cannot be found, a LoadError 00784 * will be raised. 00785 * 00786 * For Ruby extensions the filename given may use any shared library 00787 * extension. For example, on Linux the socket extension is "socket.so" and 00788 * <code>require 'socket.dll'</code> will load the socket extension. 00789 * 00790 * The absolute path of the loaded file is added to 00791 * <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be 00792 * loaded again if its path already appears in <code>$"</code>. For example, 00793 * <code>require 'a'; require './a'</code> will not load <code>a.rb</code> 00794 * again. 00795 * 00796 * require "my-library.rb" 00797 * require "db-driver" 00798 * 00799 * Any constants or globals within the loaded source file will be available 00800 * in the calling program's global namespace. However, local variables will 00801 * not be propagated to the loading environment. 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 * call-seq: 00813 * require_relative(string) -> true or false 00814 * 00815 * Ruby tries to load the library named _string_ relative to the requiring 00816 * file's path. If the file's path cannot be determined a LoadError is raised. 00817 * If a file is loaded +true+ is returned and false otherwise. 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 /* already registered */ 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 * call-seq: 01059 * mod.autoload(module, filename) -> nil 01060 * 01061 * Registers _filename_ to be loaded (using <code>Kernel::require</code>) 01062 * the first time that _module_ (which may be a <code>String</code> or 01063 * a symbol) is accessed in the namespace of _mod_. 01064 * 01065 * module A 01066 * end 01067 * A.autoload(:B, "b") 01068 * A::B.doit # autoloads "b" 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 * call-seq: 01083 * mod.autoload?(name) -> String or nil 01084 * 01085 * Returns _filename_ to be loaded if _name_ is registered as 01086 * +autoload+ in the namespace of _mod_. 01087 * 01088 * module A 01089 * end 01090 * A.autoload(:B, "b") 01091 * A.autoload?(:B) #=> "b" 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 * call-seq: 01106 * autoload(module, filename) -> nil 01107 * 01108 * Registers _filename_ to be loaded (using <code>Kernel::require</code>) 01109 * the first time that _module_ (which may be a <code>String</code> or 01110 * a symbol) is accessed. 01111 * 01112 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb") 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 * call-seq: 01127 * autoload?(name) -> String or nil 01128 * 01129 * Returns _filename_ to be loaded if _name_ is registered as 01130 * +autoload+. 01131 * 01132 * autoload(:B, "b") 01133 * autoload?(:B) #=> "b" 01134 */ 01135 01136 static VALUE 01137 rb_f_autoload_p(VALUE obj, VALUE sym) 01138 { 01139 /* use rb_vm_cbase() as same as rb_f_autoload. */ 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
1.7.6.1