Ruby  2.0.0p481(2014-05-08revision45883)
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 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