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

Generated on 19 Jul 2016 for Ruby by  doxygen 1.4.7