Ruby 1.9.3p327(2012-11-10revision37606)
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 
00011 VALUE ruby_dln_librefs;
00012 
00013 #define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
00014 #define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
00015 #ifdef DLEXT2
00016 #define IS_DLEXT(e) (strcmp((e), DLEXT) == 0 || strcmp((e), DLEXT2) == 0)
00017 #else
00018 #define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
00019 #endif
00020 
00021 
00022 static const char *const loadable_ext[] = {
00023     ".rb", DLEXT,
00024 #ifdef DLEXT2
00025     DLEXT2,
00026 #endif
00027     0
00028 };
00029 
00030 VALUE
00031 rb_get_load_path(void)
00032 {
00033     VALUE load_path = GET_VM()->load_path;
00034     return load_path;
00035 }
00036 
00037 VALUE
00038 rb_get_expanded_load_path(void)
00039 {
00040     VALUE load_path = rb_get_load_path();
00041     VALUE ary;
00042     long i;
00043 
00044     ary = rb_ary_new2(RARRAY_LEN(load_path));
00045     for (i = 0; i < RARRAY_LEN(load_path); ++i) {
00046         VALUE path = rb_file_expand_path_fast(RARRAY_PTR(load_path)[i], Qnil);
00047         rb_str_freeze(path);
00048         rb_ary_push(ary, path);
00049     }
00050     rb_obj_freeze(ary);
00051     return ary;
00052 }
00053 
00054 static VALUE
00055 load_path_getter(ID id, rb_vm_t *vm)
00056 {
00057     return vm->load_path;
00058 }
00059 
00060 static VALUE
00061 get_loaded_features(void)
00062 {
00063     return GET_VM()->loaded_features;
00064 }
00065 
00066 static st_table *
00067 get_loading_table(void)
00068 {
00069     return GET_VM()->loading_table;
00070 }
00071 
00072 static VALUE
00073 loaded_feature_path(const char *name, long vlen, const char *feature, long len,
00074                     int type, VALUE load_path)
00075 {
00076     long i;
00077     long plen;
00078     const char *e;
00079 
00080     if(vlen < len) return 0;
00081     if (!strncmp(name+(vlen-len),feature,len)){
00082         plen = vlen - len - 1;
00083     } else {
00084         for (e = name + vlen; name != e && *e != '.' && *e != '/'; --e);
00085         if (*e!='.' ||
00086             e-name < len ||
00087             strncmp(e-len,feature,len) )
00088             return 0;
00089         plen = e - name - len - 1;
00090     }
00091     for (i = 0; i < RARRAY_LEN(load_path); ++i) {
00092         VALUE p = RARRAY_PTR(load_path)[i];
00093         const char *s = StringValuePtr(p);
00094         long n = RSTRING_LEN(p);
00095 
00096         if (n != plen ) continue;
00097         if (n && (strncmp(name, s, n) || name[n] != '/')) continue;
00098         switch (type) {
00099           case 's':
00100             if (IS_DLEXT(&name[n+len+1])) return p;
00101             break;
00102           case 'r':
00103             if (IS_RBEXT(&name[n+len+1])) return p;
00104             break;
00105           default:
00106             return p;
00107         }
00108     }
00109     return 0;
00110 }
00111 
00112 struct loaded_feature_searching {
00113     const char *name;
00114     long len;
00115     int type;
00116     VALUE load_path;
00117     const char *result;
00118 };
00119 
00120 static int
00121 loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
00122 {
00123     const char *s = (const char *)v;
00124     struct loaded_feature_searching *fp = (struct loaded_feature_searching *)f;
00125     VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len,
00126                                   fp->type, fp->load_path);
00127     if (!p) return ST_CONTINUE;
00128     fp->result = s;
00129     return ST_STOP;
00130 }
00131 
00132 static int
00133 rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn)
00134 {
00135     VALUE v, features, p, load_path = 0;
00136     const char *f, *e;
00137     long i, len, elen, n;
00138     st_table *loading_tbl;
00139     st_data_t data;
00140     int type;
00141 
00142     if (fn) *fn = 0;
00143     if (ext) {
00144         elen = strlen(ext);
00145         len = strlen(feature) - elen;
00146         type = rb ? 'r' : 's';
00147     }
00148     else {
00149         len = strlen(feature);
00150         elen = 0;
00151         type = 0;
00152     }
00153     features = get_loaded_features();
00154     for (i = 0; i < RARRAY_LEN(features); ++i) {
00155         v = RARRAY_PTR(features)[i];
00156         f = StringValuePtr(v);
00157         if ((n = RSTRING_LEN(v)) < len) continue;
00158         if (strncmp(f, feature, len) != 0) {
00159             if (expanded) continue;
00160             if (!load_path) load_path = rb_get_expanded_load_path();
00161             if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
00162                 continue;
00163             expanded = 1;
00164             f += RSTRING_LEN(p) + 1;
00165         }
00166         if (!*(e = f + len)) {
00167             if (ext) continue;
00168             return 'u';
00169         }
00170         if (*e != '.') continue;
00171         if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
00172             return 's';
00173         }
00174         if ((rb || !ext) && (IS_RBEXT(e))) {
00175             return 'r';
00176         }
00177     }
00178     loading_tbl = get_loading_table();
00179     if (loading_tbl) {
00180         f = 0;
00181         if (!expanded) {
00182             struct loaded_feature_searching fs;
00183             fs.name = feature;
00184             fs.len = len;
00185             fs.type = type;
00186             fs.load_path = load_path ? load_path : rb_get_load_path();
00187             fs.result = 0;
00188             st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
00189             if ((f = fs.result) != 0) {
00190                 if (fn) *fn = f;
00191                 goto loading;
00192             }
00193         }
00194         if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
00195             if (fn) *fn = (const char*)data;
00196           loading:
00197             if (!ext) return 'u';
00198             return !IS_RBEXT(ext) ? 's' : 'r';
00199         }
00200         else {
00201             VALUE bufstr;
00202             char *buf;
00203 
00204             if (ext && *ext) return 0;
00205             bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN);
00206             buf = RSTRING_PTR(bufstr);
00207             MEMCPY(buf, feature, char, len);
00208             for (i = 0; (e = loadable_ext[i]) != 0; i++) {
00209                 strlcpy(buf + len, e, DLEXT_MAXLEN + 1);
00210                 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
00211                     rb_str_resize(bufstr, 0);
00212                     if (fn) *fn = (const char*)data;
00213                     return i ? 's' : 'r';
00214                 }
00215             }
00216             rb_str_resize(bufstr, 0);
00217         }
00218     }
00219     return 0;
00220 }
00221 
00222 int
00223 rb_provided(const char *feature)
00224 {
00225     return rb_feature_provided(feature, 0);
00226 }
00227 
00228 int
00229 rb_feature_provided(const char *feature, const char **loading)
00230 {
00231     const char *ext = strrchr(feature, '.');
00232     volatile VALUE fullpath = 0;
00233 
00234     if (*feature == '.' &&
00235         (feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) {
00236         fullpath = rb_file_expand_path_fast(rb_str_new2(feature), Qnil);
00237         feature = RSTRING_PTR(fullpath);
00238     }
00239     if (ext && !strchr(ext, '/')) {
00240         if (IS_RBEXT(ext)) {
00241             if (rb_feature_p(feature, ext, TRUE, FALSE, loading)) return TRUE;
00242             return FALSE;
00243         }
00244         else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
00245             if (rb_feature_p(feature, ext, FALSE, FALSE, loading)) return TRUE;
00246             return FALSE;
00247         }
00248     }
00249     if (rb_feature_p(feature, 0, TRUE, FALSE, loading))
00250         return TRUE;
00251     return FALSE;
00252 }
00253 
00254 static void
00255 rb_provide_feature(VALUE feature)
00256 {
00257     if (OBJ_FROZEN(get_loaded_features())) {
00258         rb_raise(rb_eRuntimeError,
00259                  "$LOADED_FEATURES is frozen; cannot append feature");
00260     }
00261     rb_ary_push(get_loaded_features(), feature);
00262 }
00263 
00264 void
00265 rb_provide(const char *feature)
00266 {
00267     rb_provide_feature(rb_usascii_str_new2(feature));
00268 }
00269 
00270 NORETURN(static void load_failed(VALUE));
00271 
00272 static void
00273 rb_load_internal(VALUE fname, int wrap)
00274 {
00275     int state;
00276     rb_thread_t *th = GET_THREAD();
00277     volatile VALUE wrapper = th->top_wrapper;
00278     volatile VALUE self = th->top_self;
00279     volatile int loaded = FALSE;
00280     volatile int mild_compile_error;
00281 #ifndef __GNUC__
00282     rb_thread_t *volatile th0 = th;
00283 #endif
00284 
00285     th->errinfo = Qnil; /* ensure */
00286 
00287     if (!wrap) {
00288         rb_secure(4);           /* should alter global state */
00289         th->top_wrapper = 0;
00290     }
00291     else {
00292         /* load in anonymous module as toplevel */
00293         th->top_self = rb_obj_clone(rb_vm_top_self());
00294         th->top_wrapper = rb_module_new();
00295         rb_extend_object(th->top_self, th->top_wrapper);
00296     }
00297 
00298     mild_compile_error = th->mild_compile_error;
00299     PUSH_TAG();
00300     state = EXEC_TAG();
00301     if (state == 0) {
00302         NODE *node;
00303         VALUE iseq;
00304 
00305         th->mild_compile_error++;
00306         node = (NODE *)rb_load_file(RSTRING_PTR(fname));
00307         loaded = TRUE;
00308         iseq = rb_iseq_new_top(node, rb_str_new2("<top (required)>"), fname, rb_realpath_internal(Qnil, fname, 1), Qfalse);
00309         th->mild_compile_error--;
00310         rb_iseq_eval(iseq);
00311     }
00312     POP_TAG();
00313 
00314 #ifndef __GNUC__
00315     th = th0;
00316     fname = RB_GC_GUARD(fname);
00317 #endif
00318     th->mild_compile_error = mild_compile_error;
00319     th->top_self = self;
00320     th->top_wrapper = wrapper;
00321 
00322     if (!loaded && !FIXNUM_P(GET_THREAD()->errinfo)) {
00323         /* an error on loading don't include INT2FIX(TAG_FATAL) see r35625 */
00324         rb_exc_raise(GET_THREAD()->errinfo);
00325     }
00326     if (state) {
00327         rb_vm_jump_tag_but_local_jump(state, Qundef);
00328     }
00329 
00330     if (!NIL_P(GET_THREAD()->errinfo)) {
00331         /* exception during load */
00332         rb_exc_raise(th->errinfo);
00333     }
00334 }
00335 
00336 void
00337 rb_load(VALUE fname, int wrap)
00338 {
00339     VALUE tmp = rb_find_file(FilePathValue(fname));
00340     if (!tmp) load_failed(fname);
00341     rb_load_internal(tmp, wrap);
00342 }
00343 
00344 void
00345 rb_load_protect(VALUE fname, int wrap, int *state)
00346 {
00347     int status;
00348 
00349     PUSH_TAG();
00350     if ((status = EXEC_TAG()) == 0) {
00351         rb_load(fname, wrap);
00352     }
00353     POP_TAG();
00354     if (state)
00355         *state = status;
00356 }
00357 
00358 /*
00359  *  call-seq:
00360  *     load(filename, wrap=false)   -> true
00361  *
00362  *  Loads and executes the Ruby
00363  *  program in the file _filename_. If the filename does not
00364  *  resolve to an absolute path, the file is searched for in the library
00365  *  directories listed in <code>$:</code>. If the optional _wrap_
00366  *  parameter is +true+, the loaded script will be executed
00367  *  under an anonymous module, protecting the calling program's global
00368  *  namespace. In no circumstance will any local variables in the loaded
00369  *  file be propagated to the loading environment.
00370  */
00371 
00372 static VALUE
00373 rb_f_load(int argc, VALUE *argv)
00374 {
00375     VALUE fname, wrap, path;
00376 
00377     rb_scan_args(argc, argv, "11", &fname, &wrap);
00378     path = rb_find_file(FilePathValue(fname));
00379     if (!path) {
00380         if (!rb_file_load_ok(RSTRING_PTR(fname)))
00381             load_failed(fname);
00382         path = fname;
00383     }
00384     rb_load_internal(path, RTEST(wrap));
00385     return Qtrue;
00386 }
00387 
00388 static char *
00389 load_lock(const char *ftptr)
00390 {
00391     st_data_t data;
00392     st_table *loading_tbl = get_loading_table();
00393 
00394     if (!loading_tbl || !st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
00395         /* loading ruby library should be serialized. */
00396         if (!loading_tbl) {
00397             GET_VM()->loading_table = loading_tbl = st_init_strtable();
00398         }
00399         /* partial state */
00400         ftptr = ruby_strdup(ftptr);
00401         data = (st_data_t)rb_barrier_new();
00402         st_insert(loading_tbl, (st_data_t)ftptr, data);
00403         return (char *)ftptr;
00404     }
00405     if (RTEST(ruby_verbose)) {
00406         rb_warning("loading in progress, circular require considered harmful - %s", ftptr);
00407         rb_backtrace();
00408     }
00409     return RTEST(rb_barrier_wait((VALUE)data)) ? (char *)ftptr : 0;
00410 }
00411 
00412 static void
00413 load_unlock(const char *ftptr, int done)
00414 {
00415     if (ftptr) {
00416         st_data_t key = (st_data_t)ftptr;
00417         st_data_t data;
00418         st_table *loading_tbl = get_loading_table();
00419 
00420         if (st_delete(loading_tbl, &key, &data)) {
00421             VALUE barrier = (VALUE)data;
00422             xfree((char *)key);
00423             if (done)
00424                 rb_barrier_destroy(barrier);
00425             else
00426                 rb_barrier_release(barrier);
00427         }
00428     }
00429 }
00430 
00431 
00432 /*
00433  *  call-seq:
00434  *     require(name)    -> true or false
00435  *
00436  *  Loads the given +name+, returning +true+ if successful and +false+ if the
00437  *  feature is already loaded.
00438  *
00439  *  If the filename does not resolve to an absolute path, it will be searched
00440  *  for in the directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
00441  *
00442  *  If the filename has the extension ".rb", it is loaded as a source file; if
00443  *  the extension is ".so", ".o", or ".dll", or the default shared library
00444  *  extension on the current platform, Ruby loads the shared library as a
00445  *  Ruby extension.  Otherwise, Ruby tries adding ".rb", ".so", and so on
00446  *  to the name until found.  If the file named cannot be found, a LoadError
00447  *  will be raised.
00448  *
00449  *  For Ruby extensions the filename given may use any shared library
00450  *  extension.  For example, on Linux the socket extension is "socket.so" and
00451  *  <code>require 'socket.dll'</code> will load the socket extension.
00452  *
00453  *  The absolute path of the loaded file is added to
00454  *  <code>$LOADED_FEATURES</code> (<code>$"</code>).  A file will not be
00455  *  loaded again if its path already appears in <code>$"</code>.  For example,
00456  *  <code>require 'a'; require './a'</code> will not load <code>a.rb</code>
00457  *  again.
00458  *
00459  *    require "my-library.rb"
00460  *    require "db-driver"
00461  */
00462 
00463 VALUE
00464 rb_f_require(VALUE obj, VALUE fname)
00465 {
00466     return rb_require_safe(fname, rb_safe_level());
00467 }
00468 
00469 /*
00470  * call-seq:
00471  *   require_relative(string) -> true or false
00472  *
00473  * Ruby tries to load the library named _string_ relative to the requiring
00474  * file's path.  If the file's path cannot be determined a LoadError is raised.
00475  * If a file is loaded +true+ is returned and false otherwise.
00476  */
00477 VALUE
00478 rb_f_require_relative(VALUE obj, VALUE fname)
00479 {
00480     VALUE base = rb_current_realfilepath();
00481     if (NIL_P(base)) {
00482         rb_raise(rb_eLoadError, "cannot infer basepath");
00483     }
00484     base = rb_file_dirname(base);
00485     return rb_require_safe(rb_file_absolute_path(fname, base), rb_safe_level());
00486 }
00487 
00488 static int
00489 search_required(VALUE fname, volatile VALUE *path, int safe_level)
00490 {
00491     VALUE tmp;
00492     char *ext, *ftptr;
00493     int type, ft = 0;
00494     const char *loading;
00495 
00496     *path = 0;
00497     ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
00498     if (ext && !strchr(ext, '/')) {
00499         if (IS_RBEXT(ext)) {
00500             if (rb_feature_p(ftptr, ext, TRUE, FALSE, &loading)) {
00501                 if (loading) *path = rb_filesystem_str_new_cstr(loading);
00502                 return 'r';
00503             }
00504             if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) {
00505                 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
00506                 if (!rb_feature_p(ftptr, ext, TRUE, TRUE, &loading) || loading)
00507                     *path = tmp;
00508                 return 'r';
00509             }
00510             return 0;
00511         }
00512         else if (IS_SOEXT(ext)) {
00513             if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) {
00514                 if (loading) *path = rb_filesystem_str_new_cstr(loading);
00515                 return 's';
00516             }
00517             tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
00518 #ifdef DLEXT2
00519             OBJ_FREEZE(tmp);
00520             if (rb_find_file_ext_safe(&tmp, loadable_ext + 1, safe_level)) {
00521                 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
00522                 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
00523                     *path = tmp;
00524                 return 's';
00525             }
00526 #else
00527             rb_str_cat2(tmp, DLEXT);
00528             OBJ_FREEZE(tmp);
00529             if ((tmp = rb_find_file_safe(tmp, safe_level)) != 0) {
00530                 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
00531                 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
00532                     *path = tmp;
00533                 return 's';
00534             }
00535 #endif
00536         }
00537         else if (IS_DLEXT(ext)) {
00538             if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) {
00539                 if (loading) *path = rb_filesystem_str_new_cstr(loading);
00540                 return 's';
00541             }
00542             if ((tmp = rb_find_file_safe(fname, safe_level)) != 0) {
00543                 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
00544                 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
00545                     *path = tmp;
00546                 return 's';
00547             }
00548         }
00549     }
00550     else if ((ft = rb_feature_p(ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
00551         if (loading) *path = rb_filesystem_str_new_cstr(loading);
00552         return 'r';
00553     }
00554     tmp = fname;
00555     type = rb_find_file_ext_safe(&tmp, loadable_ext, safe_level);
00556     switch (type) {
00557       case 0:
00558         if (ft)
00559             break;
00560         ftptr = RSTRING_PTR(tmp);
00561         return rb_feature_p(ftptr, 0, FALSE, TRUE, 0);
00562 
00563       default:
00564         if (ft)
00565             break;
00566       case 1:
00567         ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
00568         if (rb_feature_p(ftptr, ext, !--type, TRUE, &loading) && !loading)
00569             break;
00570         *path = tmp;
00571     }
00572     return type ? 's' : 'r';
00573 }
00574 
00575 static void
00576 load_failed(VALUE fname)
00577 {
00578     VALUE mesg = rb_str_buf_new_cstr("cannot load such file -- ");
00579     rb_str_append(mesg, fname); /* should be ASCII compatible */
00580     rb_exc_raise(rb_exc_new3(rb_eLoadError, mesg));
00581 }
00582 
00583 static VALUE
00584 load_ext(VALUE path)
00585 {
00586     SCOPE_SET(NOEX_PUBLIC);
00587     return (VALUE)dln_load(RSTRING_PTR(path));
00588 }
00589 
00590 VALUE
00591 rb_require_safe(VALUE fname, int safe)
00592 {
00593     volatile VALUE result = Qnil;
00594     rb_thread_t *th = GET_THREAD();
00595     volatile VALUE errinfo = th->errinfo;
00596     int state;
00597     struct {
00598         int safe;
00599     } volatile saved;
00600     char *volatile ftptr = 0;
00601 
00602     PUSH_TAG();
00603     saved.safe = rb_safe_level();
00604     if ((state = EXEC_TAG()) == 0) {
00605         VALUE path;
00606         long handle;
00607         int found;
00608 
00609         rb_set_safe_level_force(safe);
00610         FilePathValue(fname);
00611         rb_set_safe_level_force(0);
00612         found = search_required(fname, &path, safe);
00613         if (found) {
00614             if (!path || !(ftptr = load_lock(RSTRING_PTR(path)))) {
00615                 result = Qfalse;
00616             }
00617             else {
00618                 switch (found) {
00619                   case 'r':
00620                     rb_load_internal(path, 0);
00621                     break;
00622 
00623                   case 's':
00624                     handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
00625                                                     path, 0, path);
00626                     rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
00627                     break;
00628                 }
00629                 rb_provide_feature(path);
00630                 result = Qtrue;
00631             }
00632         }
00633     }
00634     POP_TAG();
00635     load_unlock(ftptr, !state);
00636 
00637     rb_set_safe_level_force(saved.safe);
00638     if (state) {
00639         JUMP_TAG(state);
00640     }
00641 
00642     if (NIL_P(result)) {
00643         load_failed(fname);
00644     }
00645 
00646     th->errinfo = errinfo;
00647 
00648     return result;
00649 }
00650 
00651 VALUE
00652 rb_require(const char *fname)
00653 {
00654     VALUE fn = rb_str_new2(fname);
00655     OBJ_FREEZE(fn);
00656     return rb_require_safe(fn, rb_safe_level());
00657 }
00658 
00659 static VALUE
00660 init_ext_call(VALUE arg)
00661 {
00662     SCOPE_SET(NOEX_PUBLIC);
00663     (*(void (*)(void))arg)();
00664     return Qnil;
00665 }
00666 
00667 RUBY_FUNC_EXPORTED void
00668 ruby_init_ext(const char *name, void (*init)(void))
00669 {
00670     if (load_lock(name)) {
00671         rb_vm_call_cfunc(rb_vm_top_self(), init_ext_call, (VALUE)init,
00672                          0, rb_str_new2(name));
00673         rb_provide(name);
00674         load_unlock(name, 1);
00675     }
00676 }
00677 
00678 /*
00679  *  call-seq:
00680  *     mod.autoload(module, filename)   -> nil
00681  *
00682  *  Registers _filename_ to be loaded (using <code>Kernel::require</code>)
00683  *  the first time that _module_ (which may be a <code>String</code> or
00684  *  a symbol) is accessed in the namespace of _mod_.
00685  *
00686  *     module A
00687  *     end
00688  *     A.autoload(:B, "b")
00689  *     A::B.doit            # autoloads "b"
00690  */
00691 
00692 static VALUE
00693 rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
00694 {
00695     ID id = rb_to_id(sym);
00696 
00697     FilePathValue(file);
00698     rb_autoload(mod, id, RSTRING_PTR(file));
00699     return Qnil;
00700 }
00701 
00702 /*
00703  *  call-seq:
00704  *     mod.autoload?(name)   -> String or nil
00705  *
00706  *  Returns _filename_ to be loaded if _name_ is registered as
00707  *  +autoload+ in the namespace of _mod_.
00708  *
00709  *     module A
00710  *     end
00711  *     A.autoload(:B, "b")
00712  *     A.autoload?(:B)            #=> "b"
00713  */
00714 
00715 static VALUE
00716 rb_mod_autoload_p(VALUE mod, VALUE sym)
00717 {
00718     return rb_autoload_p(mod, rb_to_id(sym));
00719 }
00720 
00721 /*
00722  *  call-seq:
00723  *     autoload(module, filename)   -> nil
00724  *
00725  *  Registers _filename_ to be loaded (using <code>Kernel::require</code>)
00726  *  the first time that _module_ (which may be a <code>String</code> or
00727  *  a symbol) is accessed.
00728  *
00729  *     autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
00730  */
00731 
00732 static VALUE
00733 rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
00734 {
00735     VALUE klass = rb_class_real(rb_vm_cbase());
00736     if (NIL_P(klass)) {
00737         rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
00738     }
00739     return rb_mod_autoload(klass, sym, file);
00740 }
00741 
00742 /*
00743  *  call-seq:
00744  *     autoload?(name)   -> String or nil
00745  *
00746  *  Returns _filename_ to be loaded if _name_ is registered as
00747  *  +autoload+.
00748  *
00749  *     autoload(:B, "b")
00750  *     autoload?(:B)            #=> "b"
00751  */
00752 
00753 static VALUE
00754 rb_f_autoload_p(VALUE obj, VALUE sym)
00755 {
00756     /* use rb_vm_cbase() as same as rb_f_autoload. */
00757     VALUE klass = rb_vm_cbase();
00758     if (NIL_P(klass)) {
00759         return Qnil;
00760     }
00761     return rb_mod_autoload_p(klass, sym);
00762 }
00763 
00764 void
00765 Init_load()
00766 {
00767 #undef rb_intern
00768 #define rb_intern(str) rb_intern2((str), strlen(str))
00769     rb_vm_t *vm = GET_VM();
00770     static const char var_load_path[] = "$:";
00771     ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
00772 
00773     rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
00774     rb_alias_variable(rb_intern("$-I"), id_load_path);
00775     rb_alias_variable(rb_intern("$LOAD_PATH"), id_load_path);
00776     vm->load_path = rb_ary_new();
00777 
00778     rb_define_virtual_variable("$\"", get_loaded_features, 0);
00779     rb_define_virtual_variable("$LOADED_FEATURES", get_loaded_features, 0);
00780     vm->loaded_features = rb_ary_new();
00781 
00782     rb_define_global_function("load", rb_f_load, -1);
00783     rb_define_global_function("require", rb_f_require, 1);
00784     rb_define_global_function("require_relative", rb_f_require_relative, 1);
00785     rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
00786     rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, 1);
00787     rb_define_global_function("autoload", rb_f_autoload, 2);
00788     rb_define_global_function("autoload?", rb_f_autoload_p, 1);
00789 
00790     ruby_dln_librefs = rb_ary_new();
00791     rb_gc_register_mark_object(ruby_dln_librefs);
00792 }
00793