(linenum→info "unix/slp.c:2238")

ruby/1.9.0/load.c

    1: /*
    2:  * load methods from eval.c
    3:  */
    4: 
    5: #include "eval_intern.h"
    6: 
    7: VALUE ruby_dln_librefs;
    8: 
    9: #define IS_RBEXT(e) (strcmp(e, ".rb") == 0)
   10: #define IS_SOEXT(e) (strcmp(e, ".so") == 0 || strcmp(e, ".o") == 0)
   11: #ifdef DLEXT2
   12: #define IS_DLEXT(e) (strcmp(e, DLEXT) == 0 || strcmp(e, DLEXT2) == 0)
   13: #else
   14: #define IS_DLEXT(e) (strcmp(e, DLEXT) == 0)
   15: #endif
   16: 
   17: 
   18: static const char *const loadable_ext[] = {
   19:     ".rb", DLEXT,
   20: #ifdef DLEXT2
   21:     DLEXT2,
   22: #endif
   23:     0
   24: };
   25: 
   26: VALUE rb_load_path;             /* to be moved to VM */
   27: static VALUE
   28: get_load_path(void)
   29: {
   30:     VALUE load_path = rb_load_path;
   31:     VALUE ary = rb_ary_new2(RARRAY_LEN(load_path));
   32:     long i;
   33: 
   34:     for (i = 0; i < RARRAY_LEN(load_path); ++i) {
   35:         rb_ary_push(ary, rb_file_expand_path(RARRAY_PTR(load_path)[i], Qnil));
   36:     }
   37:     return ary;
   38: }
   39: 
   40: static VALUE
   41: get_loaded_features(void)
   42: {
   43:     return GET_VM()->loaded_features;
   44: }
   45: 
   46: static st_table *
   47: get_loading_table(void)
   48: {
   49:     return GET_VM()->loading_table;
   50: }
   51: 
   52: static VALUE
   53: loaded_feature_path(const char *name, long vlen, const char *feature, long len,
   54:                     int type, VALUE load_path)
   55: {
   56:     long i;
   57: 
   58:     for (i = 0; i < RARRAY_LEN(load_path); ++i) {
   59:         VALUE p = RARRAY_PTR(load_path)[i];
   60:         const char *s = StringValuePtr(p);
   61:         long n = RSTRING_LEN(p);
   62: 
   63:         if (vlen < n + len + 1) continue;
   64:         if (n && (strncmp(name, s, n) || name[n] != '/')) continue;
   65:         if (strncmp(name + n + 1, feature, len)) continue;
   66:         if (name[n+len+1] && name[n+len+1] != '.') continue;
   67:         switch (type) {
   68:           case 's':
   69:             if (IS_DLEXT(&name[n+len+1])) return p;
   70:             break;
   71:           case 'r':
   72:             if (IS_RBEXT(&name[n+len+1])) return p;
   73:             break;
   74:           default:
   75:             return p;
   76:         }
   77:     }
   78:     return 0;
   79: }
   80: 
   81: struct loaded_feature_searching {
   82:     const char *name;
   83:     long len;
   84:     int type;
   85:     VALUE load_path;
   86:     const char *result;
   87: };
   88: 
   89: static int
   90: loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
   91: {
   92:     const char *s = (const char *)v;
   93:     struct loaded_feature_searching *fp = (struct loaded_feature_searching *)f;
   94:     VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len,
   95:                                   fp->type, fp->load_path);
   96:     if (!p) return ST_CONTINUE;
   97:     fp->result = s;
   98:     return ST_STOP;
   99: }
  100: 
  101: static int
  102: rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn)
  103: {
  104:     VALUE v, features, p, load_path = 0;
  105:     const char *f, *e;
  106:     long i, len, elen, n;
  107:     st_table *loading_tbl;
  108:     st_data_t data;
  109:     int type;
  110: 
  111:     if (fn) *fn = 0;
  112:     if (ext) {
  113:         len = ext - feature;
  114:         elen = strlen(ext);
  115:         type = rb ? 'r' : 's';
  116:     }
  117:     else {
  118:         len = strlen(feature);
  119:         elen = 0;
  120:         type = 0;
  121:     }
  122:     features = get_loaded_features();
  123:     for (i = 0; i < RARRAY_LEN(features); ++i) {
  124:         v = RARRAY_PTR(features)[i];
  125:         f = StringValuePtr(v);
  126:         if ((n = RSTRING_LEN(v)) < len) continue;
  127:         if (strncmp(f, feature, len) != 0) {
  128:             if (expanded) continue;
  129:             if (!load_path) load_path = get_load_path();
  130:             if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
  131:                 continue;
  132:             f += RSTRING_LEN(p) + 1;
  133:         }
  134:         if (!*(e = f + len)) {
  135:             if (ext) continue;
  136:             return 'u';
  137:         }
  138:         if (*e != '.') continue;
  139:         if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
  140:             return 's';
  141:         }
  142:         if ((rb || !ext) && (IS_RBEXT(e))) {
  143:             return 'r';
  144:         }
  145:     }
  146:     loading_tbl = get_loading_table();
  147:     if (loading_tbl) {
  148:         f = 0;
  149:         if (!expanded) {
  150:             struct loaded_feature_searching fs;
  151:             fs.name = feature;
  152:             fs.len = len;
  153:             fs.type = type;
  154:             fs.load_path = load_path ? load_path : get_load_path();
  155:             fs.result = 0;
  156:             st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
  157:             if ((f = fs.result) != 0) {
  158:                 if (fn) *fn = f;
  159:                 goto loading;
  160:             }
  161:         }
  162:         if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
  163:             if (fn) *fn = (const char*)data;
  164:           loading:
  165:             if (!ext) return 'u';
  166:             return !IS_RBEXT(ext) ? 's' : 'r';
  167:         }
  168:         else {
  169:             char *buf;
  170: 
  171:             if (ext && *ext) return 0;
  172:             buf = ALLOCA_N(char, len + DLEXT_MAXLEN + 1);
  173:             MEMCPY(buf, feature, char, len);
  174:             for (i = 0; (e = loadable_ext[i]) != 0; i++) {
  175:                 strncpy(buf + len, e, DLEXT_MAXLEN + 1);
  176:                 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
  177:                     if (fn) *fn = (const char*)data;
  178:                     return i ? 's' : 'r';
  179:                 }
  180:             }
  181:         }
  182:     }
  183:     return 0;
  184: }
  185: 
  186: int
  187: rb_provided(const char *feature)
  188: {
  189:     const char *ext = strrchr(feature, '.');
  190: 
  191:     if (ext && !strchr(ext, '/')) {
  192:         if (IS_RBEXT(ext)) {
  193:             if (rb_feature_p(feature, ext, Qtrue, Qfalse, 0)) return Qtrue;
  194:             return Qfalse;
  195:         }
  196:         else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
  197:             if (rb_feature_p(feature, ext, Qfalse, Qfalse, 0)) return Qtrue;
  198:             return Qfalse;
  199:         }
  200:     }
  201:     if (rb_feature_p(feature, feature + strlen(feature), Qtrue, Qfalse, 0))
  202:         return Qtrue;
  203:     return Qfalse;
  204: }
  205: 
  206: static void
  207: rb_provide_feature(VALUE feature)
  208: {
  209:     rb_ary_push(get_loaded_features(), feature);
  210: }
  211: 
  212: void
  213: rb_provide(const char *feature)
  214: {
  215:     rb_provide_feature(rb_str_new2(feature));
  216: }
  217: 
  218: NORETURN(static void load_failed(VALUE));
  219: 
  220: void
  221: rb_load(VALUE fname, int wrap)
  222: {
  223:     VALUE tmp;
  224:     int state;
  225:     rb_thread_t *th = GET_THREAD();
  226:     volatile VALUE wrapper = th->top_wrapper;
  227:     volatile VALUE self = th->top_self;
  228:     volatile int parse_in_eval;
  229:     volatile int loaded = Qfalse;
  230: #ifndef __GNUC__
  231:     rb_thread_t *volatile th0 = th;
  232: #endif
  233: 
  234:     FilePathValue(fname);
  235:     fname = rb_str_new4(fname);
  236:     tmp = rb_find_file(fname);
  237:     if (!tmp) {
  238:         load_failed(fname);
  239:     }
  240:     RB_GC_GUARD(fname) = rb_str_new4(tmp);
  241: 
  242:     th->errinfo = Qnil; /* ensure */
  243: 
  244:     if (!wrap) {
  245:         rb_secure(4);          /* should alter global state */
  246:         th->top_wrapper = 0;
  247:     }
  248:     else {
  249:         /* load in anonymous module as toplevel */
  250:         th->top_self = rb_obj_clone(rb_vm_top_self());
  251:         th->top_wrapper = rb_module_new();
  252:         rb_extend_object(th->top_self, th->top_wrapper);
  253:     }
  254: 
  255:     parse_in_eval = th->parse_in_eval;
  256:     PUSH_TAG();
  257:     state = EXEC_TAG();
  258:     if (state == 0) {
  259:         NODE *node;
  260:         VALUE iseq;
  261: 
  262:         th->parse_in_eval++;
  263:         node = (NODE *)rb_load_file(RSTRING_PTR(fname));
  264:         th->parse_in_eval--;
  265:         loaded = Qtrue;
  266:         iseq = rb_iseq_new(node, rb_str_new2("<top (required)>"),
  267:                            fname, Qfalse, ISEQ_TYPE_TOP);
  268:         rb_iseq_eval(iseq);
  269:     }
  270:     POP_TAG();
  271: 
  272: #ifndef __GNUC__
  273:     th = th0;
  274:     fname = RB_GC_GUARD(fname);
  275: #endif
  276:     th->parse_in_eval = parse_in_eval;
  277:     th->top_self = self;
  278:     th->top_wrapper = wrapper;
  279: 
  280:     if (!loaded) {
  281:         rb_exc_raise(GET_THREAD()->errinfo);
  282:     }
  283:     if (state) {
  284:         vm_jump_tag_but_local_jump(state, Qundef);
  285:     }
  286: 
  287:     if (!NIL_P(GET_THREAD()->errinfo)) {
  288:         /* exception during load */
  289:         rb_exc_raise(th->errinfo);
  290:     }
  291: }
  292: 
  293: void
  294: rb_load_protect(VALUE fname, int wrap, int *state)
  295: {
  296:     int status;
  297: 
  298:     PUSH_TAG();
  299:     if ((status = EXEC_TAG()) == 0) {
  300:         rb_load(fname, wrap);
  301:     }
  302:     POP_TAG();
  303:     if (state)
  304:         *state = status;
  305: }
  306: 
  307: /*
  308:  *  call-seq:
  309:  *     load(filename, wrap=false)   => true
  310:  *  
  311:  *  Loads and executes the Ruby
  312:  *  program in the file _filename_. If the filename does not
  313:  *  resolve to an absolute path, the file is searched for in the library
  314:  *  directories listed in <code>$:</code>. If the optional _wrap_
  315:  *  parameter is +true+, the loaded script will be executed
  316:  *  under an anonymous module, protecting the calling program's global
  317:  *  namespace. In no circumstance will any local variables in the loaded
  318:  *  file be propagated to the loading environment.
  319:  */
  320: 
  321: static VALUE
  322: rb_f_load(int argc, VALUE *argv)
  323: {
  324:     VALUE fname, wrap;
  325: 
  326:     rb_scan_args(argc, argv, "11", &fname, &wrap);
  327:     rb_load(fname, RTEST(wrap));
  328:     return Qtrue;
  329: }
  330: 
  331: static char *
  332: load_lock(const char *ftptr)
  333: {
  334:     st_data_t data;
  335:     st_table *loading_tbl = get_loading_table();
  336: 
  337:     if (!loading_tbl || !st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
  338:         /* loading ruby library should be serialized. */
  339:         if (!loading_tbl) {
  340:             GET_VM()->loading_table = loading_tbl = st_init_strtable();
  341:         }
  342:         /* partial state */
  343:         ftptr = ruby_strdup(ftptr);
  344:         data = (st_data_t)rb_barrier_new();
  345:         st_insert(loading_tbl, (st_data_t)ftptr, data);
  346:         return (char *)ftptr;
  347:     }
  348:     return RTEST(rb_barrier_wait((VALUE)data)) ? (char *)ftptr : 0;
  349: }
  350: 
  351: static void
  352: load_unlock(const char *ftptr)
  353: {
  354:     if (ftptr) {
  355:         st_data_t key = (st_data_t)ftptr;
  356:         st_data_t data;
  357:         st_table *loading_tbl = get_loading_table();
  358: 
  359:         if (st_delete(loading_tbl, &key, &data)) {
  360:             free((char *)key);
  361:             rb_barrier_release((VALUE)data);
  362:         }
  363:     }
  364: }
  365: 
  366: 
  367: /*
  368:  *  call-seq:
  369:  *     require(string)    => true or false
  370:  *  
  371:  *  Ruby tries to load the library named _string_, returning
  372:  *  +true+ if successful. If the filename does not resolve to
  373:  *  an absolute path, it will be searched for in the directories listed
  374:  *  in <code>$:</code>. If the file has the extension ``.rb'', it is
  375:  *  loaded as a source file; if the extension is ``.so'', ``.o'', or
  376:  *  ``.dll'', or whatever the default shared library extension is on
  377:  *  the current platform, Ruby loads the shared library as a Ruby
  378:  *  extension. Otherwise, Ruby tries adding ``.rb'', ``.so'', and so on
  379:  *  to the name. The name of the loaded feature is added to the array in
  380:  *  <code>$"</code>. A feature will not be loaded if it's name already
  381:  *  appears in <code>$"</code>. However, the file name is not converted
  382:  *  to an absolute path, so that ``<code>require 'a';require
  383:  *  './a'</code>'' will load <code>a.rb</code> twice.
  384:  *     
  385:  *     require "my-library.rb"
  386:  *     require "db-driver"
  387:  */
  388: 
  389: VALUE
  390: rb_f_require(VALUE obj, VALUE fname)
  391: {
  392:     return rb_require_safe(fname, rb_safe_level());
  393: }
  394: 
  395: static int
  396: search_required(VALUE fname, volatile VALUE *path)
  397: {
  398:     VALUE tmp;
  399:     char *ext, *ftptr;
  400:     int type, ft = 0;
  401:     const char *loading;
  402: 
  403:     *path = 0;
  404:     ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
  405:     if (ext && !strchr(ext, '/')) {
  406:         if (IS_RBEXT(ext)) {
  407:             if (rb_feature_p(ftptr, ext, Qtrue, Qfalse, &loading)) {
  408:                 if (loading) *path = rb_str_new2(loading);
  409:                 return 'r';
  410:             }
  411:             if ((tmp = rb_find_file(fname)) != 0) {
  412:                 tmp = rb_file_expand_path(tmp, Qnil);
  413:                 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
  414:                 if (!rb_feature_p(ftptr, ext, Qtrue, Qtrue, 0))
  415:                     *path = tmp;
  416:                 return 'r';
  417:             }
  418:             return 0;
  419:         }
  420:         else if (IS_SOEXT(ext)) {
  421:             if (rb_feature_p(ftptr, ext, Qfalse, Qfalse, &loading)) {
  422:                 if (loading) *path = rb_str_new2(loading);
  423:                 return 's';
  424:             }
  425:             tmp = rb_str_new(RSTRING_PTR(fname), ext - RSTRING_PTR(fname));
  426: #ifdef DLEXT2
  427:             OBJ_FREEZE(tmp);
  428:             if (rb_find_file_ext(&tmp, loadable_ext + 1)) {
  429:                 tmp = rb_file_expand_path(tmp, Qnil);
  430:                 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
  431:                 if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0))
  432:                     *path = tmp;
  433:                 return 's';
  434:             }
  435: #else
  436:             rb_str_cat2(tmp, DLEXT);
  437:             OBJ_FREEZE(tmp);
  438:             if ((tmp = rb_find_file(tmp)) != 0) {
  439:                 tmp = rb_file_expand_path(tmp, Qnil);
  440:                 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
  441:                 if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0))
  442:                     *path = tmp;
  443:                 return 's';
  444:             }
  445: #endif
  446:         }
  447:         else if (IS_DLEXT(ext)) {
  448:             if (rb_feature_p(ftptr, ext, Qfalse, Qfalse, &loading)) {
  449:                 if (loading) *path = rb_str_new2(loading);
  450:                 return 's';
  451:             }
  452:             if ((tmp = rb_find_file(fname)) != 0) {
  453:                 tmp = rb_file_expand_path(tmp, Qnil);
  454:                 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
  455:                 if (!rb_feature_p(ftptr, ext, Qfalse, Qtrue, 0))
  456:                     *path = tmp;
  457:                 return 's';
  458:             }
  459:         }
  460:     }
  461:     else if ((ft = rb_feature_p(ftptr, 0, Qfalse, Qfalse, &loading)) == 'r') {
  462:         if (loading) *path = rb_str_new2(loading);
  463:         return 'r';
  464:     }
  465:     tmp = fname;
  466:     type = rb_find_file_ext(&tmp, loadable_ext);
  467:     tmp = rb_file_expand_path(tmp, Qnil);
  468:     switch (type) {
  469:       case 0:
  470:         if (ft)
  471:             break;
  472:         ftptr = RSTRING_PTR(tmp);
  473:         return rb_feature_p(ftptr, 0, Qfalse, Qtrue, 0);
  474: 
  475:       default:
  476:         if (ft)
  477:             break;
  478:       case 1:
  479:         ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
  480:         if (rb_feature_p(ftptr, ext, !--type, Qtrue, &loading) && !loading)
  481:             break;
  482:         *path = tmp;
  483:     }
  484:     return type ? 's' : 'r';
  485: }
  486: 
  487: static void
  488: load_failed(VALUE fname)
  489: {
  490:     rb_raise(rb_eLoadError, "no such file to load -- %s",
  491:              RSTRING_PTR(fname));
  492: }
  493: 
  494: static VALUE
  495: load_ext(VALUE path)
  496: {
  497:     SCOPE_SET(NOEX_PUBLIC);
  498:     return (VALUE)dln_load(RSTRING_PTR(path));
  499: }
  500: 
  501: VALUE
  502: rb_require_safe(VALUE fname, int safe)
  503: {
  504:     VALUE result = Qnil;
  505:     rb_thread_t *th = GET_THREAD();
  506:     volatile VALUE errinfo = th->errinfo;
  507:     int state;
  508:     struct {
  509:         int safe;
  510:     } volatile saved;
  511:     char *volatile ftptr = 0;
  512: 
  513:     FilePathValue(fname);
  514:     RB_GC_GUARD(fname) = rb_str_new4(fname);
  515:     PUSH_TAG();
  516:     saved.safe = rb_safe_level();
  517:     if ((state = EXEC_TAG()) == 0) {
  518:         VALUE path;
  519:         long handle;
  520:         int found;
  521: 
  522:         rb_set_safe_level_force(safe);
  523:         found = search_required(fname, &path);
  524:         if (found) {
  525:             if (!path || !(ftptr = load_lock(RSTRING_PTR(path)))) {
  526:                 result = Qfalse;
  527:             }
  528:             else {
  529:                 rb_set_safe_level_force(0);
  530:                 switch (found) {
  531:                   case 'r':
  532:                     rb_load(path, 0);
  533:                     break;
  534: 
  535:                   case 's':
  536:                     handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
  537:                                                     path, 0, path);
  538:                     rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
  539:                     break;
  540:                 }
  541:                 rb_provide_feature(path);
  542:                 result = Qtrue;
  543:             }
  544:         }
  545:     }
  546:     POP_TAG();
  547:     load_unlock(ftptr);
  548: 
  549:     rb_set_safe_level_force(saved.safe);
  550:     if (state) {
  551:         JUMP_TAG(state);
  552:     }
  553: 
  554:     if (NIL_P(result)) {
  555:         load_failed(fname);
  556:     }
  557: 
  558:     th->errinfo = errinfo;
  559: 
  560:     return result;
  561: }
  562: 
  563: VALUE
  564: rb_require(const char *fname)
  565: {
  566:     VALUE fn = rb_str_new2(fname);
  567:     OBJ_FREEZE(fn);
  568:     return rb_require_safe(fn, rb_safe_level());
  569: }
  570: 
  571: static VALUE
  572: init_ext_call(VALUE arg)
  573: {
  574:     SCOPE_SET(NOEX_PUBLIC);
  575:     (*(void (*)(void))arg)();
  576:     return Qnil;
  577: }
  578: 
  579: void
  580: ruby_init_ext(const char *name, void (*init)(void))
  581: {
  582:     if (load_lock(name)) {
  583:         rb_vm_call_cfunc(rb_vm_top_self(), init_ext_call, (VALUE)init,
  584:                          0, rb_str_new2(name));
  585:         rb_provide(name);
  586:         load_unlock(name);
  587:     }
  588: }
  589: 
  590: /*
  591:  *  call-seq:
  592:  *     mod.autoload(name, filename)   => nil
  593:  *  
  594:  *  Registers _filename_ to be loaded (using <code>Kernel::require</code>)
  595:  *  the first time that _module_ (which may be a <code>String</code> or
  596:  *  a symbol) is accessed in the namespace of _mod_.
  597:  *     
  598:  *     module A
  599:  *     end