Ruby  2.0.0p247(2013-06-27revision41674)
load.c
Go to the documentation of this file.
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