Ruby 1.9.2p136(2010-12-25revision30365)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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