9#include "internal/error.h"
14#include "internal/variable.h"
20static VALUE ruby_dln_librefs;
22#define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
23#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
25#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0 || strcmp((e), DLEXT2) == 0)
27#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
30static const char *
const loadable_ext[] = {
38static const char *
const ruby_ext[] = {
56rb_construct_expanded_load_path(
enum expand_type type,
int *has_relative,
int *has_non_cache)
66 VALUE path, as_str, expanded_path;
67 int is_string, non_cache;
70 is_string = RB_TYPE_P(path,
T_STRING) ? 1 : 0;
71 non_cache = !is_string ? 1 : 0;
79 (!as_cstr[0] || as_cstr[0] !=
'~')) ||
88 if (!*has_non_cache && non_cache)
95 if (
NIL_P(expanded_path)) expanded_path = as_str;
111 int has_relative = 0, has_non_cache = 0;
112 rb_construct_expanded_load_path(
EXPAND_ALL, &has_relative, &has_non_cache);
116 else if (has_non_cache) {
125 int has_relative = 1, has_non_cache = 1;
128 &has_relative, &has_non_cache);
131 int has_relative = 1, has_non_cache = 1;
138 &has_relative, &has_non_cache);
143 &has_relative, &has_non_cache);
150load_path_getter(
ID id,
VALUE * p)
157get_loaded_features(
void)
159 return GET_VM()->loaded_features;
163get_LOADED_FEATURES(
ID _x,
VALUE *_y)
165 return get_loaded_features();
169reset_loaded_features_snapshot(
void)
176get_loaded_features_index_raw(
void)
178 return GET_VM()->loaded_features_index;
182get_loading_table(
void)
184 return GET_VM()->loading_table;
188feature_key(
const char *
str,
size_t len)
194is_rbext_path(
VALUE feature_path)
198 if (
len <= rbext_len)
return false;
210 short_feature_key = feature_key(
str,
len);
212 features_index = get_loaded_features_index_raw();
215 if (
NIL_P(this_feature_index)) {
218 else if (RB_TYPE_P(this_feature_index,
T_FIXNUM)) {
219 VALUE loaded_features = get_loaded_features();
221 VALUE feature_indexes[2];
222 int top = (rb && !is_rbext_path(this_feature_path)) ? 1 : 0;
223 feature_indexes[
top^0] = this_feature_index;
233 Check_Type(this_feature_index,
T_ARRAY);
235 VALUE loaded_features = get_loaded_features();
236 for (
long i = 0; i <
RARRAY_LEN(this_feature_index); ++i) {
239 Check_Type(this_feature_path,
T_STRING);
240 if (!is_rbext_path(this_feature_path)) {
270 const char *feature_str, *feature_end, *ext, *p;
276 for (ext = feature_end; ext > feature_str; ext--)
277 if (*ext ==
'.' || *ext ==
'/')
286 p = ext ? ext : feature_end;
289 while (p >= feature_str && *p !=
'/')
294 features_index_add_single(p + 1, feature_end - p - 1,
offset,
false);
296 features_index_add_single(p + 1, ext - p - 1,
offset, rb);
299 features_index_add_single(feature_str, feature_end - feature_str,
offset,
false);
301 features_index_add_single(feature_str, ext - feature_str,
offset, rb);
317get_loaded_features_index(
void)
335 features_index_add(as_str,
INT2FIX(i));
337 reset_loaded_features_snapshot();
354loaded_feature_path(
const char *
name,
long vlen,
const char *feature,
long len,
361 if (vlen <
len+1)
return 0;
366 for (e =
name + vlen;
name != e && *e !=
'.' && *e !=
'/'; --e);
369 strncmp(e-
len, feature,
len))
373 if (plen > 0 &&
name[plen-1] !=
'/') {
384 if (plen > 0) --plen;
390 if (n != plen)
continue;
391 if (n && strncmp(
name, s, n))
continue;
408 const char *s = (
const char *)v;
418rb_feature_p(
const char *feature,
const char *ext,
int rb,
int expanded,
const char **fn)
422 long i,
len, elen, n;
423 st_table *loading_tbl, *features_index;
432 type = rb ?
'r' :
's';
439 features = get_loaded_features();
440 features_index = get_loaded_features_index();
442 key = feature_key(feature,
strlen(feature));
470 if (!
NIL_P(this_feature_index)) {
474 if (RB_TYPE_P(this_feature_index,
T_ARRAY)) {
475 if (i >=
RARRAY_LEN(this_feature_index))
break;
480 entry = this_feature_index;
487 if (strncmp(
f, feature,
len) != 0) {
488 if (expanded)
continue;
495 if (!*(e =
f +
len)) {
499 if (*e !=
'.')
continue;
503 if ((rb || !ext) && (
IS_RBEXT(e))) {
509 loading_tbl = get_loading_table();
519 if ((
f = fs.result) != 0) {
525 if (fn) *fn = (
const char*)data;
531 static const char so_ext[][4] = {
535 if (ext && *ext)
return 0;
539 for (i = 0; (e = loadable_ext[i]) != 0; i++) {
543 if (fn) *fn = (
const char*)data;
544 return i ?
's' :
'r';
547 for (i = 0; i <
numberof(so_ext); i++) {
551 if (fn) *fn = (
const char*)data;
560 if (!ext)
return 'u';
573 const char *ext =
strrchr(feature,
'.');
576 if (*feature ==
'.' &&
577 (feature[1] ==
'/' || strncmp(feature+1,
"./", 2) == 0)) {
581 if (ext && !
strchr(ext,
'/')) {
583 if (rb_feature_p(feature, ext,
TRUE,
FALSE, loading))
return TRUE;
587 if (rb_feature_p(feature, ext,
FALSE,
FALSE, loading))
return TRUE;
591 if (rb_feature_p(feature, 0,
TRUE,
FALSE, loading))
598rb_provide_feature(
VALUE feature)
602 features = get_loaded_features();
605 "$LOADED_FEATURES is frozen; cannot append feature");
609 get_loaded_features_index();
612 reset_loaded_features_snapshot();
637 rb_exec_event_hook_script_compiled(ec, iseq,
Qnil);
662 load_iseq_eval(ec, fname);
688rb_load_internal(
VALUE fname,
int wrap)
693 state = load_wrapping(ec, fname);
696 load_iseq_eval(ec, fname);
698 raise_load_if_failed(ec,
state);
705 if (!tmp) load_failed(fname);
706 rb_load_internal(tmp, wrap);
756 VALUE fname, wrap, path, orig_fname;
767 load_failed(orig_fname);
770 rb_load_internal(path,
RTEST(wrap));
778load_lock(
const char *ftptr)
781 st_table *loading_tbl = get_loading_table();
788 return (
char *)ftptr;
792 void (*init)(void) = memo->
u3.
func;
799 VALUE warning =
rb_warning_string(
"loading in progress, circular require considered harmful - %s", ftptr);
808 return (
char *)ftptr;
830load_unlock(
const char *ftptr,
int done)
834 st_table *loading_tbl = get_loading_table();
904typedef int (*
feature_func)(
const char *feature,
const char *ext,
int rb,
int expanded,
const char **fn);
916 if (ext && !
strchr(ext,
'/')) {
918 if (rb_feature_p(ftptr, ext,
TRUE,
FALSE, &loading)) {
924 if (!rb_feature_p(ftptr, ext,
TRUE,
TRUE, &loading) || loading)
931 if (rb_feature_p(ftptr, ext,
FALSE,
FALSE, &loading)) {
940 if (!rb_feature_p(ftptr, ext,
FALSE,
TRUE, &loading) || loading)
949 if (!rb_feature_p(ftptr, ext,
FALSE,
TRUE, &loading) || loading)
956 if (rb_feature_p(ftptr, ext,
FALSE,
FALSE, &loading)) {
962 if (!rb_feature_p(ftptr, ext,
FALSE,
TRUE, &loading) || loading)
968 else if ((ft = rb_feature_p(ftptr, 0,
FALSE,
FALSE, &loading)) ==
'r') {
977 goto statically_linked;
979 return rb_feature_p(ftptr, 0,
FALSE,
TRUE, 0);
983 goto statically_linked;
988 if (rb_feature_p(ftptr, ext, !--
type,
TRUE, &loading) && !loading)
992 return type ?
's' :
'r';
1000load_failed(
VALUE fname)
1013no_feature_p(
const char *feature,
const char *ext,
int rb,
int expanded,
const char **fn)
1028 found = search_required(path, &path, no_feature_p);
1060 GET_THREAD()->ext_config.ractor_safe = flag;
1073 volatile int result = -1;
1079 char *
volatile ftptr = 0;
1081 volatile bool reset_ext_config =
false;
1096 found = search_required(path, &path, rb_feature_p);
1100 if (!path || !(ftptr = load_lock(
RSTRING_PTR(path)))) {
1109 load_iseq_eval(ec, path);
1113 reset_ext_config =
true;
1114 ext_config_push(th, &prev_ext_config);
1129 if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1137 else if (exception) {
1156 if (result ==
TAG_RETURN) rb_provide_feature(path);
1168 return require_internal(ec, fname, 1);
1177 int result = require_internal(ec,
str, 0);
1179 return result ==
TAG_RETURN ? 1 : result ? -1 : 0;
1186 int result = require_internal(ec, fname, 1);
1207 const char *
name = (
char *)*
key;
1219RUBY_FUNC_EXPORTED
void
1222 st_table *loading_tbl = get_loading_table();
1310 return rb_mod_autoload(klass,
sym,
file);
1332 return rb_mod_autoload_p(
argc,
argv, klass);
1339 static const char var_load_path[] =
"$:";
1340 ID id_load_path =
rb_intern2(var_load_path,
sizeof(var_load_path)-1);
void rb_ary_store(VALUE ary, long idx, VALUE val)
VALUE rb_ary_push(VALUE ary, VALUE item)
void rb_ary_free(VALUE ary)
VALUE rb_ary_replace(VALUE copy, VALUE orig)
VALUE rb_ary_shared_with_p(VALUE ary1, VALUE ary2)
VALUE rb_ary_tmp_new(long capa)
VALUE rb_ary_cat(VALUE ary, const VALUE *argv, long len)
VALUE rb_ary_entry(VALUE ary, long offset)
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
VALUE rb_dir_getwd_ospath(void)
char * strchr(char *, char)
void * dln_load(const char *file)
char str[HTML_ESCAPE_MAX_LEN+1]
VALUE rb_vm_call_cfunc(VALUE recv, VALUE(*func)(VALUE), VALUE arg, VALUE block_handler, VALUE filename)
#define EC_JUMP_TAG(ec, st)
char * strrchr(const char *, const char)
void rb_vm_jump_tag_but_local_jump(int)
VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val)
#define RSTRING_LEN(string)
#define RSTRING_PTR(string)
VALUE rb_get_path(VALUE obj)
VALUE rb_get_path_check_convert(VALUE obj)
VALUE rb_find_file(VALUE path)
VALUE rb_file_expand_path_fast(VALUE fname, VALUE dname)
VALUE rb_str_encode_ospath(VALUE path)
int rb_file_load_ok(const char *path)
int rb_is_absolute_path(const char *path)
int rb_find_file_ext(VALUE *filep, const char *const *ext)
VALUE rb_check_realpath(VALUE basedir, VALUE path, rb_encoding *enc)
VALUE rb_get_path_check_to_string(VALUE obj)
VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict)
VALUE rb_file_dirname(VALUE fname)
VALUE rb_file_absolute_path(VALUE fname, VALUE dname)
void rb_gc_register_mark_object(VALUE obj)
Inform the garbage collector that object is a live Ruby object that should not be moved.
void rb_extend_object(VALUE obj, VALUE module)
Extend the object with the module.
VALUE rb_module_new(void)
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
void rb_raise(VALUE exc, const char *fmt,...)
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
void rb_set_errinfo(VALUE err)
Sets the current exception ($!) to the given value.
VALUE rb_warning_string(const char *fmt,...)
void rb_load_fail(VALUE path, const char *err)
void rb_warn(const char *fmt,...)
void rb_loaderror(const char *fmt,...)
void rb_warning(const char *fmt,...)
VALUE rb_cModule
Module class.
VALUE rb_class_real(VALUE)
Looks up the nearest ancestor of cl, skipping singleton classes or module inclusions.
VALUE rb_obj_clone(VALUE)
Almost same as Object::clone.
VALUE rb_obj_freeze(VALUE)
Make the object unmodifiable.
#define MEMO_NEW(a, b, c)
VALUE rb_str_freeze(VALUE)
VALUE rb_str_resize(VALUE, long)
VALUE rb_filesystem_str_new_cstr(const char *)
VALUE rb_str_equal(VALUE str1, VALUE str2)
VALUE rb_str_tmp_new(long)
VALUE rb_str_subseq(VALUE, long, long)
#define rb_strlen_lit(str)
VALUE rb_str_append(VALUE, VALUE)
#define rb_str_new_cstr(str)
void rb_alias_variable(ID, ID)
ID rb_intern2(const char *, long)
ID rb_intern(const char *)
ID rb_check_id(volatile VALUE *)
Returns ID for the given name if it is interned already, or 0.
rb_gvar_setter_t rb_gvar_readonly_setter
size_t strlcpy(char *, const char *, size_t)
char * ruby_strdup(const char *)
Internal header for File.
Internal header for require.
Internal header for the parser.
void * rb_parser_load_file(VALUE parser, VALUE name)
VALUE rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb_encoding *enc)
#define rb_fstring_lit(str)
Internal header for Thread.
VALUE rb_thread_shield_new(void)
VALUE rb_thread_shield_destroy(VALUE self)
VALUE rb_thread_shield_wait(VALUE self)
VALUE rb_thread_shield_release(VALUE self)
VALUE rb_autoload_at_p(VALUE, ID, int)
void rb_autoload_str(VALUE mod, ID id, VALUE file)
void rb_backtrace_each(VALUE(*iter)(VALUE recv, VALUE str), VALUE output)
#define RUBY_DTRACE_HOOK(name, arg)
VALUE rb_vm_top_self(void)
VALUE rb_current_realfilepath(void)
#define rb_ary_new_from_args(...)
#define rb_fstring_cstr(...)
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
const rb_iseq_t * rb_iseq_load_iseq(VALUE fname)
rb_iseq_t * rb_iseq_new_top(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent)
VALUE rb_require_string(VALUE fname)
int(* feature_func)(const char *feature, const char *ext, int rb, int expanded, const char **fn)
void rb_provide(const char *feature)
void rb_load(VALUE fname, int wrap)
void rb_load_protect(VALUE fname, int wrap, int *pstate)
VALUE rb_f_require(VALUE obj, VALUE fname)
void rb_ext_ractor_safe(bool flag)
int rb_require_internal(VALUE fname)
VALUE rb_f_require_relative(VALUE obj, VALUE fname)
void ruby_init_ext(const char *name, void(*init)(void))
int rb_feature_provided(const char *feature, const char **loading)
VALUE rb_resolve_feature_path(VALUE klass, VALUE fname)
VALUE rb_require(const char *fname)
int rb_provided(const char *feature)
int ruby_require_internal(const char *fname, unsigned int len)
VALUE rb_get_expanded_load_path(void)
#define MEMCPY(p1, p2, type, n)
#define MEMMOVE(p1, p2, type, n)
void rb_scope_visibility_set(rb_method_visibility_t)
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
VALUE type(ANYARGS)
ANYARGS-ed function type.
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
void rb_ast_dispose(rb_ast_t *ast)
#define RARRAY_AREF(a, i)
#define RARRAY_CONST_PTR_TRANSIENT
VALUE rb_parser_new(void)
VALUE rb_parser_set_context(VALUE vparser, const struct rb_iseq_struct *base, int main)
#define StringValuePtr(v)
size_t strlen(const char *)
struct rb_ext_config ext_config
VALUE load_path_check_cache
VALUE loaded_features_snapshot
struct st_table * loaded_features_index
VALUE rb_iseq_eval(const rb_iseq_t *iseq)
#define VM_BLOCK_HANDLER_NONE