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