Ruby 3.0.5p211 (2022-11-24 revision ba5cf0f7c52d4d35cc6a173c89eda98ceffa2dcf)
load.c
Go to the documentation of this file.
1/*
2 * load methods from eval.c
3 */
4
5#include "dln.h"
6#include "eval_intern.h"
7#include "internal.h"
8#include "internal/dir.h"
9#include "internal/error.h"
10#include "internal/file.h"
11#include "internal/load.h"
12#include "internal/parse.h"
13#include "internal/thread.h"
14#include "internal/variable.h"
15#include "iseq.h"
16#include "probes.h"
17#include "ruby/encoding.h"
18#include "ruby/util.h"
19
20static VALUE ruby_dln_librefs;
21
22#define IS_RBEXT(e) (strcmp((e), ".rb") == 0)
23#define IS_SOEXT(e) (strcmp((e), ".so") == 0 || strcmp((e), ".o") == 0)
24#ifdef DLEXT2
25#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0 || strcmp((e), DLEXT2) == 0)
26#else
27#define IS_DLEXT(e) (strcmp((e), DLEXT) == 0)
28#endif
29
30static const char *const loadable_ext[] = {
31 ".rb", DLEXT,
32#ifdef DLEXT2
33 DLEXT2,
34#endif
35 0
36};
37
38static const char *const ruby_ext[] = {
39 ".rb",
40 0
41};
42
48};
49
50/* Construct expanded load path and store it to cache.
51 We rebuild load path partially if the cache is invalid.
52 We don't cache non string object and expand it every time. We ensure that
53 string objects in $LOAD_PATH are frozen.
54 */
55static void
56rb_construct_expanded_load_path(enum expand_type type, int *has_relative, int *has_non_cache)
57{
58 rb_vm_t *vm = GET_VM();
59 VALUE load_path = vm->load_path;
60 VALUE expanded_load_path = vm->expanded_load_path;
61 VALUE ary;
62 long i;
63
64 ary = rb_ary_tmp_new(RARRAY_LEN(load_path));
65 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
66 VALUE path, as_str, expanded_path;
67 int is_string, non_cache;
68 char *as_cstr;
69 as_str = path = RARRAY_AREF(load_path, i);
70 is_string = RB_TYPE_P(path, T_STRING) ? 1 : 0;
71 non_cache = !is_string ? 1 : 0;
72 as_str = rb_get_path_check_to_string(path);
73 as_cstr = RSTRING_PTR(as_str);
74
75 if (!non_cache) {
76 if ((type == EXPAND_RELATIVE &&
77 rb_is_absolute_path(as_cstr)) ||
78 (type == EXPAND_HOME &&
79 (!as_cstr[0] || as_cstr[0] != '~')) ||
81 /* Use cached expanded path. */
82 rb_ary_push(ary, RARRAY_AREF(expanded_load_path, i));
83 continue;
84 }
85 }
86 if (!*has_relative && !rb_is_absolute_path(as_cstr))
87 *has_relative = 1;
88 if (!*has_non_cache && non_cache)
89 *has_non_cache = 1;
90 /* Freeze only string object. We expand other objects every time. */
91 if (is_string)
92 rb_str_freeze(path);
93 as_str = rb_get_path_check_convert(as_str);
94 expanded_path = rb_check_realpath(Qnil, as_str, NULL);
95 if (NIL_P(expanded_path)) expanded_path = as_str;
96 rb_ary_push(ary, rb_fstring(expanded_path));
97 }
98 rb_obj_freeze(ary);
99 vm->expanded_load_path = ary;
101}
102
103VALUE
105{
106 rb_vm_t *vm = GET_VM();
107 const VALUE non_cache = Qtrue;
108
110 /* The load path was modified. Rebuild the expanded load path. */
111 int has_relative = 0, has_non_cache = 0;
112 rb_construct_expanded_load_path(EXPAND_ALL, &has_relative, &has_non_cache);
113 if (has_relative) {
115 }
116 else if (has_non_cache) {
117 /* Non string object. */
118 vm->load_path_check_cache = non_cache;
119 }
120 else {
121 vm->load_path_check_cache = 0;
122 }
123 }
124 else if (vm->load_path_check_cache == non_cache) {
125 int has_relative = 1, has_non_cache = 1;
126 /* Expand only non-cacheable objects. */
127 rb_construct_expanded_load_path(EXPAND_NON_CACHE,
128 &has_relative, &has_non_cache);
129 }
130 else if (vm->load_path_check_cache) {
131 int has_relative = 1, has_non_cache = 1;
133 if (!rb_str_equal(vm->load_path_check_cache, cwd)) {
134 /* Current working directory or filesystem encoding was changed.
135 Expand relative load path and non-cacheable objects again. */
136 vm->load_path_check_cache = cwd;
137 rb_construct_expanded_load_path(EXPAND_RELATIVE,
138 &has_relative, &has_non_cache);
139 }
140 else {
141 /* Expand only tilde (User HOME) and non-cacheable objects. */
142 rb_construct_expanded_load_path(EXPAND_HOME,
143 &has_relative, &has_non_cache);
144 }
145 }
146 return vm->expanded_load_path;
147}
148
149static VALUE
150load_path_getter(ID id, VALUE * p)
151{
152 rb_vm_t *vm = (void *)p;
153 return vm->load_path;
154}
155
156static VALUE
157get_loaded_features(void)
158{
159 return GET_VM()->loaded_features;
160}
161
162static VALUE
163get_LOADED_FEATURES(ID _x, VALUE *_y)
164{
165 return get_loaded_features();
166}
167
168static void
169reset_loaded_features_snapshot(void)
170{
171 rb_vm_t *vm = GET_VM();
173}
174
175static struct st_table *
176get_loaded_features_index_raw(void)
177{
178 return GET_VM()->loaded_features_index;
179}
180
181static st_table *
182get_loading_table(void)
183{
184 return GET_VM()->loading_table;
185}
186
187static st_data_t
188feature_key(const char *str, size_t len)
189{
190 return st_hash(str, len, 0xfea7009e);
191}
192
193static bool
194is_rbext_path(VALUE feature_path)
195{
196 long len = RSTRING_LEN(feature_path);
197 long rbext_len = rb_strlen_lit(".rb");
198 if (len <= rbext_len) return false;
199 return IS_RBEXT(RSTRING_PTR(feature_path) + len - rbext_len);
200}
201
202static void
203features_index_add_single(const char* str, size_t len, VALUE offset, bool rb)
204{
205 struct st_table *features_index;
206 VALUE this_feature_index = Qnil;
207 st_data_t short_feature_key;
208
209 Check_Type(offset, T_FIXNUM);
210 short_feature_key = feature_key(str, len);
211
212 features_index = get_loaded_features_index_raw();
213 st_lookup(features_index, short_feature_key, (st_data_t *)&this_feature_index);
214
215 if (NIL_P(this_feature_index)) {
216 st_insert(features_index, short_feature_key, (st_data_t)offset);
217 }
218 else if (RB_TYPE_P(this_feature_index, T_FIXNUM)) {
219 VALUE loaded_features = get_loaded_features();
220 VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(this_feature_index));
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;
224 feature_indexes[top^1] = offset;
225 this_feature_index = (VALUE)xcalloc(1, sizeof(struct RArray));
226 RBASIC(this_feature_index)->flags = T_ARRAY; /* fake VALUE, do not mark/sweep */
227 rb_ary_cat(this_feature_index, feature_indexes, numberof(feature_indexes));
228 st_insert(features_index, short_feature_key, (st_data_t)this_feature_index);
229 }
230 else {
231 long pos = -1;
232
233 Check_Type(this_feature_index, T_ARRAY);
234 if (rb) {
235 VALUE loaded_features = get_loaded_features();
236 for (long i = 0; i < RARRAY_LEN(this_feature_index); ++i) {
237 VALUE idx = RARRAY_AREF(this_feature_index, i);
238 VALUE this_feature_path = RARRAY_AREF(loaded_features, FIX2LONG(idx));
239 Check_Type(this_feature_path, T_STRING);
240 if (!is_rbext_path(this_feature_path)) {
241 /* as this_feature_index is a fake VALUE, `push` (which
242 * doesn't wb_unprotect like as rb_ary_splice) first,
243 * then rotate partially. */
244 pos = i;
245 break;
246 }
247 }
248 }
249 rb_ary_push(this_feature_index, offset);
250 if (pos >= 0) {
251 VALUE *ptr = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(this_feature_index);
252 long len = RARRAY_LEN(this_feature_index);
253 MEMMOVE(ptr + pos, ptr + pos + 1, VALUE, len - pos - 1);
254 ptr[pos] = offset;
255 }
256 }
257}
258
259/* Add to the loaded-features index all the required entries for
260 `feature`, located at `offset` in $LOADED_FEATURES. We add an
261 index entry at each string `short_feature` for which
262 feature == "#{prefix}#{short_feature}#{ext}"
263 where `ext` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
264 or ends in '/'. This maintains the invariant that `rb_feature_p()`
265 relies on for its fast lookup.
266*/
267static void
268features_index_add(VALUE feature, VALUE offset)
269{
270 const char *feature_str, *feature_end, *ext, *p;
271 bool rb = false;
272
273 feature_str = StringValuePtr(feature);
274 feature_end = feature_str + RSTRING_LEN(feature);
275
276 for (ext = feature_end; ext > feature_str; ext--)
277 if (*ext == '.' || *ext == '/')
278 break;
279 if (*ext != '.')
280 ext = NULL;
281 else
282 rb = IS_RBEXT(ext);
283 /* Now `ext` points to the only string matching %r{^\.[^./]*$} that is
284 at the end of `feature`, or is NULL if there is no such string. */
285
286 p = ext ? ext : feature_end;
287 while (1) {
288 p--;
289 while (p >= feature_str && *p != '/')
290 p--;
291 if (p < feature_str)
292 break;
293 /* Now *p == '/'. We reach this point for every '/' in `feature`. */
294 features_index_add_single(p + 1, feature_end - p - 1, offset, false);
295 if (ext) {
296 features_index_add_single(p + 1, ext - p - 1, offset, rb);
297 }
298 }
299 features_index_add_single(feature_str, feature_end - feature_str, offset, false);
300 if (ext) {
301 features_index_add_single(feature_str, ext - feature_str, offset, rb);
302 }
303}
304
305static int
306loaded_features_index_clear_i(st_data_t key, st_data_t val, st_data_t arg)
307{
308 VALUE obj = (VALUE)val;
309 if (!SPECIAL_CONST_P(obj)) {
310 rb_ary_free(obj);
311 ruby_sized_xfree((void *)obj, sizeof(struct RArray));
312 }
313 return ST_DELETE;
314}
315
316static st_table *
317get_loaded_features_index(void)
318{
319 VALUE features;
320 int i;
321 rb_vm_t *vm = GET_VM();
322
324 /* The sharing was broken; something (other than us in rb_provide_feature())
325 modified loaded_features. Rebuild the index. */
326 st_foreach(vm->loaded_features_index, loaded_features_index_clear_i, 0);
327 features = vm->loaded_features;
328 for (i = 0; i < RARRAY_LEN(features); i++) {
329 VALUE entry, as_str;
330 as_str = entry = rb_ary_entry(features, i);
331 StringValue(as_str);
332 as_str = rb_fstring(rb_str_freeze(as_str));
333 if (as_str != entry)
334 rb_ary_store(features, i, as_str);
335 features_index_add(as_str, INT2FIX(i));
336 }
337 reset_loaded_features_snapshot();
338 }
339 return vm->loaded_features_index;
340}
341
342/* This searches `load_path` for a value such that
343 name == "#{load_path[i]}/#{feature}"
344 if `feature` is a suffix of `name`, or otherwise
345 name == "#{load_path[i]}/#{feature}#{ext}"
346 for an acceptable string `ext`. It returns
347 `load_path[i].to_str` if found, else 0.
348
349 If type is 's', then `ext` is acceptable only if IS_DLEXT(ext);
350 if 'r', then only if IS_RBEXT(ext); otherwise `ext` may be absent
351 or have any value matching `%r{^\.[^./]*$}`.
352*/
353static VALUE
354loaded_feature_path(const char *name, long vlen, const char *feature, long len,
355 int type, VALUE load_path)
356{
357 long i;
358 long plen;
359 const char *e;
360
361 if (vlen < len+1) return 0;
362 if (strchr(feature, '.') && !strncmp(name+(vlen-len), feature, len)) {
363 plen = vlen - len;
364 }
365 else {
366 for (e = name + vlen; name != e && *e != '.' && *e != '/'; --e);
367 if (*e != '.' ||
368 e-name < len ||
369 strncmp(e-len, feature, len))
370 return 0;
371 plen = e - name - len;
372 }
373 if (plen > 0 && name[plen-1] != '/') {
374 return 0;
375 }
376 if (type == 's' ? !IS_DLEXT(&name[plen+len]) :
377 type == 'r' ? !IS_RBEXT(&name[plen+len]) :
378 0) {
379 return 0;
380 }
381 /* Now name == "#{prefix}/#{feature}#{ext}" where ext is acceptable
382 (possibly empty) and prefix is some string of length plen. */
383
384 if (plen > 0) --plen; /* exclude '.' */
385 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
386 VALUE p = RARRAY_AREF(load_path, i);
387 const char *s = StringValuePtr(p);
388 long n = RSTRING_LEN(p);
389
390 if (n != plen) continue;
391 if (n && strncmp(name, s, n)) continue;
392 return p;
393 }
394 return 0;
395}
396
398 const char *name;
399 long len;
400 int type;
402 const char *result;
403};
404
405static int
406loaded_feature_path_i(st_data_t v, st_data_t b, st_data_t f)
407{
408 const char *s = (const char *)v;
410 VALUE p = loaded_feature_path(s, strlen(s), fp->name, fp->len,
411 fp->type, fp->load_path);
412 if (!p) return ST_CONTINUE;
413 fp->result = s;
414 return ST_STOP;
415}
416
417static int
418rb_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn)
419{
420 VALUE features, this_feature_index = Qnil, v, p, load_path = 0;
421 const char *f, *e;
422 long i, len, elen, n;
423 st_table *loading_tbl, *features_index;
424 st_data_t data;
426 int type;
427
428 if (fn) *fn = 0;
429 if (ext) {
430 elen = strlen(ext);
431 len = strlen(feature) - elen;
432 type = rb ? 'r' : 's';
433 }
434 else {
435 len = strlen(feature);
436 elen = 0;
437 type = 0;
438 }
439 features = get_loaded_features();
440 features_index = get_loaded_features_index();
441
442 key = feature_key(feature, strlen(feature));
443 st_lookup(features_index, key, (st_data_t *)&this_feature_index);
444 /* We search `features` for an entry such that either
445 "#{features[i]}" == "#{load_path[j]}/#{feature}#{e}"
446 for some j, or
447 "#{features[i]}" == "#{feature}#{e}"
448 Here `e` is an "allowed" extension -- either empty or one
449 of the extensions accepted by IS_RBEXT, IS_SOEXT, or
450 IS_DLEXT. Further, if `ext && rb` then `IS_RBEXT(e)`,
451 and if `ext && !rb` then `IS_SOEXT(e) || IS_DLEXT(e)`.
452
453 If `expanded`, then only the latter form (without load_path[j])
454 is accepted. Otherwise either form is accepted, *unless* `ext`
455 is false and an otherwise-matching entry of the first form is
456 preceded by an entry of the form
457 "#{features[i2]}" == "#{load_path[j2]}/#{feature}#{e2}"
458 where `e2` matches %r{^\.[^./]*$} but is not an allowed extension.
459 After a "distractor" entry of this form, only entries of the
460 form "#{feature}#{e}" are accepted.
461
462 In `rb_provide_feature()` and `get_loaded_features_index()` we
463 maintain an invariant that the array `this_feature_index` will
464 point to every entry in `features` which has the form
465 "#{prefix}#{feature}#{e}"
466 where `e` is empty or matches %r{^\.[^./]*$}, and `prefix` is empty
467 or ends in '/'. This includes both match forms above, as well
468 as any distractors, so we may ignore all other entries in `features`.
469 */
470 if (!NIL_P(this_feature_index)) {
471 for (i = 0; ; i++) {
472 VALUE entry;
473 long index;
474 if (RB_TYPE_P(this_feature_index, T_ARRAY)) {
475 if (i >= RARRAY_LEN(this_feature_index)) break;
476 entry = RARRAY_AREF(this_feature_index, i);
477 }
478 else {
479 if (i > 0) break;
480 entry = this_feature_index;
481 }
482 index = FIX2LONG(entry);
483
484 v = RARRAY_AREF(features, index);
485 f = StringValuePtr(v);
486 if ((n = RSTRING_LEN(v)) < len) continue;
487 if (strncmp(f, feature, len) != 0) {
488 if (expanded) continue;
490 if (!(p = loaded_feature_path(f, n, feature, len, type, load_path)))
491 continue;
492 expanded = 1;
493 f += RSTRING_LEN(p) + 1;
494 }
495 if (!*(e = f + len)) {
496 if (ext) continue;
497 return 'u';
498 }
499 if (*e != '.') continue;
500 if ((!rb || !ext) && (IS_SOEXT(e) || IS_DLEXT(e))) {
501 return 's';
502 }
503 if ((rb || !ext) && (IS_RBEXT(e))) {
504 return 'r';
505 }
506 }
507 }
508
509 loading_tbl = get_loading_table();
510 f = 0;
511 if (!expanded) {
512 struct loaded_feature_searching fs;
513 fs.name = feature;
514 fs.len = len;
515 fs.type = type;
516 fs.load_path = load_path ? load_path : rb_get_expanded_load_path();
517 fs.result = 0;
518 st_foreach(loading_tbl, loaded_feature_path_i, (st_data_t)&fs);
519 if ((f = fs.result) != 0) {
520 if (fn) *fn = f;
521 goto loading;
522 }
523 }
524 if (st_get_key(loading_tbl, (st_data_t)feature, &data)) {
525 if (fn) *fn = (const char*)data;
526 goto loading;
527 }
528 else {
529 VALUE bufstr;
530 char *buf;
531 static const char so_ext[][4] = {
532 ".so", ".o",
533 };
534
535 if (ext && *ext) return 0;
536 bufstr = rb_str_tmp_new(len + DLEXT_MAXLEN);
537 buf = RSTRING_PTR(bufstr);
538 MEMCPY(buf, feature, char, len);
539 for (i = 0; (e = loadable_ext[i]) != 0; i++) {
540 strlcpy(buf + len, e, DLEXT_MAXLEN + 1);
541 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
542 rb_str_resize(bufstr, 0);
543 if (fn) *fn = (const char*)data;
544 return i ? 's' : 'r';
545 }
546 }
547 for (i = 0; i < numberof(so_ext); i++) {
548 strlcpy(buf + len, so_ext[i], DLEXT_MAXLEN + 1);
549 if (st_get_key(loading_tbl, (st_data_t)buf, &data)) {
550 rb_str_resize(bufstr, 0);
551 if (fn) *fn = (const char*)data;
552 return 's';
553 }
554 }
555 rb_str_resize(bufstr, 0);
556 }
557 return 0;
558
559 loading:
560 if (!ext) return 'u';
561 return !IS_RBEXT(ext) ? 's' : 'r';
562}
563
564int
565rb_provided(const char *feature)
566{
567 return rb_feature_provided(feature, 0);
568}
569
570int
571rb_feature_provided(const char *feature, const char **loading)
572{
573 const char *ext = strrchr(feature, '.');
574 VALUE fullpath = 0;
575
576 if (*feature == '.' &&
577 (feature[1] == '/' || strncmp(feature+1, "./", 2) == 0)) {
579 feature = RSTRING_PTR(fullpath);
580 }
581 if (ext && !strchr(ext, '/')) {
582 if (IS_RBEXT(ext)) {
583 if (rb_feature_p(feature, ext, TRUE, FALSE, loading)) return TRUE;
584 return FALSE;
585 }
586 else if (IS_SOEXT(ext) || IS_DLEXT(ext)) {
587 if (rb_feature_p(feature, ext, FALSE, FALSE, loading)) return TRUE;
588 return FALSE;
589 }
590 }
591 if (rb_feature_p(feature, 0, TRUE, FALSE, loading))
592 return TRUE;
593 RB_GC_GUARD(fullpath);
594 return FALSE;
595}
596
597static void
598rb_provide_feature(VALUE feature)
599{
600 VALUE features;
601
602 features = get_loaded_features();
603 if (OBJ_FROZEN(features)) {
605 "$LOADED_FEATURES is frozen; cannot append feature");
606 }
607 rb_str_freeze(feature);
608
609 get_loaded_features_index();
610 rb_ary_push(features, rb_fstring(feature));
611 features_index_add(feature, INT2FIX(RARRAY_LEN(features)-1));
612 reset_loaded_features_snapshot();
613}
614
615void
616rb_provide(const char *feature)
617{
618 rb_provide_feature(rb_fstring_cstr(feature));
619}
620
621NORETURN(static void load_failed(VALUE));
622
623static inline void
624load_iseq_eval(rb_execution_context_t *ec, VALUE fname)
625{
626 const rb_iseq_t *iseq = rb_iseq_load_iseq(fname);
627
628 if (!iseq) {
629 rb_ast_t *ast;
630 VALUE parser = rb_parser_new();
632 ast = (rb_ast_t *)rb_parser_load_file(parser, fname);
633 iseq = rb_iseq_new_top(&ast->body, rb_fstring_lit("<top (required)>"),
634 fname, rb_realpath_internal(Qnil, fname, 1), NULL);
635 rb_ast_dispose(ast);
636 }
637 rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
638 rb_iseq_eval(iseq);
639}
640
641static inline enum ruby_tag_type
642load_wrapping(rb_execution_context_t *ec, VALUE fname)
643{
644 enum ruby_tag_type state;
645 rb_thread_t *th = rb_ec_thread_ptr(ec);
646 volatile VALUE wrapper = th->top_wrapper;
647 volatile VALUE self = th->top_self;
648#if !defined __GNUC__
649 rb_thread_t *volatile th0 = th;
650#endif
651
652 ec->errinfo = Qnil; /* ensure */
653
654 /* load in anonymous module as toplevel */
658
659 EC_PUSH_TAG(ec);
660 state = EC_EXEC_TAG();
661 if (state == TAG_NONE) {
662 load_iseq_eval(ec, fname);
663 }
664 EC_POP_TAG();
665
666#if !defined __GNUC__
667 th = th0;
668 fname = RB_GC_GUARD(fname);
669#endif
670 th->top_self = self;
671 th->top_wrapper = wrapper;
672 return state;
673}
674
675static inline void
676raise_load_if_failed(rb_execution_context_t *ec, enum ruby_tag_type state)
677{
678 if (state) {
680 }
681
682 if (!NIL_P(ec->errinfo)) {
684 }
685}
686
687static void
688rb_load_internal(VALUE fname, int wrap)
689{
690 rb_execution_context_t *ec = GET_EC();
692 if (wrap) {
693 state = load_wrapping(ec, fname);
694 }
695 else {
696 load_iseq_eval(ec, fname);
697 }
698 raise_load_if_failed(ec, state);
699}
700
701void
702rb_load(VALUE fname, int wrap)
703{
704 VALUE tmp = rb_find_file(FilePathValue(fname));
705 if (!tmp) load_failed(fname);
706 rb_load_internal(tmp, wrap);
707}
708
709void
710rb_load_protect(VALUE fname, int wrap, int *pstate)
711{
712 enum ruby_tag_type state;
713
714 EC_PUSH_TAG(GET_EC());
715 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
716 rb_load(fname, wrap);
717 }
718 EC_POP_TAG();
719
720 if (state != TAG_NONE) *pstate = state;
721}
722
723/*
724 * call-seq:
725 * load(filename, wrap=false) -> true
726 *
727 * Loads and executes the Ruby program in the file _filename_.
728 *
729 * If the filename is an absolute path (e.g. starts with '/'), the file
730 * will be loaded directly using the absolute path.
731 *
732 * If the filename is an explicit relative path (e.g. starts with './' or
733 * '../'), the file will be loaded using the relative path from the current
734 * directory.
735 *
736 * Otherwise, the file will be searched for in the library
737 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
738 * If the file is found in a directory, it will attempt to load the file
739 * relative to that directory. If the file is not found in any of the
740 * directories in <code>$LOAD_PATH</code>, the file will be loaded using
741 * the relative path from the current directory.
742 *
743 * If the file doesn't exist when there is an attempt to load it, a
744 * LoadError will be raised.
745 *
746 * If the optional _wrap_ parameter is +true+, the loaded script will
747 * be executed under an anonymous module, protecting the calling
748 * program's global namespace. In no circumstance will any local
749 * variables in the loaded file be propagated to the loading
750 * environment.
751 */
752
753static VALUE
754rb_f_load(int argc, VALUE *argv, VALUE _)
755{
756 VALUE fname, wrap, path, orig_fname;
757
758 rb_scan_args(argc, argv, "11", &fname, &wrap);
759
760 orig_fname = rb_get_path_check_to_string(fname);
761 fname = rb_str_encode_ospath(orig_fname);
762 RUBY_DTRACE_HOOK(LOAD_ENTRY, RSTRING_PTR(orig_fname));
763
764 path = rb_find_file(fname);
765 if (!path) {
766 if (!rb_file_load_ok(RSTRING_PTR(fname)))
767 load_failed(orig_fname);
768 path = fname;
769 }
770 rb_load_internal(path, RTEST(wrap));
771
772 RUBY_DTRACE_HOOK(LOAD_RETURN, RSTRING_PTR(orig_fname));
773
774 return Qtrue;
775}
776
777static char *
778load_lock(const char *ftptr)
779{
780 st_data_t data;
781 st_table *loading_tbl = get_loading_table();
782
783 if (!st_lookup(loading_tbl, (st_data_t)ftptr, &data)) {
784 /* partial state */
785 ftptr = ruby_strdup(ftptr);
787 st_insert(loading_tbl, (st_data_t)ftptr, data);
788 return (char *)ftptr;
789 }
790 else if (imemo_type_p(data, imemo_memo)) {
791 struct MEMO *memo = MEMO_CAST(data);
792 void (*init)(void) = memo->u3.func;
794 st_insert(loading_tbl, (st_data_t)ftptr, data);
795 (*init)();
796 return (char *)"";
797 }
798 if (RTEST(ruby_verbose)) {
799 VALUE warning = rb_warning_string("loading in progress, circular require considered harmful - %s", ftptr);
801 rb_warning("%"PRIsVALUE, warning);
802 }
803 switch (rb_thread_shield_wait((VALUE)data)) {
804 case Qfalse:
805 case Qnil:
806 return 0;
807 }
808 return (char *)ftptr;
809}
810
811static int
812release_thread_shield(st_data_t *key, st_data_t *value, st_data_t done, int existing)
813{
814 VALUE thread_shield = (VALUE)*value;
815 if (!existing) return ST_STOP;
816 if (done) {
817 rb_thread_shield_destroy(thread_shield);
818 /* Delete the entry even if there are waiting threads, because they
819 * won't load the file and won't delete the entry. */
820 }
821 else if (rb_thread_shield_release(thread_shield)) {
822 /* still in-use */
823 return ST_CONTINUE;
824 }
825 xfree((char *)*key);
826 return ST_DELETE;
827}
828
829static void
830load_unlock(const char *ftptr, int done)
831{
832 if (ftptr) {
833 st_data_t key = (st_data_t)ftptr;
834 st_table *loading_tbl = get_loading_table();
835
836 st_update(loading_tbl, key, release_thread_shield, done);
837 }
838}
839
840
841/*
842 * call-seq:
843 * require(name) -> true or false
844 *
845 * Loads the given +name+, returning +true+ if successful and +false+ if the
846 * feature is already loaded.
847 *
848 * If the filename neither resolves to an absolute path nor starts with
849 * './' or '../', the file will be searched for in the library
850 * directories listed in <code>$LOAD_PATH</code> (<code>$:</code>).
851 * If the filename starts with './' or '../', resolution is based on Dir.pwd.
852 *
853 * If the filename has the extension ".rb", it is loaded as a source file; if
854 * the extension is ".so", ".o", or ".dll", or the default shared library
855 * extension on the current platform, Ruby loads the shared library as a
856 * Ruby extension. Otherwise, Ruby tries adding ".rb", ".so", and so on
857 * to the name until found. If the file named cannot be found, a LoadError
858 * will be raised.
859 *
860 * For Ruby extensions the filename given may use any shared library
861 * extension. For example, on Linux the socket extension is "socket.so" and
862 * <code>require 'socket.dll'</code> will load the socket extension.
863 *
864 * The absolute path of the loaded file is added to
865 * <code>$LOADED_FEATURES</code> (<code>$"</code>). A file will not be
866 * loaded again if its path already appears in <code>$"</code>. For example,
867 * <code>require 'a'; require './a'</code> will not load <code>a.rb</code>
868 * again.
869 *
870 * require "my-library.rb"
871 * require "db-driver"
872 *
873 * Any constants or globals within the loaded source file will be available
874 * in the calling program's global namespace. However, local variables will
875 * not be propagated to the loading environment.
876 *
877 */
878
879VALUE
881{
882 return rb_require_string(fname);
883}
884
885/*
886 * call-seq:
887 * require_relative(string) -> true or false
888 *
889 * Ruby tries to load the library named _string_ relative to the requiring
890 * file's path. If the file's path cannot be determined a LoadError is raised.
891 * If a file is loaded +true+ is returned and false otherwise.
892 */
893VALUE
895{
897 if (NIL_P(base)) {
898 rb_loaderror("cannot infer basepath");
899 }
900 base = rb_file_dirname(base);
901 return rb_require_string(rb_file_absolute_path(fname, base));
902}
903
904typedef int (*feature_func)(const char *feature, const char *ext, int rb, int expanded, const char **fn);
905
906static int
907search_required(VALUE fname, volatile VALUE *path, feature_func rb_feature_p)
908{
909 VALUE tmp;
910 char *ext, *ftptr;
911 int type, ft = 0;
912 const char *loading;
913
914 *path = 0;
915 ext = strrchr(ftptr = RSTRING_PTR(fname), '.');
916 if (ext && !strchr(ext, '/')) {
917 if (IS_RBEXT(ext)) {
918 if (rb_feature_p(ftptr, ext, TRUE, FALSE, &loading)) {
919 if (loading) *path = rb_filesystem_str_new_cstr(loading);
920 return 'r';
921 }
922 if ((tmp = rb_find_file(fname)) != 0) {
923 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
924 if (!rb_feature_p(ftptr, ext, TRUE, TRUE, &loading) || loading)
925 *path = tmp;
926 return 'r';
927 }
928 return 0;
929 }
930 else if (IS_SOEXT(ext)) {
931 if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) {
932 if (loading) *path = rb_filesystem_str_new_cstr(loading);
933 return 's';
934 }
935 tmp = rb_str_subseq(fname, 0, ext - RSTRING_PTR(fname));
936#ifdef DLEXT2
937 OBJ_FREEZE(tmp);
938 if (rb_find_file_ext(&tmp, loadable_ext + 1)) {
939 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
940 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
941 *path = tmp;
942 return 's';
943 }
944#else
945 rb_str_cat2(tmp, DLEXT);
946 OBJ_FREEZE(tmp);
947 if ((tmp = rb_find_file(tmp)) != 0) {
948 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
949 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
950 *path = tmp;
951 return 's';
952 }
953#endif
954 }
955 else if (IS_DLEXT(ext)) {
956 if (rb_feature_p(ftptr, ext, FALSE, FALSE, &loading)) {
957 if (loading) *path = rb_filesystem_str_new_cstr(loading);
958 return 's';
959 }
960 if ((tmp = rb_find_file(fname)) != 0) {
961 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
962 if (!rb_feature_p(ftptr, ext, FALSE, TRUE, &loading) || loading)
963 *path = tmp;
964 return 's';
965 }
966 }
967 }
968 else if ((ft = rb_feature_p(ftptr, 0, FALSE, FALSE, &loading)) == 'r') {
969 if (loading) *path = rb_filesystem_str_new_cstr(loading);
970 return 'r';
971 }
972 tmp = fname;
973 type = rb_find_file_ext(&tmp, ft == 's' ? ruby_ext : loadable_ext);
974 switch (type) {
975 case 0:
976 if (ft)
977 goto statically_linked;
978 ftptr = RSTRING_PTR(tmp);
979 return rb_feature_p(ftptr, 0, FALSE, TRUE, 0);
980
981 default:
982 if (ft) {
983 goto statically_linked;
984 }
985 /* fall through */
986 case 1:
987 ext = strrchr(ftptr = RSTRING_PTR(tmp), '.');
988 if (rb_feature_p(ftptr, ext, !--type, TRUE, &loading) && !loading)
989 break;
990 *path = tmp;
991 }
992 return type ? 's' : 'r';
993
994 statically_linked:
995 if (loading) *path = rb_filesystem_str_new_cstr(loading);
996 return ft;
997}
998
999static void
1000load_failed(VALUE fname)
1001{
1002 rb_load_fail(fname, "cannot load such file");
1003}
1004
1005static VALUE
1006load_ext(VALUE path)
1007{
1009 return (VALUE)dln_load(RSTRING_PTR(path));
1010}
1011
1012static int
1013no_feature_p(const char *feature, const char *ext, int rb, int expanded, const char **fn)
1014{
1015 return 0;
1016}
1017
1018// Documented in doc/globals.rdoc
1019VALUE
1021{
1022 VALUE path;
1023 int found;
1024 VALUE sym;
1025
1026 fname = rb_get_path(fname);
1027 path = rb_str_encode_ospath(fname);
1028 found = search_required(path, &path, no_feature_p);
1029
1030 switch (found) {
1031 case 'r':
1032 sym = ID2SYM(rb_intern("rb"));
1033 break;
1034 case 's':
1035 sym = ID2SYM(rb_intern("so"));
1036 break;
1037 default:
1038 load_failed(fname);
1039 }
1040
1041 return rb_ary_new_from_args(2, sym, path);
1042}
1043
1044static void
1045ext_config_push(rb_thread_t *th, struct rb_ext_config *prev)
1046{
1047 *prev = th->ext_config;
1048 th->ext_config = (struct rb_ext_config){0};
1049}
1050
1051static void
1052ext_config_pop(rb_thread_t *th, struct rb_ext_config *prev)
1053{
1054 th->ext_config = *prev;
1055}
1056
1057void
1059{
1060 GET_THREAD()->ext_config.ractor_safe = flag;
1061}
1062
1063/*
1064 * returns
1065 * 0: if already loaded (false)
1066 * 1: successfully loaded (true)
1067 * <0: not found (LoadError)
1068 * >1: exception
1069 */
1070static int
1071require_internal(rb_execution_context_t *ec, VALUE fname, int exception)
1072{
1073 volatile int result = -1;
1074 rb_thread_t *th = rb_ec_thread_ptr(ec);
1075 volatile VALUE wrapper = th->top_wrapper;
1076 volatile VALUE self = th->top_self;
1077 volatile VALUE errinfo = ec->errinfo;
1078 enum ruby_tag_type state;
1079 char *volatile ftptr = 0;
1080 VALUE path;
1081 volatile bool reset_ext_config = false;
1082 struct rb_ext_config prev_ext_config;
1083
1084 fname = rb_get_path(fname);
1085 path = rb_str_encode_ospath(fname);
1086 RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
1087
1088 EC_PUSH_TAG(ec);
1089 ec->errinfo = Qnil; /* ensure */
1090 th->top_wrapper = 0;
1091 if ((state = EC_EXEC_TAG()) == TAG_NONE) {
1092 long handle;
1093 int found;
1094
1095 RUBY_DTRACE_HOOK(FIND_REQUIRE_ENTRY, RSTRING_PTR(fname));
1096 found = search_required(path, &path, rb_feature_p);
1097 RUBY_DTRACE_HOOK(FIND_REQUIRE_RETURN, RSTRING_PTR(fname));
1098
1099 if (found) {
1100 if (!path || !(ftptr = load_lock(RSTRING_PTR(path)))) {
1101 result = 0;
1102 }
1103 else if (!*ftptr) {
1104 result = TAG_RETURN;
1105 }
1106 else {
1107 switch (found) {
1108 case 'r':
1109 load_iseq_eval(ec, path);
1110 break;
1111
1112 case 's':
1113 reset_ext_config = true;
1114 ext_config_push(th, &prev_ext_config);
1115 handle = (long)rb_vm_call_cfunc(rb_vm_top_self(), load_ext,
1116 path, VM_BLOCK_HANDLER_NONE, path);
1117 rb_ary_push(ruby_dln_librefs, LONG2NUM(handle));
1118 break;
1119 }
1120 result = TAG_RETURN;
1121 }
1122 }
1123 }
1124 EC_POP_TAG();
1125
1126 rb_thread_t *th2 = rb_ec_thread_ptr(ec);
1127 th2->top_self = self;
1128 th2->top_wrapper = wrapper;
1129 if (reset_ext_config) ext_config_pop(th2, &prev_ext_config);
1130
1131 if (ftptr) load_unlock(RSTRING_PTR(path), !state);
1132
1133 if (state) {
1134 if (state == TAG_FATAL || state == TAG_THROW) {
1135 EC_JUMP_TAG(ec, state);
1136 }
1137 else if (exception) {
1138 /* usually state == TAG_RAISE only, except for
1139 * rb_iseq_load_iseq in load_iseq_eval case */
1141 if (!NIL_P(exc)) ec->errinfo = exc;
1142 return TAG_RAISE;
1143 }
1144 else if (state == TAG_RETURN) {
1145 return TAG_RAISE;
1146 }
1147 RB_GC_GUARD(fname);
1148 /* never TAG_RETURN */
1149 return state;
1150 }
1151 if (!NIL_P(ec->errinfo)) {
1152 if (!exception) return TAG_RAISE;
1153 rb_exc_raise(ec->errinfo);
1154 }
1155
1156 if (result == TAG_RETURN) rb_provide_feature(path);
1157 ec->errinfo = errinfo;
1158
1159 RUBY_DTRACE_HOOK(REQUIRE_RETURN, RSTRING_PTR(fname));
1160
1161 return result;
1162}
1163
1164int
1166{
1167 rb_execution_context_t *ec = GET_EC();
1168 return require_internal(ec, fname, 1);
1169}
1170
1171int
1172ruby_require_internal(const char *fname, unsigned int len)
1173{
1174 struct RString fake;
1175 VALUE str = rb_setup_fake_str(&fake, fname, len, 0);
1176 rb_execution_context_t *ec = GET_EC();
1177 int result = require_internal(ec, str, 0);
1179 return result == TAG_RETURN ? 1 : result ? -1 : 0;
1180}
1181
1182VALUE
1184{
1185 rb_execution_context_t *ec = GET_EC();
1186 int result = require_internal(ec, fname, 1);
1187
1188 if (result > TAG_RETURN) {
1189 EC_JUMP_TAG(ec, result);
1190 }
1191 if (result < 0) {
1192 load_failed(fname);
1193 }
1194
1195 return result ? Qtrue : Qfalse;
1196}
1197
1198VALUE
1199rb_require(const char *fname)
1200{
1201 return rb_require_string(rb_str_new_cstr(fname));
1202}
1203
1204static int
1205register_init_ext(st_data_t *key, st_data_t *value, st_data_t init, int existing)
1206{
1207 const char *name = (char *)*key;
1208 if (existing) {
1209 /* already registered */
1210 rb_warn("%s is already registered", name);
1211 }
1212 else {
1213 *value = (st_data_t)MEMO_NEW(0, 0, init);
1215 }
1216 return ST_CONTINUE;
1217}
1218
1219RUBY_FUNC_EXPORTED void
1220ruby_init_ext(const char *name, void (*init)(void))
1221{
1222 st_table *loading_tbl = get_loading_table();
1223
1224 if (rb_provided(name))
1225 return;
1226 st_update(loading_tbl, (st_data_t)name, register_init_ext, (st_data_t)init);
1227}
1228
1229/*
1230 * call-seq:
1231 * mod.autoload(module, filename) -> nil
1232 *
1233 * Registers _filename_ to be loaded (using Kernel::require)
1234 * the first time that _module_ (which may be a String or
1235 * a symbol) is accessed in the namespace of _mod_.
1236 *
1237 * module A
1238 * end
1239 * A.autoload(:B, "b")
1240 * A::B.doit # autoloads "b"
1241 */
1242
1243static VALUE
1244rb_mod_autoload(VALUE mod, VALUE sym, VALUE file)
1245{
1246 ID id = rb_to_id(sym);
1247
1249 rb_autoload_str(mod, id, file);
1250 return Qnil;
1251}
1252
1253/*
1254 * call-seq:
1255 * mod.autoload?(name, inherit=true) -> String or nil
1256 *
1257 * Returns _filename_ to be loaded if _name_ is registered as
1258 * +autoload+ in the namespace of _mod_ or one of its ancestors.
1259 *
1260 * module A
1261 * end
1262 * A.autoload(:B, "b")
1263 * A.autoload?(:B) #=> "b"
1264 *
1265 * If +inherit+ is false, the lookup only checks the autoloads in the receiver:
1266 *
1267 * class A
1268 * autoload :CONST, "const.rb"
1269 * end
1270 *
1271 * class B < A
1272 * end
1273 *
1274 * B.autoload?(:CONST) #=> "const.rb", found in A (ancestor)
1275 * B.autoload?(:CONST, false) #=> nil, not found in B itself
1276 *
1277 */
1278
1279static VALUE
1280rb_mod_autoload_p(int argc, VALUE *argv, VALUE mod)
1281{
1282 int recur = (rb_check_arity(argc, 1, 2) == 1) ? TRUE : RTEST(argv[1]);
1283 VALUE sym = argv[0];
1284
1285 ID id = rb_check_id(&sym);
1286 if (!id) {
1287 return Qnil;
1288 }
1289 return rb_autoload_at_p(mod, id, recur);
1290}
1291
1292/*
1293 * call-seq:
1294 * autoload(module, filename) -> nil
1295 *
1296 * Registers _filename_ to be loaded (using Kernel::require)
1297 * the first time that _module_ (which may be a String or
1298 * a symbol) is accessed.
1299 *
1300 * autoload(:MyModule, "/usr/local/lib/modules/my_module.rb")
1301 */
1302
1303static VALUE
1304rb_f_autoload(VALUE obj, VALUE sym, VALUE file)
1305{
1306 VALUE klass = rb_class_real(rb_vm_cbase());
1307 if (!klass) {
1308 rb_raise(rb_eTypeError, "Can not set autoload on singleton class");
1309 }
1310 return rb_mod_autoload(klass, sym, file);
1311}
1312
1313/*
1314 * call-seq:
1315 * autoload?(name, inherit=true) -> String or nil
1316 *
1317 * Returns _filename_ to be loaded if _name_ is registered as
1318 * +autoload+.
1319 *
1320 * autoload(:B, "b")
1321 * autoload?(:B) #=> "b"
1322 */
1323
1324static VALUE
1325rb_f_autoload_p(int argc, VALUE *argv, VALUE obj)
1326{
1327 /* use rb_vm_cbase() as same as rb_f_autoload. */
1328 VALUE klass = rb_vm_cbase();
1329 if (NIL_P(klass)) {
1330 return Qnil;
1331 }
1332 return rb_mod_autoload_p(argc, argv, klass);
1333}
1334
1335void
1337{
1338 rb_vm_t *vm = GET_VM();
1339 static const char var_load_path[] = "$:";
1340 ID id_load_path = rb_intern2(var_load_path, sizeof(var_load_path)-1);
1341
1342 rb_define_hooked_variable(var_load_path, (VALUE*)vm, load_path_getter, rb_gvar_readonly_setter);
1343 rb_alias_variable(rb_intern_const("$-I"), id_load_path);
1344 rb_alias_variable(rb_intern_const("$LOAD_PATH"), id_load_path);
1345 vm->load_path = rb_ary_new();
1348 vm->load_path_check_cache = 0;
1349 rb_define_singleton_method(vm->load_path, "resolve_feature_path", rb_resolve_feature_path, 1);
1350
1351 rb_define_virtual_variable("$\"", get_LOADED_FEATURES, 0);
1352 rb_define_virtual_variable("$LOADED_FEATURES", get_LOADED_FEATURES, 0);
1356
1357 rb_define_global_function("load", rb_f_load, -1);
1359 rb_define_global_function("require_relative", rb_f_require_relative, 1);
1360 rb_define_method(rb_cModule, "autoload", rb_mod_autoload, 2);
1361 rb_define_method(rb_cModule, "autoload?", rb_mod_autoload_p, -1);
1362 rb_define_global_function("autoload", rb_f_autoload, 2);
1363 rb_define_global_function("autoload?", rb_f_autoload_p, -1);
1364
1365 ruby_dln_librefs = rb_ary_tmp_new(0);
1366 rb_gc_register_mark_object(ruby_dln_librefs);
1367}
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:1141
VALUE rb_ary_push(VALUE ary, VALUE item)
Definition: array.c:1301
void rb_ary_free(VALUE ary)
Definition: array.c:864
VALUE rb_ary_replace(VALUE copy, VALUE orig)
Definition: array.c:4484
VALUE rb_ary_new(void)
Definition: array.c:749
VALUE rb_ary_shared_with_p(VALUE ary1, VALUE ary2)
Definition: array.c:687
VALUE rb_ary_tmp_new(long capa)
Definition: array.c:846
VALUE rb_ary_cat(VALUE ary, const VALUE *argv, long len)
Definition: array.c:1314
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1672
#define NORETURN(x)
Definition: attributes.h:152
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
Definition: cxxanyargs.hpp:653
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
Definition: cxxanyargs.hpp:668
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
Definition: cxxanyargs.hpp:678
#define mod(x, y)
Definition: date_strftime.c:28
#define recur(fmt)
struct RIMemo * ptr
Definition: debug.c:88
VALUE rb_dir_getwd_ospath(void)
Definition: dir.c:1092
char * strchr(char *, char)
void * dln_load(const char *file)
Definition: dln.c:1264
struct tab * done
Definition: enough.c:233
#define sym(name)
Definition: enumerator.c:4007
uint8_t len
Definition: escape.c:17
char str[HTML_ESCAPE_MAX_LEN+1]
Definition: escape.c:18
#define numberof(array)
Definition: etc.c:649
VALUE rb_vm_call_cfunc(VALUE recv, VALUE(*func)(VALUE), VALUE arg, VALUE block_handler, VALUE filename)
Definition: vm.c:2452
#define EC_EXEC_TAG()
Definition: eval_intern.h:193
#define EC_PUSH_TAG(ec)
Definition: eval_intern.h:130
#define EC_JUMP_TAG(ec, st)
Definition: eval_intern.h:196
char * strrchr(const char *, const char)
#define EC_POP_TAG()
Definition: eval_intern.h:138
void rb_vm_jump_tag_but_local_jump(int)
Definition: vm.c:1750
VALUE rb_vm_make_jump_tag_but_local_jump(int state, VALUE val)
Definition: vm.c:1718
VALUE rb_vm_cbase(void)
Definition: vm.c:1665
#define RSTRING_LEN(string)
Definition: fbuffer.h:22
#define RSTRING_PTR(string)
Definition: fbuffer.h:19
VALUE rb_get_path(VALUE obj)
Definition: file.c:245
VALUE rb_get_path_check_convert(VALUE obj)
Definition: file.c:226
VALUE rb_find_file(VALUE path)
Definition: file.c:6404
VALUE rb_file_expand_path_fast(VALUE fname, VALUE dname)
Definition: file.c:4110
VALUE rb_str_encode_ospath(VALUE path)
Definition: file.c:251
int rb_file_load_ok(const char *path)
Definition: file.c:6304
int rb_is_absolute_path(const char *path)
Definition: file.c:6177
int rb_find_file_ext(VALUE *filep, const char *const *ext)
Definition: file.c:6345
VALUE rb_check_realpath(VALUE basedir, VALUE path, rb_encoding *enc)
Definition: file.c:4504
VALUE rb_get_path_check_to_string(VALUE obj)
Definition: file.c:211
VALUE rb_realpath_internal(VALUE basedir, VALUE path, int strict)
Definition: file.c:4496
VALUE rb_file_dirname(VALUE fname)
Definition: file.c:4732
VALUE rb_file_absolute_path(VALUE fname, VALUE dname)
Definition: file.c:4157
#define PRIsVALUE
Definition: function.c:10
void rb_gc_register_mark_object(VALUE obj)
Inform the garbage collector that object is a live Ruby object that should not be moved.
Definition: gc.c:8022
void rb_extend_object(VALUE obj, VALUE module)
Extend the object with the module.
Definition: eval.c:1730
VALUE rb_module_new(void)
Definition: class.c:856
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:2296
#define OBJ_FROZEN
Definition: fl_type.h:136
#define OBJ_FREEZE
Definition: fl_type.h:134
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2917
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition: eval.c:712
void rb_set_errinfo(VALUE err)
Sets the current exception ($!) to the given value.
Definition: eval.c:1925
VALUE rb_warning_string(const char *fmt,...)
Definition: error.c:460
VALUE rb_eTypeError
Definition: error.c:1057
void rb_load_fail(VALUE path, const char *err)
Definition: error.c:3219
VALUE rb_eRuntimeError
Definition: error.c:1055
void rb_warn(const char *fmt,...)
Definition: error.c:408
void rb_loaderror(const char *fmt,...)
Definition: error.c:2936
void rb_warning(const char *fmt,...)
Definition: error.c:439
VALUE rb_cModule
Module class.
Definition: object.c:50
VALUE rb_class_real(VALUE)
Looks up the nearest ancestor of cl, skipping singleton classes or module inclusions.
Definition: object.c:235
VALUE rb_obj_clone(VALUE)
Almost same as Object::clone.
Definition: object.c:457
VALUE rb_obj_freeze(VALUE)
Make the object unmodifiable.
Definition: object.c:1101
#define MEMO_NEW(a, b, c)
Definition: imemo.h:122
#define MEMO_CAST(m)
Definition: imemo.h:121
@ imemo_memo
Definition: imemo.h:40
#define DLEXT_MAXLEN
Definition: config.h:94
#define ruby_verbose
Definition: error.h:68
#define rb_check_arity
Definition: error.h:34
#define rb_str_new2
Definition: string.h:276
VALUE rb_str_freeze(VALUE)
Definition: string.c:2766
VALUE rb_str_resize(VALUE, long)
Definition: string.c:2859
#define rb_str_cat2
Definition: string.h:285
VALUE rb_filesystem_str_new_cstr(const char *)
Definition: string.c:1187
VALUE rb_str_equal(VALUE str1, VALUE str2)
Definition: string.c:3423
VALUE rb_str_tmp_new(long)
Definition: string.c:1427
VALUE rb_str_subseq(VALUE, long, long)
Definition: string.c:2624
#define rb_strlen_lit(str)
Definition: string.h:286
VALUE rb_str_append(VALUE, VALUE)
Definition: string.c:3118
#define rb_str_new_cstr(str)
Definition: string.h:219
void rb_alias_variable(ID, ID)
Definition: variable.c:843
#define ID2SYM
Definition: symbol.h:44
ID rb_intern2(const char *, long)
Definition: symbol.c:778
ID rb_intern(const char *)
Definition: symbol.c:785
ID rb_check_id(volatile VALUE *)
Returns ID for the given name if it is interned already, or 0.
Definition: symbol.c:1069
ID rb_to_id(VALUE)
Definition: string.c:11501
rb_gvar_setter_t rb_gvar_readonly_setter
Definition: variable.h:46
size_t strlcpy(char *, const char *, size_t)
Definition: strlcpy.c:29
char * ruby_strdup(const char *)
Definition: util.c:531
Internal header for Dir.
Internal header for File.
#define ruby_sized_xfree
Definition: gc.h:166
Internal header for require.
Internal header for the parser.
void * rb_parser_load_file(VALUE parser, VALUE name)
Definition: ruby.c:2374
VALUE rb_setup_fake_str(struct RString *fake_str, const char *name, long len, rb_encoding *enc)
Definition: string.c:435
#define rb_fstring_lit(str)
Definition: string.h:78
VALUE rb_fstring(VALUE)
Definition: string.c:353
Internal header for Thread.
VALUE rb_thread_shield_new(void)
Definition: thread.c:5072
VALUE rb_thread_shield_destroy(VALUE self)
Definition: thread.c:5128
VALUE rb_thread_shield_wait(VALUE self)
Definition: thread.c:5088
VALUE rb_thread_shield_release(VALUE self)
Definition: thread.c:5117
VALUE rb_autoload_at_p(VALUE, ID, int)
Definition: variable.c:2517
void rb_autoload_str(VALUE mod, ID id, VALUE file)
Definition: variable.c:2158
void rb_backtrace_each(VALUE(*iter)(VALUE recv, VALUE str), VALUE output)
#define RUBY_DTRACE_HOOK(name, arg)
Definition: vm.h:122
VALUE rb_vm_top_self(void)
Definition: vm.c:3752
VALUE rb_current_realfilepath(void)
Definition: vm_eval.c:2569
#define rb_ary_new_from_args(...)
Definition: internal.h:65
#define rb_fstring_cstr(...)
Definition: internal.h:71
typedef long(ZCALLBACK *tell_file_func) OF((voidpf opaque
voidpf uLong offset
Definition: ioapi.h:144
typedef int(ZCALLBACK *close_file_func) OF((voidpf opaque
voidpf void * buf
Definition: ioapi.h:138
const rb_iseq_t * rb_iseq_load_iseq(VALUE fname)
Definition: iseq.c:907
rb_iseq_t * rb_iseq_new_top(const rb_ast_body_t *ast, VALUE name, VALUE path, VALUE realpath, const rb_iseq_t *parent)
Definition: iseq.c:817
VALUE rb_require_string(VALUE fname)
Definition: load.c:1183
int(* feature_func)(const char *feature, const char *ext, int rb, int expanded, const char **fn)
Definition: load.c:904
void rb_provide(const char *feature)
Definition: load.c:616
void rb_load(VALUE fname, int wrap)
Definition: load.c:702
void rb_load_protect(VALUE fname, int wrap, int *pstate)
Definition: load.c:710
#define IS_SOEXT(e)
Definition: load.c:23
VALUE rb_f_require(VALUE obj, VALUE fname)
Definition: load.c:880
void rb_ext_ractor_safe(bool flag)
Definition: load.c:1058
int rb_require_internal(VALUE fname)
Definition: load.c:1165
VALUE rb_f_require_relative(VALUE obj, VALUE fname)
Definition: load.c:894
void ruby_init_ext(const char *name, void(*init)(void))
Definition: load.c:1220
int rb_feature_provided(const char *feature, const char **loading)
Definition: load.c:571
expand_type
Definition: load.c:43
@ EXPAND_ALL
Definition: load.c:44
@ EXPAND_HOME
Definition: load.c:46
@ EXPAND_RELATIVE
Definition: load.c:45
@ EXPAND_NON_CACHE
Definition: load.c:47
VALUE rb_resolve_feature_path(VALUE klass, VALUE fname)
Definition: load.c:1020
VALUE rb_require(const char *fname)
Definition: load.c:1199
void Init_load(void)
Definition: load.c:1336
int rb_provided(const char *feature)
Definition: load.c:565
int ruby_require_internal(const char *fname, unsigned int len)
Definition: load.c:1172
#define IS_RBEXT(e)
Definition: load.c:22
VALUE rb_get_expanded_load_path(void)
Definition: load.c:104
#define IS_DLEXT(e)
Definition: load.c:27
#define INT2FIX
Definition: long.h:48
#define LONG2NUM
Definition: long.h:50
#define FIX2LONG
Definition: long.h:46
#define MEMCPY(p1, p2, type, n)
Definition: memory.h:129
#define RB_GC_GUARD(v)
Definition: memory.h:91
#define MEMMOVE(p1, p2, type, n)
Definition: memory.h:130
@ METHOD_VISI_PUBLIC
Definition: method.h:31
void rb_scope_visibility_set(rb_method_visibility_t)
Definition: vm_method.c:1483
void rb_define_hooked_variable(const char *q, VALUE *w, type *e, void_type *r)
Define a function-backended global variable.
Definition: cxxanyargs.hpp:136
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition: cxxanyargs.hpp:56
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
Definition: cxxanyargs.hpp:73
unsigned int top
Definition: nkf.c:4323
const char * name
Definition: nkf.c:208
#define TRUE
Definition: nkf.h:175
#define FALSE
Definition: nkf.h:174
void rb_ast_dispose(rb_ast_t *ast)
Definition: node.c:1448
#define RARRAY_AREF(a, i)
Definition: psych_emitter.c:7
#define RARRAY_LEN
Definition: rarray.h:52
#define RARRAY_CONST_PTR_TRANSIENT
Definition: rarray.h:54
#define RBASIC(obj)
Definition: rbasic.h:34
#define NULL
Definition: regenc.h:69
VALUE rb_parser_new(void)
Definition: ripper.c:20781
VALUE rb_parser_set_context(VALUE vparser, const struct rb_iseq_struct *base, int main)
Definition: ripper.c:20791
#define StringValue(v)
Definition: rstring.h:50
#define StringValuePtr(v)
Definition: rstring.h:51
#define FilePathValue(v)
Definition: ruby.h:61
int argc
Definition: ruby.c:240
char ** argv
Definition: ruby.c:241
#define Qundef
#define SPECIAL_CONST_P
#define Qtrue
#define RTEST
#define Qnil
#define Qfalse
#define NIL_P
#define f
@ ST_STOP
Definition: st.h:99
@ ST_DELETE
Definition: st.h:99
@ ST_CONTINUE
Definition: st.h:99
unsigned long st_data_t
Definition: st.h:22
#define st_get_key
Definition: st.h:130
#define st_foreach
Definition: st.h:142
#define st_hash
Definition: st.h:176
#define st_init_numtable
Definition: st.h:106
#define st_lookup
Definition: st.h:128
#define st_insert
Definition: st.h:124
#define st_update
Definition: st.h:136
#define _(args)
Definition: stdarg.h:31
size_t strlen(const char *)
MEMO.
Definition: imemo.h:105
void(* func)(void)
Definition: imemo.h:114
union MEMO::@112 u3
const VALUE value
Definition: imemo.h:113
Definition: rarray.h:87
Definition: gzappend.c:170
const char * result
Definition: load.c:402
const char * name
Definition: load.c:398
rb_ast_body_t body
Definition: node.h:406
VALUE top_wrapper
Definition: vm_core.h:950
VALUE top_self
Definition: vm_core.h:949
struct rb_ext_config ext_config
Definition: vm_core.h:1021
VALUE load_path_check_cache
Definition: vm_core.h:618
VALUE load_path
Definition: vm_core.h:616
VALUE load_path_snapshot
Definition: vm_core.h:617
VALUE expanded_load_path
Definition: vm_core.h:619
VALUE loaded_features_snapshot
Definition: vm_core.h:621
struct st_table * loaded_features_index
Definition: vm_core.h:622
VALUE loaded_features
Definition: vm_core.h:620
Definition: st.h:79
Definition: blast.c:41
unsigned long VALUE
Definition: value.h:38
unsigned long ID
Definition: value.h:39
#define T_STRING
Definition: value_type.h:77
#define T_FIXNUM
Definition: value_type.h:62
#define T_ARRAY
Definition: value_type.h:55
VALUE rb_iseq_eval(const rb_iseq_t *iseq)
Definition: vm.c:2403
#define TAG_RAISE
Definition: vm_core.h:204
#define TAG_NONE
Definition: vm_core.h:198
ruby_tag_type
Definition: vm_core.h:185
#define TAG_THROW
Definition: vm_core.h:205
#define TAG_FATAL
Definition: vm_core.h:206
#define TAG_RETURN
Definition: vm_core.h:199
#define VM_BLOCK_HANDLER_NONE
Definition: vm_core.h:1299
#define xfree
Definition: xmalloc.h:49
#define xcalloc
Definition: xmalloc.h:46