Ruby: ruby.c Source File

Ruby 3.3.4p94 (2024-07-09 revision be1089c8ec5ba40e09b1553e36b3174bf4014d9d)

ruby.c
1/**********************************************************************
2
3 ruby.c -
4
5 $Author$
6 created at: Tue Aug 10 12:47:31 JST 1993
7
8 Copyright (C) 1993-2007 Yukihiro Matsumoto
9 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
10 Copyright (C) 2000 Information-technology Promotion Agency, Japan
11
12**********************************************************************/
13
14#include "ruby/internal/config.h"
15
16#include <ctype.h>
17#include <stdio.h>
18#include <sys/types.h>
19
20#ifdef __CYGWIN__
21# include <windows.h>
22# include <sys/cygwin.h>
23#endif
24
25#if defined(LOAD_RELATIVE) && defined(HAVE_DLADDR)
26# include <dlfcn.h>
27#endif
28
29#ifdef HAVE_UNISTD_H
30# include <unistd.h>
31#endif
32
33#if defined(HAVE_FCNTL_H)
34# include <fcntl.h>
35#elif defined(HAVE_SYS_FCNTL_H)
36# include <sys/fcntl.h>
37#endif
38
39#ifdef HAVE_SYS_PARAM_H
40# include <sys/param.h>
41#endif
42
43#include "dln.h"
44#include "eval_intern.h"
45#include "internal.h"
46#include "internal/cmdlineopt.h"
47#include "internal/cont.h"
48#include "internal/error.h"
49#include "internal/file.h"
50#include "internal/inits.h"
51#include "internal/io.h"
52#include "internal/load.h"
53#include "internal/loadpath.h"
54#include "internal/missing.h"
55#include "internal/object.h"
56#include "internal/thread.h"
57#include "internal/ruby_parser.h"
58#include "internal/variable.h"
59#include "ruby/encoding.h"
60#include "ruby/thread.h"
61#include "ruby/util.h"
62#include "ruby/version.h"
63#include "ruby/internal/error.h"
64
65#define singlebit_only_p(x) !((x) & ((x)-1))
66STATIC_ASSERT(Qnil_1bit_from_Qfalse, singlebit_only_p(Qnil^Qfalse));
67STATIC_ASSERT(Qundef_1bit_from_Qnil, singlebit_only_p(Qundef^Qnil));
68
69#ifndef MAXPATHLEN
70# define MAXPATHLEN 1024
71#endif
72#ifndef O_ACCMODE
73# define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
74#endif
75
76void Init_ruby_description(ruby_cmdline_options_t *opt);
77
78#ifndef HAVE_STDLIB_H
79char *getenv();
80#endif
81
82#ifndef DISABLE_RUBYGEMS
83# define DISABLE_RUBYGEMS 0
84#endif
85#if DISABLE_RUBYGEMS
86#define DEFAULT_RUBYGEMS_ENABLED "disabled"
87#else
88#define DEFAULT_RUBYGEMS_ENABLED "enabled"
89#endif
90
91void rb_warning_category_update(unsigned int mask, unsigned int bits);
92
93#define COMMA ,
94#define FEATURE_BIT(bit) (1U << feature_##bit)
95#define EACH_FEATURES(X, SEP) \
96 X(gems) \
97 SEP \
98 X(error_highlight) \
99 SEP \
100 X(did_you_mean) \
101 SEP \
102 X(syntax_suggest) \
103 SEP \
104 X(rubyopt) \
105 SEP \
106 X(frozen_string_literal) \
107 SEP \
108 X(rjit) \
109 SEP \
110 X(yjit) \
111 /* END OF FEATURES */
112#define EACH_DEBUG_FEATURES(X, SEP) \
113 X(frozen_string_literal) \
114 /* END OF DEBUG FEATURES */
115#define AMBIGUOUS_FEATURE_NAMES 0 /* no ambiguous feature names now */
116#define DEFINE_FEATURE(bit) feature_##bit
117#define DEFINE_DEBUG_FEATURE(bit) feature_debug_##bit
118enum feature_flag_bits {
119 EACH_FEATURES(DEFINE_FEATURE, COMMA),
120 feature_debug_flag_first,
121#if defined(RJIT_FORCE_ENABLE) || !USE_YJIT
122 DEFINE_FEATURE(jit) = feature_rjit,
123#else
124 DEFINE_FEATURE(jit) = feature_yjit,
125#endif
126 feature_jit_mask = FEATURE_BIT(rjit) | FEATURE_BIT(yjit),
127
128 feature_debug_flag_begin = feature_debug_flag_first - 1,
129 EACH_DEBUG_FEATURES(DEFINE_DEBUG_FEATURE, COMMA),
130 feature_flag_count
131};
132
133#define MULTI_BITS_P(bits) ((bits) & ((bits) - 1))
134
135#define DEBUG_BIT(bit) (1U << feature_debug_##bit)
136
137#define DUMP_BIT(bit) (1U << dump_##bit)
138#define DEFINE_DUMP(bit) dump_##bit
139#define EACH_DUMPS(X, SEP) \
140 X(version) \
141 SEP \
142 X(copyright) \
143 SEP \
144 X(usage) \
145 SEP \
146 X(help) \
147 SEP \
148 X(yydebug) \
149 SEP \
150 X(syntax) \
151 SEP \
152 X(parsetree) \
153 SEP \
154 X(parsetree_with_comment) \
155 SEP \
156 X(insns) \
157 SEP \
158 X(insns_without_opt) \
159 /* END OF DUMPS */
160enum dump_flag_bits {
161 dump_version_v,
162 dump_error_tolerant,
163 EACH_DUMPS(DEFINE_DUMP, COMMA),
164 dump_error_tolerant_bits = (DUMP_BIT(yydebug) |
165 DUMP_BIT(parsetree) |
166 DUMP_BIT(parsetree_with_comment)),
167 dump_exit_bits = (DUMP_BIT(yydebug) | DUMP_BIT(syntax) |
168 DUMP_BIT(parsetree) | DUMP_BIT(parsetree_with_comment) |
169 DUMP_BIT(insns) | DUMP_BIT(insns_without_opt))
170};
171
172static inline void
173rb_feature_set_to(ruby_features_t *feat, unsigned int bit_mask, unsigned int bit_set)
174{
175 feat->mask |= bit_mask;
176 feat->set = (feat->set & ~bit_mask) | bit_set;
177}
178
179#define FEATURE_SET_TO(feat, bit_mask, bit_set) \
180 rb_feature_set_to(&(feat), bit_mask, bit_set)
181#define FEATURE_SET(feat, bits) FEATURE_SET_TO(feat, bits, bits)
182#define FEATURE_SET_RESTORE(feat, save) FEATURE_SET_TO(feat, (save).mask, (save).set & (save).mask)
183#define FEATURE_SET_P(feat, bits) ((feat).set & FEATURE_BIT(bits))
184#define FEATURE_USED_P(feat, bits) ((feat).mask & FEATURE_BIT(bits))
185#define FEATURE_SET_BITS(feat) ((feat).set & (feat).mask)
186
187static void init_ids(ruby_cmdline_options_t *);
188
189#define src_encoding_index GET_VM()->src_encoding_index
190
191enum {
192 COMPILATION_FEATURES = (
193 0
194 | FEATURE_BIT(frozen_string_literal)
195 | FEATURE_BIT(debug_frozen_string_literal)
196 ),
197 DEFAULT_FEATURES = (
198 (FEATURE_BIT(debug_flag_first)-1)
199#if DISABLE_RUBYGEMS
200 & ~FEATURE_BIT(gems)
201#endif
202 & ~FEATURE_BIT(frozen_string_literal)
203 & ~feature_jit_mask
204 )
205};
206
207#define BACKTRACE_LENGTH_LIMIT_VALID_P(n) ((n) >= -1)
208#define OPT_BACKTRACE_LENGTH_LIMIT_VALID_P(opt) \
209 BACKTRACE_LENGTH_LIMIT_VALID_P((opt)->backtrace_length_limit)
210
211static ruby_cmdline_options_t *
212cmdline_options_init(ruby_cmdline_options_t *opt)
213{
214 MEMZERO(opt, *opt, 1);
215 init_ids(opt);
216 opt->src.enc.index = src_encoding_index;
217 opt->ext.enc.index = -1;
218 opt->intern.enc.index = -1;
219 opt->features.set = DEFAULT_FEATURES;
220#ifdef RJIT_FORCE_ENABLE /* to use with: ./configure cppflags="-DRJIT_FORCE_ENABLE" */
221 opt->features.set |= FEATURE_BIT(rjit);
222#elif defined(YJIT_FORCE_ENABLE)
223 opt->features.set |= FEATURE_BIT(yjit);
224#endif
225 opt->backtrace_length_limit = LONG_MIN;
226
227 return opt;
228}
229
230static rb_ast_t *load_file(VALUE parser, VALUE fname, VALUE f, int script,
231 ruby_cmdline_options_t *opt);
232static VALUE open_load_file(VALUE fname_v, int *xflag);
233static void forbid_setid(const char *, const ruby_cmdline_options_t *);
234#define forbid_setid(s) forbid_setid((s), opt)
235
236static struct {
237 int argc;
238 char **argv;
239} origarg;
240
241static const char esc_standout[] = "\n\033[1;7m";
242static const char esc_bold[] = "\033[1m";
243static const char esc_reset[] = "\033[0m";
244static const char esc_none[] = "";
245#define USAGE_INDENT " " /* macro for concatenation */
246
247static void
248show_usage_part(const char *str, const unsigned int namelen,
249 const char *str2, const unsigned int secondlen,
250 const char *desc,
251 int help, int highlight, unsigned int w, int columns)
252{
253 static const int indent_width = (int)rb_strlen_lit(USAGE_INDENT);
254 const char *sb = highlight ? esc_bold : esc_none;
255 const char *se = highlight ? esc_reset : esc_none;
256 unsigned int desclen = (unsigned int)strcspn(desc, "\n");
257 if (help && (namelen + 1 > w) && /* a padding space */
258 (int)(namelen + secondlen + indent_width) >= columns) {
259 printf(USAGE_INDENT "%s" "%.*s" "%s\n", sb, namelen, str, se);
260 if (secondlen > 0) {
261 const int second_end = secondlen;
262 int n = 0;
263 if (str2[n] == ',') n++;
264 if (str2[n] == ' ') n++;
265 printf(USAGE_INDENT "%s" "%.*s" "%s\n", sb, second_end-n, str2+n, se);
266 }
267 printf("%-*s%.*s\n", w + indent_width, USAGE_INDENT, desclen, desc);
268 }
269 else {
270 const int wrap = help && namelen + secondlen >= w;
271 printf(USAGE_INDENT "%s%.*s%-*.*s%s%-*s%.*s\n", sb, namelen, str,
272 (wrap ? 0 : w - namelen),
273 (help ? secondlen : 0), str2, se,
274 (wrap ? (int)(w + rb_strlen_lit("\n" USAGE_INDENT)) : 0),
275 (wrap ? "\n" USAGE_INDENT : ""),
276 desclen, desc);
277 }
278 if (help) {
279 while (desc[desclen]) {
280 desc += desclen + rb_strlen_lit("\n");
281 desclen = (unsigned int)strcspn(desc, "\n");
282 printf("%-*s%.*s\n", w + indent_width, USAGE_INDENT, desclen, desc);
283 }
284 }
285}
286
287static void
288show_usage_line(const struct ruby_opt_message *m,
289 int help, int highlight, unsigned int w, int columns)
290{
291 const char *str = m->str;
292 const unsigned int namelen = m->namelen, secondlen = m->secondlen;
293 const char *desc = str + namelen + secondlen;
294 show_usage_part(str, namelen - 1, str + namelen, secondlen - 1, desc,
295 help, highlight, w, columns);
296}
297
298void
299ruby_show_usage_line(const char *name, const char *secondary, const char *description,
300 int help, int highlight, unsigned int width, int columns)
301{
302 unsigned int namelen = (unsigned int)strlen(name);
303 unsigned int secondlen = (secondary ? (unsigned int)strlen(secondary) : 0);
304 show_usage_part(name, namelen, secondary, secondlen,
305 description, help, highlight, width, columns);
306}
307
308static void
309usage(const char *name, int help, int highlight, int columns)
310{
311#define M(shortopt, longopt, desc) RUBY_OPT_MESSAGE(shortopt, longopt, desc)
312
313#if USE_YJIT
314# define PLATFORM_JIT_OPTION "--yjit"
315#else
316# define PLATFORM_JIT_OPTION "--rjit (experimental)"
317#endif
318
319 /* This message really ought to be max 23 lines.
320 * Removed -h because the user already knows that option. Others? */
321 static const struct ruby_opt_message usage_msg[] = {
322 M("-0[octal]", "", "specify record separator (\\0, if no argument)\n"
323 "(-00 for paragraph mode, -0777 for slurp mode)"),
324 M("-a", "", "autosplit mode with -n or -p (splits $_ into $F)"),
325 M("-c", "", "check syntax only"),
326 M("-Cdirectory", "", "cd to directory before executing your script"),
327 M("-d", ", --debug", "set debugging flags (set $DEBUG to true)"),
328 M("-e 'command'", "", "one line of script. Several -e's allowed. Omit [programfile]"),
329 M("-Eex[:in]", ", --encoding=ex[:in]", "specify the default external and internal character encodings"),
330 M("-Fpattern", "", "split() pattern for autosplit (-a)"),
331 M("-i[extension]", "", "edit ARGV files in place (make backup if extension supplied)"),
332 M("-Idirectory", "", "specify $LOAD_PATH directory (may be used more than once)"),
333 M("-l", "", "enable line ending processing"),
334 M("-n", "", "assume 'while gets(); ... end' loop around your script"),
335 M("-p", "", "assume loop like -n but print line also like sed"),
336 M("-rlibrary", "", "require the library before executing your script"),
337 M("-s", "", "enable some switch parsing for switches after script name"),
338 M("-S", "", "look for the script using PATH environment variable"),
339 M("-v", "", "print the version number, then turn on verbose mode"),
340 M("-w", "", "turn warnings on for your script"),
341 M("-W[level=2|:category]", "", "set warning level; 0=silence, 1=medium, 2=verbose"),
342 M("-x[directory]", "", "strip off text before #!ruby line and perhaps cd to directory"),
343 M("--jit", "", "enable JIT for the platform, same as " PLATFORM_JIT_OPTION),
344#if USE_YJIT
345 M("--yjit", "", "enable in-process JIT compiler"),
346#endif
347#if USE_RJIT
348 M("--rjit", "", "enable pure-Ruby JIT compiler (experimental)"),
349#endif
350 M("-h", "", "show this message, --help for more info"),
351 };
352 STATIC_ASSERT(usage_msg_size, numberof(usage_msg) < 25);
353
354 static const struct ruby_opt_message help_msg[] = {
355 M("--copyright", "", "print the copyright"),
356 M("--dump={insns|parsetree|...}[,...]", "",
357 "dump debug information. see below for available dump list"),
358 M("--enable={jit|rubyopt|...}[,...]", ", --disable={jit|rubyopt|...}[,...]",
359 "enable or disable features. see below for available features"),
360 M("--external-encoding=encoding", ", --internal-encoding=encoding",
361 "specify the default external or internal character encoding"),
362 M("--parser={parse.y|prism}", ", --parser=prism",
363 "the parser used to parse Ruby code (experimental)"),
364 M("--backtrace-limit=num", "", "limit the maximum length of backtrace"),
365 M("--verbose", "", "turn on verbose mode and disable script from stdin"),
366 M("--version", "", "print the version number, then exit"),
367 M("--crash-report=TEMPLATE", "", "template of crash report files"),
368 M("-y", ", --yydebug", "print log of parser. Backward compatibility is not guaranteed"),
369 M("--help", "", "show this message, -h for short message"),
370 };
371 static const struct ruby_opt_message dumps[] = {
372 M("insns", "", "instruction sequences"),
373 M("insns_without_opt", "", "instruction sequences compiled with no optimization"),
374 M("yydebug(+error-tolerant)", "", "yydebug of yacc parser generator"),
375 M("parsetree(+error-tolerant)","", "AST"),
376 M("parsetree_with_comment(+error-tolerant)", "", "AST with comments"),
377 M("prism_parsetree", "", "Prism AST with comments"),
378 };
379 static const struct ruby_opt_message features[] = {
380 M("gems", "", "rubygems (only for debugging, default: "DEFAULT_RUBYGEMS_ENABLED")"),
381 M("error_highlight", "", "error_highlight (default: "DEFAULT_RUBYGEMS_ENABLED")"),
382 M("did_you_mean", "", "did_you_mean (default: "DEFAULT_RUBYGEMS_ENABLED")"),
383 M("syntax_suggest", "", "syntax_suggest (default: "DEFAULT_RUBYGEMS_ENABLED")"),
384 M("rubyopt", "", "RUBYOPT environment variable (default: enabled)"),
385 M("frozen-string-literal", "", "freeze all string literals (default: disabled)"),
386#if USE_YJIT
387 M("yjit", "", "in-process JIT compiler (default: disabled)"),
388#endif
389#if USE_RJIT
390 M("rjit", "", "pure-Ruby JIT compiler (experimental, default: disabled)"),
391#endif
392 };
393 static const struct ruby_opt_message warn_categories[] = {
394 M("deprecated", "", "deprecated features"),
395 M("experimental", "", "experimental features"),
396 M("performance", "", "performance issues"),
397 };
398#if USE_RJIT
399 extern const struct ruby_opt_message rb_rjit_option_messages[];
400#endif
401 int i;
402 const char *sb = highlight ? esc_standout+1 : esc_none;
403 const char *se = highlight ? esc_reset : esc_none;
404 const int num = numberof(usage_msg) - (help ? 1 : 0);
405 unsigned int w = (columns > 80 ? (columns - 79) / 2 : 0) + 16;
406#define SHOW(m) show_usage_line(&(m), help, highlight, w, columns)
407
408 printf("%sUsage:%s %s [switches] [--] [programfile] [arguments]\n", sb, se, name);
409 for (i = 0; i < num; ++i)
410 SHOW(usage_msg[i]);
411
412 if (!help) return;
413
414 if (highlight) sb = esc_standout;
415
416 for (i = 0; i < numberof(help_msg); ++i)
417 SHOW(help_msg[i]);
418 printf("%s""Dump List:%s\n", sb, se);
419 for (i = 0; i < numberof(dumps); ++i)
420 SHOW(dumps[i]);
421 printf("%s""Features:%s\n", sb, se);
422 for (i = 0; i < numberof(features); ++i)
423 SHOW(features[i]);
424 printf("%s""Warning categories:%s\n", sb, se);
425 for (i = 0; i < numberof(warn_categories); ++i)
426 SHOW(warn_categories[i]);
427#if USE_YJIT
428 printf("%s""YJIT options:%s\n", sb, se);
429 rb_yjit_show_usage(help, highlight, w, columns);
430#endif
431#if USE_RJIT
432 printf("%s""RJIT options (experimental):%s\n", sb, se);
433 for (i = 0; rb_rjit_option_messages[i].str; ++i)
434 SHOW(rb_rjit_option_messages[i]);
435#endif
436}
437
438#define rubylib_path_new rb_str_new
439
440static void
441push_include(const char *path, VALUE (*filter)(VALUE))
442{
443 const char sep = PATH_SEP_CHAR;
444 const char *p, *s;
445 VALUE load_path = GET_VM()->load_path;
446
447 p = path;
448 while (*p) {
449 while (*p == sep)
450 p++;
451 if (!*p) break;
452 for (s = p; *s && *s != sep; s = CharNext(s));
453 rb_ary_push(load_path, (*filter)(rubylib_path_new(p, s - p)));
454 p = s;
455 }
456}
457
458#ifdef __CYGWIN__
459static void
460push_include_cygwin(const char *path, VALUE (*filter)(VALUE))
461{
462 const char *p, *s;
463 char rubylib[FILENAME_MAX];
464 VALUE buf = 0;
465
466 p = path;
467 while (*p) {
468 unsigned int len;
469 while (*p == ';')
470 p++;
471 if (!*p) break;
472 for (s = p; *s && *s != ';'; s = CharNext(s));
473 len = s - p;
474 if (*s) {
475 if (!buf) {
476 buf = rb_str_new(p, len);
477 p = RSTRING_PTR(buf);
478 }
479 else {
480 rb_str_resize(buf, len);
481 p = strncpy(RSTRING_PTR(buf), p, len);
482 }
483 }
484#ifdef HAVE_CYGWIN_CONV_PATH
485#define CONV_TO_POSIX_PATH(p, lib) \
486 cygwin_conv_path(CCP_WIN_A_TO_POSIX|CCP_RELATIVE, (p), (lib), sizeof(lib))
487#else
488# error no cygwin_conv_path
489#endif
490 if (CONV_TO_POSIX_PATH(p, rubylib) == 0)
491 p = rubylib;
492 push_include(p, filter);
493 if (!*s) break;
494 p = s + 1;
495 }
496}
497
498#define push_include push_include_cygwin
499#endif
500
501void
502ruby_push_include(const char *path, VALUE (*filter)(VALUE))
503{
504 if (path == 0)
505 return;
506 push_include(path, filter);
507}
508
509static VALUE
510identical_path(VALUE path)
511{
512 return path;
513}
514static VALUE
515locale_path(VALUE path)
516{
517 rb_enc_associate(path, rb_locale_encoding());
518 return path;
519}
520
521void
522ruby_incpush(const char *path)
523{
524 ruby_push_include(path, locale_path);
525}
526
527static VALUE
528expand_include_path(VALUE path)
529{
530 char *p = RSTRING_PTR(path);
531 if (!p)
532 return path;
533 if (*p == '.' && p[1] == '/')
534 return path;
535 return rb_file_expand_path(path, Qnil);
536}
537
538void
539ruby_incpush_expand(const char *path)
540{
541 ruby_push_include(path, expand_include_path);
542}
543
544#undef UTF8_PATH
545#if defined _WIN32 || defined __CYGWIN__
546static HMODULE libruby;
547
548BOOL WINAPI
549DllMain(HINSTANCE dll, DWORD reason, LPVOID reserved)
550{
551 if (reason == DLL_PROCESS_ATTACH)
552 libruby = dll;
553 return TRUE;
554}
555
556HANDLE
557rb_libruby_handle(void)
558{
559 return libruby;
560}
561
562static inline void
563translit_char_bin(char *p, int from, int to)
564{
565 while (*p) {
566 if ((unsigned char)*p == from)
567 *p = to;
568 p++;
569 }
570}
571#endif
572
573#ifdef _WIN32
574# define UTF8_PATH 1
575#endif
576
577#ifndef UTF8_PATH
578# define UTF8_PATH 0
579#endif
580#if UTF8_PATH
581# define IF_UTF8_PATH(t, f) t
582#else
583# define IF_UTF8_PATH(t, f) f
584#endif
585
586#if UTF8_PATH
587static VALUE
588str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
589{
590 return rb_str_conv_enc_opts(str, from, to,
591 ECONV_UNDEF_REPLACE|ECONV_INVALID_REPLACE,
592 Qnil);
593}
594#else
595# define str_conv_enc(str, from, to) (str)
596#endif
597
598void ruby_init_loadpath(void);
599
600#if defined(LOAD_RELATIVE)
601static VALUE
602runtime_libruby_path(void)
603{
604#if defined _WIN32 || defined __CYGWIN__
605 DWORD ret;
606 DWORD len = 32;
607 VALUE path;
608 VALUE wsopath = rb_str_new(0, len*sizeof(WCHAR));
609 WCHAR *wlibpath;
610 char *libpath;
611
612 while (wlibpath = (WCHAR *)RSTRING_PTR(wsopath),
613 ret = GetModuleFileNameW(libruby, wlibpath, len),
614 (ret == len))
615 {
616 rb_str_modify_expand(wsopath, len*sizeof(WCHAR));
617 rb_str_set_len(wsopath, (len += len)*sizeof(WCHAR));
618 }
619 if (!ret || ret > len) rb_fatal("failed to get module file name");
620#if defined __CYGWIN__
621 {
622 const int win_to_posix = CCP_WIN_W_TO_POSIX | CCP_RELATIVE;
623 size_t newsize = cygwin_conv_path(win_to_posix, wlibpath, 0, 0);
624 if (!newsize) rb_fatal("failed to convert module path to cygwin");
625 path = rb_str_new(0, newsize);
626 libpath = RSTRING_PTR(path);
627 if (cygwin_conv_path(win_to_posix, wlibpath, libpath, newsize)) {
628 rb_str_resize(path, 0);
629 }
630 }
631#else
632 {
633 DWORD i;
634 for (len = ret, i = 0; i < len; ++i) {
635 if (wlibpath[i] == L'\\') {
636 wlibpath[i] = L'/';
637 ret = i+1; /* chop after the last separator */
638 }
639 }
640 }
641 len = WideCharToMultiByte(CP_UTF8, 0, wlibpath, ret, NULL, 0, NULL, NULL);
642 path = rb_utf8_str_new(0, len);
643 libpath = RSTRING_PTR(path);
644 WideCharToMultiByte(CP_UTF8, 0, wlibpath, ret, libpath, len, NULL, NULL);
645#endif
646 rb_str_resize(wsopath, 0);
647 return path;
648#elif defined(HAVE_DLADDR)
649 Dl_info dli;
650 VALUE fname, path;
651 const void* addr = (void *)(VALUE)expand_include_path;
652
653 if (!dladdr((void *)addr, &dli)) {
654 return rb_str_new(0, 0);
655 }
656#ifdef __linux__
657 else if (origarg.argc > 0 && origarg.argv && dli.dli_fname == origarg.argv[0]) {
658 fname = rb_str_new_cstr("/proc/self/exe");
659 path = rb_readlink(fname, NULL);
660 }
661#endif
662 else {
663 fname = rb_str_new_cstr(dli.dli_fname);
664 path = rb_realpath_internal(Qnil, fname, 1);
665 }
666 rb_str_resize(fname, 0);
667 return path;
668#else
669# error relative load path is not supported on this platform.
670#endif
671}
672#endif
673
674#define INITIAL_LOAD_PATH_MARK rb_intern_const("@gem_prelude_index")
675
676 VALUE ruby_archlibdir_path, ruby_prefix_path;
677
678void
679ruby_init_loadpath(void)
680{
681 VALUE load_path, archlibdir = 0;
682 ID id_initial_load_path_mark;
683 const char *paths = ruby_initial_load_paths;
684
685#if defined LOAD_RELATIVE
686#if !defined ENABLE_MULTIARCH
687# define RUBY_ARCH_PATH ""
688#elif defined RUBY_ARCH
689# define RUBY_ARCH_PATH "/"RUBY_ARCH
690#else
691# define RUBY_ARCH_PATH "/"RUBY_PLATFORM
692#endif
693 char *libpath;
694 VALUE sopath;
695 size_t baselen;
696 const char *p;
697
698 sopath = runtime_libruby_path();
699 libpath = RSTRING_PTR(sopath);
700
701 p = strrchr(libpath, '/');
702 if (p) {
703 static const char libdir[] = "/"
704#ifdef LIBDIR_BASENAME
705 LIBDIR_BASENAME
706#else
707 "lib"
708#endif
709 RUBY_ARCH_PATH;
710 const ptrdiff_t libdir_len = (ptrdiff_t)sizeof(libdir)
711 - rb_strlen_lit(RUBY_ARCH_PATH) - 1;
712 static const char bindir[] = "/bin";
713 const ptrdiff_t bindir_len = (ptrdiff_t)sizeof(bindir) - 1;
714
715 const char *p2 = NULL;
716
717#ifdef ENABLE_MULTIARCH
718 multiarch:
719#endif
720 if (p - libpath >= bindir_len && !STRNCASECMP(p - bindir_len, bindir, bindir_len)) {
721 p -= bindir_len;
722 archlibdir = rb_str_subseq(sopath, 0, p - libpath);
723 rb_str_cat_cstr(archlibdir, libdir);
724 OBJ_FREEZE_RAW(archlibdir);
725 }
726 else if (p - libpath >= libdir_len && !strncmp(p - libdir_len, libdir, libdir_len)) {
727 archlibdir = rb_str_subseq(sopath, 0, (p2 ? p2 : p) - libpath);
728 OBJ_FREEZE_RAW(archlibdir);
729 p -= libdir_len;
730 }
731#ifdef ENABLE_MULTIARCH
732 else if (p2) {
733 p = p2;
734 }
735 else {
736 p2 = p;
737 p = rb_enc_path_last_separator(libpath, p, rb_ascii8bit_encoding());
738 if (p) goto multiarch;
739 p = p2;
740 }
741#endif
742 baselen = p - libpath;
743 }
744 else {
745 baselen = 0;
746 }
747 rb_str_resize(sopath, baselen);
748 libpath = RSTRING_PTR(sopath);
749#define PREFIX_PATH() sopath
750#define BASEPATH() rb_str_buf_cat(rb_str_buf_new(baselen+len), libpath, baselen)
751#define RUBY_RELATIVE(path, len) rb_str_buf_cat(BASEPATH(), (path), (len))
752#else
753 const size_t exec_prefix_len = strlen(ruby_exec_prefix);
754#define RUBY_RELATIVE(path, len) rubylib_path_new((path), (len))
755#define PREFIX_PATH() RUBY_RELATIVE(ruby_exec_prefix, exec_prefix_len)
756#endif
757 rb_gc_register_address(&ruby_prefix_path);
758 ruby_prefix_path = PREFIX_PATH();
759 OBJ_FREEZE_RAW(ruby_prefix_path);
760 if (!archlibdir) archlibdir = ruby_prefix_path;
761 rb_gc_register_address(&ruby_archlibdir_path);
762 ruby_archlibdir_path = archlibdir;
763
764 load_path = GET_VM()->load_path;
765
766 ruby_push_include(getenv("RUBYLIB"), identical_path);
767
768 id_initial_load_path_mark = INITIAL_LOAD_PATH_MARK;
769 while (*paths) {
770 size_t len = strlen(paths);
771 VALUE path = RUBY_RELATIVE(paths, len);
772 rb_ivar_set(path, id_initial_load_path_mark, path);
773 rb_ary_push(load_path, path);
774 paths += len + 1;
775 }
776
777 rb_const_set(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX"), ruby_prefix_path);
778}
779
780
781static void
782add_modules(VALUE *req_list, const char *mod)
783{
784 VALUE list = *req_list;
785 VALUE feature;
786
787 if (!list) {
788 *req_list = list = rb_ary_hidden_new(0);
789 }
790 feature = rb_str_cat_cstr(rb_str_tmp_new(0), mod);
791 rb_ary_push(list, feature);
792}
793
794static void
795require_libraries(VALUE *req_list)
796{
797 VALUE list = *req_list;
798 VALUE self = rb_vm_top_self();
799 ID require;
800 rb_encoding *extenc = rb_default_external_encoding();
801
802 CONST_ID(require, "require");
803 while (list && RARRAY_LEN(list) > 0) {
804 VALUE feature = rb_ary_shift(list);
805 rb_enc_associate(feature, extenc);
806 RBASIC_SET_CLASS_RAW(feature, rb_cString);
807 OBJ_FREEZE(feature);
808 rb_funcallv(self, require, 1, &feature);
809 }
810 *req_list = 0;
811}
812
813static const struct rb_block*
814toplevel_context(rb_binding_t *bind)
815{
816 return &bind->block;
817}
818
819static int
820process_sflag(int sflag)
821{
822 if (sflag > 0) {
823 long n;
824 const VALUE *args;
825 VALUE argv = rb_argv;
826
827 n = RARRAY_LEN(argv);
828 args = RARRAY_CONST_PTR(argv);
829 while (n > 0) {
830 VALUE v = *args++;
831 char *s = StringValuePtr(v);
832 char *p;
833 int hyphen = FALSE;
834
835 if (s[0] != '-')
836 break;
837 n--;
838 if (s[1] == '-' && s[2] == '\0')
839 break;
840
841 v = Qtrue;
842 /* check if valid name before replacing - with _ */
843 for (p = s + 1; *p; p++) {
844 if (*p == '=') {
845 *p++ = '\0';
846 v = rb_str_new2(p);
847 break;
848 }
849 if (*p == '-') {
850 hyphen = TRUE;
851 }
852 else if (*p != '_' && !ISALNUM(*p)) {
853 VALUE name_error[2];
854 name_error[0] =
855 rb_str_new2("invalid name for global variable - ");
856 if (!(p = strchr(p, '='))) {
857 rb_str_cat2(name_error[0], s);
858 }
859 else {
860 rb_str_cat(name_error[0], s, p - s);
861 }
862 name_error[1] = args[-1];
863 rb_exc_raise(rb_class_new_instance(2, name_error, rb_eNameError));
864 }
865 }
866 s[0] = '$';
867 if (hyphen) {
868 for (p = s + 1; *p; ++p) {
869 if (*p == '-')
870 *p = '_';
871 }
872 }
873 rb_gv_set(s, v);
874 }
875 n = RARRAY_LEN(argv) - n;
876 while (n--) {
877 rb_ary_shift(argv);
878 }
879 return -1;
880 }
881 return sflag;
882}
883
884static long proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt);
885
886static void
887moreswitches(const char *s, ruby_cmdline_options_t *opt, int envopt)
888{
889 long argc, i, len;
890 char **argv, *p;
891 const char *ap = 0;
892 VALUE argstr, argary;
893 void *ptr;
894
895 VALUE src_enc_name = opt->src.enc.name;
896 VALUE ext_enc_name = opt->ext.enc.name;
897 VALUE int_enc_name = opt->intern.enc.name;
898 ruby_features_t feat = opt->features;
899 ruby_features_t warn = opt->warn;
900 long backtrace_length_limit = opt->backtrace_length_limit;
901 const char *crash_report = opt->crash_report;
902
903 while (ISSPACE(*s)) s++;
904 if (!*s) return;
905
906 opt->src.enc.name = opt->ext.enc.name = opt->intern.enc.name = 0;
907
908 const int hyphen = *s != '-';
909 argstr = rb_str_tmp_new((len = strlen(s)) + hyphen);
910 argary = rb_str_tmp_new(0);
911
912 p = RSTRING_PTR(argstr);
913 if (hyphen) *p = '-';
914 memcpy(p + hyphen, s, len + 1);
915 ap = 0;
916 rb_str_cat(argary, (char *)&ap, sizeof(ap));
917 while (*p) {
918 ap = p;
919 rb_str_cat(argary, (char *)&ap, sizeof(ap));
920 while (*p && !ISSPACE(*p)) ++p;
921 if (!*p) break;
922 *p++ = '\0';
923 while (ISSPACE(*p)) ++p;
924 }
925 argc = RSTRING_LEN(argary) / sizeof(ap);
926 ap = 0;
927 rb_str_cat(argary, (char *)&ap, sizeof(ap));
928 argv = ptr = ALLOC_N(char *, argc);
929 MEMMOVE(argv, RSTRING_PTR(argary), char *, argc);
930
931 while ((i = proc_options(argc, argv, opt, envopt)) > 1 && envopt && (argc -= i) > 0) {
932 argv += i;
933 if (**argv != '-') {
934 *--*argv = '-';
935 }
936 if ((*argv)[1]) {
937 ++argc;
938 --argv;
939 }
940 }
941
942 if (src_enc_name) {
943 opt->src.enc.name = src_enc_name;
944 }
945 if (ext_enc_name) {
946 opt->ext.enc.name = ext_enc_name;
947 }
948 if (int_enc_name) {
949 opt->intern.enc.name = int_enc_name;
950 }
951 FEATURE_SET_RESTORE(opt->features, feat);
952 FEATURE_SET_RESTORE(opt->warn, warn);
953 if (BACKTRACE_LENGTH_LIMIT_VALID_P(backtrace_length_limit)) {
954 opt->backtrace_length_limit = backtrace_length_limit;
955 }
956 if (crash_report) {
957 opt->crash_report = crash_report;
958 }
959
960 ruby_xfree(ptr);
961 /* get rid of GC */
962 rb_str_resize(argary, 0);
963 rb_str_resize(argstr, 0);
964}
965
966static int
967name_match_p(const char *name, const char *str, size_t len)
968{
969 if (len == 0) return 0;
970 while (1) {
971 while (TOLOWER(*str) == *name) {
972 if (!--len) return 1;
973 ++name;
974 ++str;
975 }
976 if (*str != '-' && *str != '_') return 0;
977 while (ISALNUM(*name)) name++;
978 if (*name != '-' && *name != '_') return 0;
979 ++name;
980 ++str;
981 if (--len == 0) return 1;
982 }
983}
984
985#define NAME_MATCH_P(name, str, len) \
986 ((len) < (int)sizeof(name) && name_match_p((name), (str), (len)))
987
988#define UNSET_WHEN(name, bit, str, len) \
989 if (NAME_MATCH_P((name), (str), (len))) { \
990 *(unsigned int *)arg &= ~(bit); \
991 return; \
992 }
993
994#define SET_WHEN(name, bit, str, len) \
995 if (NAME_MATCH_P((name), (str), (len))) { \
996 *(unsigned int *)arg |= (bit); \
997 return; \
998 }
999
1000#define LITERAL_NAME_ELEMENT(name) #name
1001
1002static void
1003feature_option(const char *str, int len, void *arg, const unsigned int enable)
1004{
1005 static const char list[] = EACH_FEATURES(LITERAL_NAME_ELEMENT, ", ");
1006 ruby_features_t *argp = arg;
1007 unsigned int mask = ~0U;
1008 unsigned int set = 0U;
1009#if AMBIGUOUS_FEATURE_NAMES
1010 int matched = 0;
1011# define FEATURE_FOUND ++matched
1012#else
1013# define FEATURE_FOUND goto found
1014#endif
1015#define SET_FEATURE(bit) \
1016 if (NAME_MATCH_P(#bit, str, len)) {set |= mask = FEATURE_BIT(bit); FEATURE_FOUND;}
1017 EACH_FEATURES(SET_FEATURE, ;);
1018 if (NAME_MATCH_P("jit", str, len)) { // This allows you to cancel --jit
1019 set |= mask = FEATURE_BIT(jit);
1020 goto found;
1021 }
1022 if (NAME_MATCH_P("all", str, len)) {
1023 // YJIT and RJIT cannot be enabled at the same time. We enable only one for --enable=all.
1024 mask &= ~feature_jit_mask | FEATURE_BIT(jit);
1025 goto found;
1026 }
1027#if AMBIGUOUS_FEATURE_NAMES
1028 if (matched == 1) goto found;
1029 if (matched > 1) {
1030 VALUE mesg = rb_sprintf("ambiguous feature: `%.*s' (", len, str);
1031#define ADD_FEATURE_NAME(bit) \
1032 if (FEATURE_BIT(bit) & set) { \
1033 rb_str_cat_cstr(mesg, #bit); \
1034 if (--matched) rb_str_cat_cstr(mesg, ", "); \
1035 }
1036 EACH_FEATURES(ADD_FEATURE_NAME, ;);
1037 rb_str_cat_cstr(mesg, ")");
1038 rb_exc_raise(rb_exc_new_str(rb_eRuntimeError, mesg));
1039#undef ADD_FEATURE_NAME
1040 }
1041#else
1042 (void)set;
1043#endif
1044 rb_warn("unknown argument for --%s: `%.*s'",
1045 enable ? "enable" : "disable", len, str);
1046 rb_warn("features are [%.*s].", (int)strlen(list), list);
1047 return;
1048
1049 found:
1050 FEATURE_SET_TO(*argp, mask, (mask & enable));
1051 return;
1052}
1053
1054static void
1055enable_option(const char *str, int len, void *arg)
1056{
1057 feature_option(str, len, arg, ~0U);
1058}
1059
1060static void
1061disable_option(const char *str, int len, void *arg)
1062{
1063 feature_option(str, len, arg, 0U);
1064}
1065
1066 RUBY_EXTERN const int ruby_patchlevel;
1067int ruby_env_debug_option(const char *str, int len, void *arg);
1068
1069static void
1070debug_option(const char *str, int len, void *arg)
1071{
1072 static const char list[] = EACH_DEBUG_FEATURES(LITERAL_NAME_ELEMENT, ", ");
1073 ruby_features_t *argp = arg;
1074#define SET_WHEN_DEBUG(bit) \
1075 if (NAME_MATCH_P(#bit, str, len)) { \
1076 FEATURE_SET(*argp, DEBUG_BIT(bit)); \
1077 return; \
1078 }
1079 EACH_DEBUG_FEATURES(SET_WHEN_DEBUG, ;);
1080#ifdef RUBY_DEVEL
1081 if (ruby_patchlevel < 0 && ruby_env_debug_option(str, len, 0)) return;
1082#endif
1083 rb_warn("unknown argument for --debug: `%.*s'", len, str);
1084 rb_warn("debug features are [%.*s].", (int)strlen(list), list);
1085}
1086
1087static int
1088memtermspn(const char *str, char term, int len)
1089{
1090 RUBY_ASSERT(len >= 0);
1091 if (len <= 0) return 0;
1092 const char *next = memchr(str, term, len);
1093 return next ? (int)(next - str) : len;
1094}
1095
1096static const char additional_opt_sep = '+';
1097
1098static unsigned int
1099dump_additional_option(const char *str, int len, unsigned int bits, const char *name)
1100{
1101 int w;
1102 for (; len-- > 0 && *str++ == additional_opt_sep; len -= w, str += w) {
1103 w = memtermspn(str, additional_opt_sep, len);
1104#define SET_ADDITIONAL(bit) if (NAME_MATCH_P(#bit, str, w)) { \
1105 if (bits & DUMP_BIT(bit)) \
1106 rb_warn("duplicate option to dump %s: `%.*s'", name, w, str); \
1107 bits |= DUMP_BIT(bit); \
1108 continue; \
1109 }
1110 if (dump_error_tolerant_bits & bits) {
1111 SET_ADDITIONAL(error_tolerant);
1112 }
1113 rb_warn("don't know how to dump %s with `%.*s'", name, w, str);
1114 }
1115 return bits;
1116}
1117
1118static void
1119dump_option(const char *str, int len, void *arg)
1120{
1121 static const char list[] = EACH_DUMPS(LITERAL_NAME_ELEMENT, ", ");
1122 int w = memtermspn(str, additional_opt_sep, len);
1123
1124#define SET_WHEN_DUMP(bit) \
1125 if (NAME_MATCH_P(#bit, (str), (w))) { \
1126 *(unsigned int *)arg |= \
1127 dump_additional_option(str + w, len - w, DUMP_BIT(bit), #bit); \
1128 return; \
1129 }
1130 EACH_DUMPS(SET_WHEN_DUMP, ;);
1131 rb_warn("don't know how to dump `%.*s',", len, str);
1132 rb_warn("but only [%.*s].", (int)strlen(list), list);
1133}
1134
1135static void
1136set_option_encoding_once(const char *type, VALUE *name, const char *e, long elen)
1137{
1138 VALUE ename;
1139
1140 if (!elen) elen = strlen(e);
1141 ename = rb_str_new(e, elen);
1142
1143 if (*name &&
1144 rb_funcall(ename, rb_intern("casecmp"), 1, *name) != INT2FIX(0)) {
1145 rb_raise(rb_eRuntimeError,
1146 "%s already set to %"PRIsVALUE, type, *name);
1147 }
1148 *name = ename;
1149}
1150
1151#define set_internal_encoding_once(opt, e, elen) \
1152 set_option_encoding_once("default_internal", &(opt)->intern.enc.name, (e), (elen))
1153#define set_external_encoding_once(opt, e, elen) \
1154 set_option_encoding_once("default_external", &(opt)->ext.enc.name, (e), (elen))
1155#define set_source_encoding_once(opt, e, elen) \
1156 set_option_encoding_once("source", &(opt)->src.enc.name, (e), (elen))
1157
1158#define yjit_opt_match_noarg(s, l, name) \
1159 opt_match(s, l, name) && (*(s) ? (rb_warn("argument to --yjit-" name " is ignored"), 1) : 1)
1160#define yjit_opt_match_arg(s, l, name) \
1161 opt_match(s, l, name) && (*(s) && *(s+1) ? 1 : (rb_raise(rb_eRuntimeError, "--yjit-" name " needs an argument"), 0))
1162
1163#if USE_YJIT
1164static bool
1165setup_yjit_options(const char *s)
1166{
1167 // The option parsing is done in yjit/src/options.rs
1168 bool rb_yjit_parse_option(const char* s);
1169 bool success = rb_yjit_parse_option(s);
1170
1171 if (success) {
1172 return true;
1173 }
1174
1175 rb_raise(
1176 rb_eRuntimeError,
1177 "invalid YJIT option `%s' (--help will show valid yjit options)",
1178 s
1179 );
1180}
1181#endif
1182
1183/*
1184 * Following proc_*_option functions are tree kinds:
1185 *
1186 * - with a required argument, takes also `argc` and `argv`, and
1187 * returns the number of consumed argv including the option itself.
1188 *
1189 * - with a mandatory argument just after the option.
1190 *
1191 * - no required argument, this returns the address of
1192 * the next character after the last consumed character.
1193 */
1194
1195/* optional */
1196static const char *
1197proc_W_option(ruby_cmdline_options_t *opt, const char *s, int *warning)
1198{
1199 if (s[1] == ':') {
1200 unsigned int bits = 0;
1201 static const char no_prefix[] = "no-";
1202 int enable = strncmp(s += 2, no_prefix, sizeof(no_prefix)-1) != 0;
1203 if (!enable) s += sizeof(no_prefix)-1;
1204 size_t len = strlen(s);
1205 if (NAME_MATCH_P("deprecated", s, len)) {
1206 bits = 1U << RB_WARN_CATEGORY_DEPRECATED;
1207 }
1208 else if (NAME_MATCH_P("experimental", s, len)) {
1209 bits = 1U << RB_WARN_CATEGORY_EXPERIMENTAL;
1210 }
1211 else if (NAME_MATCH_P("performance", s, len)) {
1212 bits = 1U << RB_WARN_CATEGORY_PERFORMANCE;
1213 }
1214 else {
1215 rb_warn("unknown warning category: `%s'", s);
1216 }
1217 if (bits) FEATURE_SET_TO(opt->warn, bits, enable ? bits : 0);
1218 return 0;
1219 }
1220 else {
1221 size_t numlen;
1222 int v = 2; /* -W as -W2 */
1223
1224 if (*++s) {
1225 v = scan_oct(s, 1, &numlen);
1226 if (numlen == 0)
1227 v = 2;
1228 s += numlen;
1229 }
1230 if (!opt->warning) {
1231 switch (v) {
1232 case 0:
1233 ruby_verbose = Qnil;
1234 break;
1235 case 1:
1236 ruby_verbose = Qfalse;
1237 break;
1238 default:
1239 ruby_verbose = Qtrue;
1240 break;
1241 }
1242 }
1243 *warning = 1;
1244 switch (v) {
1245 case 0:
1246 FEATURE_SET_TO(opt->warn, RB_WARN_CATEGORY_DEFAULT_BITS, 0);
1247 break;
1248 case 1:
1249 FEATURE_SET_TO(opt->warn, 1U << RB_WARN_CATEGORY_DEPRECATED, 0);
1250 break;
1251 default:
1252 FEATURE_SET(opt->warn, RB_WARN_CATEGORY_DEFAULT_BITS);
1253 break;
1254 }
1255 return s;
1256 }
1257}
1258
1259/* required */
1260static long
1261proc_e_option(ruby_cmdline_options_t *opt, const char *s, long argc, char **argv)
1262{
1263 long n = 1;
1264 forbid_setid("-e");
1265 if (!*++s) {
1266 if (!--argc)
1267 rb_raise(rb_eRuntimeError, "no code specified for -e");
1268 s = *++argv;
1269 n++;
1270 }
1271 if (!opt->e_script) {
1272 opt->e_script = rb_str_new(0, 0);
1273 if (opt->script == 0)
1274 opt->script = "-e";
1275 }
1276 rb_str_cat2(opt->e_script, s);
1277 rb_str_cat2(opt->e_script, "\n");
1278 return n;
1279}
1280
1281/* optional */
1282static const char *
1283proc_K_option(ruby_cmdline_options_t *opt, const char *s)
1284{
1285 if (*++s) {
1286 const char *enc_name = 0;
1287 switch (*s) {
1288 case 'E': case 'e':
1289 enc_name = "EUC-JP";
1290 break;
1291 case 'S': case 's':
1292 enc_name = "Windows-31J";
1293 break;
1294 case 'U': case 'u':
1295 enc_name = "UTF-8";
1296 break;
1297 case 'N': case 'n': case 'A': case 'a':
1298 enc_name = "ASCII-8BIT";
1299 break;
1300 }
1301 if (enc_name) {
1302 opt->src.enc.name = rb_str_new2(enc_name);
1303 if (!opt->ext.enc.name)
1304 opt->ext.enc.name = opt->src.enc.name;
1305 }
1306 s++;
1307 }
1308 return s;
1309}
1310
1311/* optional */
1312static const char *
1313proc_0_option(ruby_cmdline_options_t *opt, const char *s)
1314{
1315 size_t numlen;
1316 int v;
1317 char c;
1318
1319 v = scan_oct(s, 4, &numlen);
1320 s += numlen;
1321 if (v > 0377)
1322 rb_rs = Qnil;
1323 else if (v == 0 && numlen >= 2) {
1324 rb_rs = rb_str_new2("");
1325 }
1326 else {
1327 c = v & 0xff;
1328 rb_rs = rb_str_new(&c, 1);
1329 }
1330 return s;
1331}
1332
1333/* mandatory */
1334static void
1335proc_encoding_option(ruby_cmdline_options_t *opt, const char *s, const char *opt_name)
1336{
1337 char *p;
1338# define set_encoding_part(type) \
1339 if (!(p = strchr(s, ':'))) { \
1340 set_##type##_encoding_once(opt, s, 0); \
1341 return; \
1342 } \
1343 else if (p > s) { \
1344 set_##type##_encoding_once(opt, s, p-s); \
1345 }
1346 set_encoding_part(external);
1347 if (!*(s = ++p)) return;
1348 set_encoding_part(internal);
1349 if (!*(s = ++p)) return;
1350#if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
1351 set_encoding_part(source);
1352 if (!*(s = ++p)) return;
1353#endif
1354 rb_raise(rb_eRuntimeError, "extra argument for %s: %s", opt_name, s);
1355# undef set_encoding_part
1356 UNREACHABLE;
1357}
1358
1359static long
1360proc_long_options(ruby_cmdline_options_t *opt, const char *s, long argc, char **argv, int envopt)
1361{
1362 size_t n;
1363 long argc0 = argc;
1364# define is_option_end(c, allow_hyphen) \
1365 (!(c) || ((allow_hyphen) && (c) == '-') || (c) == '=')
1366# define check_envopt(name, allow_envopt) \
1367 (((allow_envopt) || !envopt) ? (void)0 : \
1368 rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --" name))
1369# define need_argument(name, s, needs_arg, next_arg) \
1370 ((*(s) ? !*++(s) : (next_arg) && (!argc || !((s) = argv[1]) || (--argc, ++argv, 0))) && (needs_arg) ? \
1371 rb_raise(rb_eRuntimeError, "missing argument for --" name) \
1372 : (void)0)
1373# define is_option_with_arg(name, allow_hyphen, allow_envopt) \
1374 is_option_with_optarg(name, allow_hyphen, allow_envopt, Qtrue, Qtrue)
1375# define is_option_with_optarg(name, allow_hyphen, allow_envopt, needs_arg, next_arg) \
1376 (strncmp((name), s, n = sizeof(name) - 1) == 0 && is_option_end(s[n], (allow_hyphen)) && \
1377 (s[n] != '-' || s[n+1]) ? \
1378 (check_envopt(name, (allow_envopt)), s += n, \
1379 need_argument(name, s, needs_arg, next_arg), 1) : 0)
1380
1381 if (strcmp("copyright", s) == 0) {
1382 if (envopt) goto noenvopt_long;
1383 opt->dump |= DUMP_BIT(copyright);
1384 }
1385 else if (is_option_with_optarg("debug", Qtrue, Qtrue, Qfalse, Qfalse)) {
1386 if (s && *s) {
1387 ruby_each_words(s, debug_option, &opt->features);
1388 }
1389 else {
1390 ruby_debug = Qtrue;
1391 ruby_verbose = Qtrue;
1392 }
1393 }
1394 else if (is_option_with_arg("enable", Qtrue, Qtrue)) {
1395 ruby_each_words(s, enable_option, &opt->features);
1396 }
1397 else if (is_option_with_arg("disable", Qtrue, Qtrue)) {
1398 ruby_each_words(s, disable_option, &opt->features);
1399 }
1400 else if (is_option_with_arg("encoding", Qfalse, Qtrue)) {
1401 proc_encoding_option(opt, s, "--encoding");
1402 }
1403 else if (is_option_with_arg("internal-encoding", Qfalse, Qtrue)) {
1404 set_internal_encoding_once(opt, s, 0);
1405 }
1406 else if (is_option_with_arg("external-encoding", Qfalse, Qtrue)) {
1407 set_external_encoding_once(opt, s, 0);
1408 }
1409 else if (is_option_with_arg("parser", Qfalse, Qtrue)) {
1410 if (strcmp("prism", s) == 0) {
1411 (*rb_ruby_prism_ptr()) = true;
1412 rb_warn("The compiler based on the Prism parser is currently experimental and "
1413 "compatibility with the compiler based on parse.y "
1414 "is not yet complete. Please report any issues you "
1415 "find on the `ruby/prism` issue tracker.");
1416 }
1417 else if (strcmp("parse.y", s) == 0) {
1418 // default behavior
1419 }
1420 else {
1421 rb_raise(rb_eRuntimeError, "unknown parser %s", s);
1422 }
1423 }
1424#if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
1425 else if (is_option_with_arg("source-encoding", Qfalse, Qtrue)) {
1426 set_source_encoding_once(opt, s, 0);
1427 }
1428#endif
1429 else if (strcmp("version", s) == 0) {
1430 if (envopt) goto noenvopt_long;
1431 opt->dump |= DUMP_BIT(version);
1432 }
1433 else if (strcmp("verbose", s) == 0) {
1434 opt->verbose = 1;
1435 ruby_verbose = Qtrue;
1436 }
1437 else if (strcmp("jit", s) == 0) {
1438#if USE_YJIT || USE_RJIT
1439 FEATURE_SET(opt->features, FEATURE_BIT(jit));
1440#else
1441 rb_warn("Ruby was built without JIT support");
1442#endif
1443 }
1444 else if (is_option_with_optarg("rjit", '-', true, false, false)) {
1445#if USE_RJIT
1446 extern void rb_rjit_setup_options(const char *s, struct rb_rjit_options *rjit_opt);
1447 FEATURE_SET(opt->features, FEATURE_BIT(rjit));
1448 rb_rjit_setup_options(s, &opt->rjit);
1449#else
1450 rb_warn("RJIT support is disabled.");
1451#endif
1452 }
1453 else if (is_option_with_optarg("yjit", '-', true, false, false)) {
1454#if USE_YJIT
1455 FEATURE_SET(opt->features, FEATURE_BIT(yjit));
1456 setup_yjit_options(s);
1457#else
1458 rb_warn("Ruby was built without YJIT support."
1459 " You may need to install rustc to build Ruby with YJIT.");
1460#endif
1461 }
1462 else if (strcmp("yydebug", s) == 0) {
1463 if (envopt) goto noenvopt_long;
1464 opt->dump |= DUMP_BIT(yydebug);
1465 }
1466 else if (is_option_with_arg("dump", Qfalse, Qfalse)) {
1467 ruby_each_words(s, dump_option, &opt->dump);
1468 }
1469 else if (strcmp("help", s) == 0) {
1470 if (envopt) goto noenvopt_long;
1471 opt->dump |= DUMP_BIT(help);
1472 return 0;
1473 }
1474 else if (is_option_with_arg("backtrace-limit", Qfalse, Qtrue)) {
1475 char *e;
1476 long n = strtol(s, &e, 10);
1477 if (errno == ERANGE || !BACKTRACE_LENGTH_LIMIT_VALID_P(n) || *e) {
1478 rb_raise(rb_eRuntimeError, "wrong limit for backtrace length");
1479 }
1480 else {
1481 opt->backtrace_length_limit = n;
1482 }
1483 }
1484 else if (is_option_with_arg("crash-report", true, true)) {
1485 opt->crash_report = s;
1486 }
1487 else {
1488 rb_raise(rb_eRuntimeError,
1489 "invalid option --%s (-h will show valid options)", s);
1490 }
1491 return argc0 - argc + 1;
1492
1493 noenvopt_long:
1494 rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --%s", s);
1495# undef is_option_end
1496# undef check_envopt
1497# undef need_argument
1498# undef is_option_with_arg
1499# undef is_option_with_optarg
1500 UNREACHABLE_RETURN(0);
1501}
1502
1503static long
1504proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
1505{
1506 long n, argc0 = argc;
1507 const char *s;
1508 int warning = opt->warning;
1509
1510 if (argc <= 0 || !argv)
1511 return 0;
1512
1513 for (argc--, argv++; argc > 0; argc--, argv++) {
1514 const char *const arg = argv[0];
1515 if (!arg || arg[0] != '-' || !arg[1])
1516 break;
1517
1518 s = arg + 1;
1519 reswitch:
1520 switch (*s) {
1521 case 'a':
1522 if (envopt) goto noenvopt;
1523 opt->do_split = TRUE;
1524 s++;
1525 goto reswitch;
1526
1527 case 'p':
1528 if (envopt) goto noenvopt;
1529 opt->do_print = TRUE;
1530 /* through */
1531 case 'n':
1532 if (envopt) goto noenvopt;
1533 opt->do_loop = TRUE;
1534 s++;
1535 goto reswitch;
1536
1537 case 'd':
1538 ruby_debug = Qtrue;
1539 ruby_verbose = Qtrue;
1540 s++;
1541 goto reswitch;
1542
1543 case 'y':
1544 if (envopt) goto noenvopt;
1545 opt->dump |= DUMP_BIT(yydebug);
1546 s++;
1547 goto reswitch;
1548
1549 case 'v':
1550 if (opt->verbose) {
1551 s++;
1552 goto reswitch;
1553 }
1554 opt->dump |= DUMP_BIT(version_v);
1555 opt->verbose = 1;
1556 case 'w':
1557 if (!opt->warning) {
1558 warning = 1;
1559 ruby_verbose = Qtrue;
1560 }
1561 FEATURE_SET(opt->warn, RB_WARN_CATEGORY_DEFAULT_BITS);
1562 s++;
1563 goto reswitch;
1564
1565 case 'W':
1566 if (!(s = proc_W_option(opt, s, &warning))) break;
1567 goto reswitch;
1568
1569 case 'c':
1570 if (envopt) goto noenvopt;
1571 opt->dump |= DUMP_BIT(syntax);
1572 s++;
1573 goto reswitch;
1574
1575 case 's':
1576 if (envopt) goto noenvopt;
1577 forbid_setid("-s");
1578 if (!opt->sflag) opt->sflag = 1;
1579 s++;
1580 goto reswitch;
1581
1582 case 'h':
1583 if (envopt) goto noenvopt;
1584 opt->dump |= DUMP_BIT(usage);
1585 goto switch_end;
1586
1587 case 'l':
1588 if (envopt) goto noenvopt;
1589 opt->do_line = TRUE;
1590 rb_output_rs = rb_rs;
1591 s++;
1592 goto reswitch;
1593
1594 case 'S':
1595 if (envopt) goto noenvopt;
1596 forbid_setid("-S");
1597 opt->do_search = TRUE;
1598 s++;
1599 goto reswitch;
1600
1601 case 'e':
1602 if (envopt) goto noenvopt;
1603 if (!(n = proc_e_option(opt, s, argc, argv))) break;
1604 --n;
1605 argc -= n;
1606 argv += n;
1607 break;
1608
1609 case 'r':
1610 forbid_setid("-r");
1611 if (*++s) {
1612 add_modules(&opt->req_list, s);
1613 }
1614 else if (argc > 1) {
1615 add_modules(&opt->req_list, argv[1]);
1616 argc--, argv++;
1617 }
1618 break;
1619
1620 case 'i':
1621 if (envopt) goto noenvopt;
1622 forbid_setid("-i");
1623 ruby_set_inplace_mode(s + 1);
1624 break;
1625
1626 case 'x':
1627 if (envopt) goto noenvopt;
1628 forbid_setid("-x");
1629 opt->xflag = TRUE;
1630 s++;
1631 if (*s && chdir(s) < 0) {
1632 rb_fatal("Can't chdir to %s", s);
1633 }
1634 break;
1635
1636 case 'C':
1637 case 'X':
1638 if (envopt) goto noenvopt;
1639 if (!*++s && (!--argc || !(s = *++argv) || !*s)) {
1640 rb_fatal("Can't chdir");
1641 }
1642 if (chdir(s) < 0) {
1643 rb_fatal("Can't chdir to %s", s);
1644 }
1645 break;
1646
1647 case 'F':
1648 if (envopt) goto noenvopt;
1649 if (*++s) {
1650 rb_fs = rb_reg_new(s, strlen(s), 0);
1651 }
1652 break;
1653
1654 case 'E':
1655 if (!*++s && (!--argc || !(s = *++argv))) {
1656 rb_raise(rb_eRuntimeError, "missing argument for -E");
1657 }
1658 proc_encoding_option(opt, s, "-E");
1659 break;
1660
1661 case 'U':
1662 set_internal_encoding_once(opt, "UTF-8", 0);
1663 ++s;
1664 goto reswitch;
1665
1666 case 'K':
1667 if (!(s = proc_K_option(opt, s))) break;
1668 goto reswitch;
1669
1670 case 'I':
1671 forbid_setid("-I");
1672 if (*++s)
1673 ruby_incpush_expand(s);
1674 else if (argc > 1) {
1675 ruby_incpush_expand(argv[1]);
1676 argc--, argv++;
1677 }
1678 break;
1679
1680 case '0':
1681 if (envopt) goto noenvopt;
1682 if (!(s = proc_0_option(opt, s))) break;
1683 goto reswitch;
1684
1685 case '-':
1686 if (!s[1] || (s[1] == '\r' && !s[2])) {
1687 argc--, argv++;
1688 goto switch_end;
1689 }
1690 s++;
1691
1692 if (!(n = proc_long_options(opt, s, argc, argv, envopt))) goto switch_end;
1693 --n;
1694 argc -= n;
1695 argv += n;
1696 break;
1697
1698 case '\r':
1699 if (!s[1])
1700 break;
1701
1702 default:
1703 rb_raise(rb_eRuntimeError,
1704 "invalid option -%c (-h will show valid options)",
1705 (int)(unsigned char)*s);
1706 goto switch_end;
1707
1708 noenvopt:
1709 /* "EIdvwWrKU" only */
1710 rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: -%c", *s);
1711 break;
1712
1713 case 0:
1714 break;
1715 }
1716 }
1717
1718 switch_end:
1719 if (warning) opt->warning = warning;
1720 return argc0 - argc;
1721}
1722
1723void Init_builtin_features(void);
1724
1725static void
1726ruby_init_prelude(void)
1727{
1728 Init_builtin_features();
1729 rb_const_remove(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX"));
1730}
1731
1732void rb_call_builtin_inits(void);
1733
1734// Initialize extra optional exts linked statically.
1735// This empty definition will be replaced with the actual strong symbol by linker.
1736#if RBIMPL_HAS_ATTRIBUTE(weak)
1737 __attribute__((weak))
1738#endif
1739void
1740Init_extra_exts(void)
1741{
1742}
1743
1744static void
1745ruby_opt_init(ruby_cmdline_options_t *opt)
1746{
1747 if (opt->dump & dump_exit_bits) return;
1748
1749 if (FEATURE_SET_P(opt->features, gems)) {
1750 rb_define_module("Gem");
1751 if (opt->features.set & FEATURE_BIT(error_highlight)) {
1752 rb_define_module("ErrorHighlight");
1753 }
1754 if (opt->features.set & FEATURE_BIT(did_you_mean)) {
1755 rb_define_module("DidYouMean");
1756 }
1757 if (opt->features.set & FEATURE_BIT(syntax_suggest)) {
1758 rb_define_module("SyntaxSuggest");
1759 }
1760 }
1761
1762 rb_warning_category_update(opt->warn.mask, opt->warn.set);
1763
1764 /* [Feature #19785] Warning for removed GC environment variable.
1765 * Remove this in Ruby 3.4. */
1766 if (getenv("RUBY_GC_HEAP_INIT_SLOTS")) {
1767 rb_warn_deprecated("The environment variable RUBY_GC_HEAP_INIT_SLOTS",
1768 "environment variables RUBY_GC_HEAP_%d_INIT_SLOTS");
1769 }
1770
1771 if (getenv("RUBY_FREE_AT_EXIT")) {
1772 rb_category_warn(RB_WARN_CATEGORY_EXPERIMENTAL, "Free at exit is experimental and may be unstable");
1773 rb_free_at_exit = true;
1774 }
1775
1776#if USE_RJIT
1777 // rb_call_builtin_inits depends on RubyVM::RJIT.enabled?
1778 if (opt->rjit.on)
1779 rb_rjit_enabled = true;
1780 if (opt->rjit.stats)
1781 rb_rjit_stats_enabled = true;
1782 if (opt->rjit.trace_exits)
1783 rb_rjit_trace_exits_enabled = true;
1784#endif
1785
1786 Init_ext(); /* load statically linked extensions before rubygems */
1787 Init_extra_exts();
1788 rb_call_builtin_inits();
1789 ruby_init_prelude();
1790
1791 // Initialize JITs after prelude because JITing prelude is typically not optimal.
1792#if USE_RJIT
1793 // Also, rb_rjit_init is safe only after rb_call_builtin_inits() defines RubyVM::RJIT::Compiler.
1794 if (opt->rjit.on)
1795 rb_rjit_init(&opt->rjit);
1796#endif
1797#if USE_YJIT
1798 rb_yjit_init(opt->yjit);
1799#endif
1800
1801 ruby_set_script_name(opt->script_name);
1802 require_libraries(&opt->req_list);
1803}
1804
1805static int
1806opt_enc_index(VALUE enc_name)
1807{
1808 const char *s = RSTRING_PTR(enc_name);
1809 int i = rb_enc_find_index(s);
1810
1811 if (i < 0) {
1812 rb_raise(rb_eRuntimeError, "unknown encoding name - %s", s);
1813 }
1814 else if (rb_enc_dummy_p(rb_enc_from_index(i))) {
1815 rb_raise(rb_eRuntimeError, "dummy encoding is not acceptable - %s ", s);
1816 }
1817 return i;
1818}
1819
1820#define rb_progname (GET_VM()->progname)
1821#define rb_orig_progname (GET_VM()->orig_progname)
1822 VALUE rb_argv0;
1823 VALUE rb_e_script;
1824
1825static VALUE
1826false_value(ID _x, VALUE *_y)
1827{
1828 return Qfalse;
1829}
1830
1831static VALUE
1832true_value(ID _x, VALUE *_y)
1833{
1834 return Qtrue;
1835}
1836
1837#define rb_define_readonly_boolean(name, val) \
1838 rb_define_virtual_variable((name), (val) ? true_value : false_value, 0)
1839
1840static VALUE
1841uscore_get(void)
1842{
1843 VALUE line;
1844
1845 line = rb_lastline_get();
1846 if (!RB_TYPE_P(line, T_STRING)) {
1847 rb_raise(rb_eTypeError, "$_ value need to be String (%s given)",
1848 NIL_P(line) ? "nil" : rb_obj_classname(line));
1849 }
1850 return line;
1851}
1852
1853/*
1854 * call-seq:
1855 * sub(pattern, replacement) -> $_
1856 * sub(pattern) {|...| block } -> $_
1857 *
1858 * Equivalent to <code>$_.sub(<i>args</i>)</code>, except that
1859 * <code>$_</code> will be updated if substitution occurs.
1860 * Available only when -p/-n command line option specified.
1861 */
1862
1863static VALUE
1864rb_f_sub(int argc, VALUE *argv, VALUE _)
1865{
1866 VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("sub"), argc, argv);
1867 rb_lastline_set(str);
1868 return str;
1869}
1870
1871/*
1872 * call-seq:
1873 * gsub(pattern, replacement) -> $_
1874 * gsub(pattern) {|...| block } -> $_
1875 *
1876 * Equivalent to <code>$_.gsub...</code>, except that <code>$_</code>
1877 * will be updated if substitution occurs.
1878 * Available only when -p/-n command line option specified.
1879 *
1880 */
1881
1882static VALUE
1883rb_f_gsub(int argc, VALUE *argv, VALUE _)
1884{
1885 VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("gsub"), argc, argv);
1886 rb_lastline_set(str);
1887 return str;
1888}
1889
1890/*
1891 * call-seq:
1892 * chop -> $_
1893 *
1894 * Equivalent to <code>($_.dup).chop!</code>, except <code>nil</code>
1895 * is never returned. See String#chop!.
1896 * Available only when -p/-n command line option specified.
1897 *
1898 */
1899
1900static VALUE
1901rb_f_chop(VALUE _)
1902{
1903 VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("chop"), 0, 0);
1904 rb_lastline_set(str);
1905 return str;
1906}
1907
1908
1909/*
1910 * call-seq:
1911 * chomp -> $_
1912 * chomp(string) -> $_
1913 *
1914 * Equivalent to <code>$_ = $_.chomp(<em>string</em>)</code>. See
1915 * String#chomp.
1916 * Available only when -p/-n command line option specified.
1917 *
1918 */
1919
1920static VALUE
1921rb_f_chomp(int argc, VALUE *argv, VALUE _)
1922{
1923 VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("chomp"), argc, argv);
1924 rb_lastline_set(str);
1925 return str;
1926}
1927
1928static void
1929setup_pager_env(void)
1930{
1931 if (!getenv("LESS")) {
1932 // Output "raw" control characters, and move per sections.
1933 ruby_setenv("LESS", "-R +/^[A-Z].*");
1934 }
1935}
1936
1937#ifdef _WIN32
1938static int
1939tty_enabled(void)
1940{
1941 HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
1942 DWORD m;
1943 if (!GetConsoleMode(h, &m)) return 0;
1944# ifndef ENABLE_VIRTUAL_TERMINAL_PROCESSING
1945# define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x4
1946# endif
1947 if (!(m & ENABLE_VIRTUAL_TERMINAL_PROCESSING)) return 0;
1948 return 1;
1949}
1950#elif !defined(HAVE_WORKING_FORK)
1951# define tty_enabled() 0
1952#endif
1953
1954static VALUE
1955copy_str(VALUE str, rb_encoding *enc, bool intern)
1956{
1957 if (!intern) {
1958 if (rb_enc_str_coderange_scan(str, enc) == ENC_CODERANGE_BROKEN)
1959 return 0;
1960 return rb_enc_associate(rb_str_dup(str), enc);
1961 }
1962 return rb_enc_interned_str(RSTRING_PTR(str), RSTRING_LEN(str), enc);
1963}
1964
1965#if USE_YJIT
1966// Check that an environment variable is set to a truthy value
1967static bool
1968env_var_truthy(const char *name)
1969{
1970 const char *value = getenv(name);
1971
1972 if (!value)
1973 return false;
1974 if (strcmp(value, "1") == 0)
1975 return true;
1976 if (strcmp(value, "true") == 0)
1977 return true;
1978 if (strcmp(value, "yes") == 0)
1979 return true;
1980
1981 return false;
1982}
1983#endif
1984
1985rb_pid_t rb_fork_ruby(int *status);
1986
1987static rb_ast_t *
1988process_script(ruby_cmdline_options_t *opt)
1989{
1990 rb_ast_t *ast;
1991 VALUE parser = rb_parser_new();
1992
1993 if (opt->dump & DUMP_BIT(yydebug)) {
1994 rb_parser_set_yydebug(parser, Qtrue);
1995 }
1996
1997 if (opt->dump & DUMP_BIT(error_tolerant)) {
1998 rb_parser_error_tolerant(parser);
1999 }
2000
2001 if (opt->e_script) {
2002 VALUE progname = rb_progname;
2003 rb_parser_set_context(parser, 0, TRUE);
2004
2005 ruby_opt_init(opt);
2006 ruby_set_script_name(progname);
2007 rb_parser_set_options(parser, opt->do_print, opt->do_loop,
2008 opt->do_line, opt->do_split);
2009 ast = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
2010 }
2011 else {
2012 VALUE f;
2013 int xflag = opt->xflag;
2014 f = open_load_file(opt->script_name, &xflag);
2015 opt->xflag = xflag != 0;
2016 rb_parser_set_context(parser, 0, f == rb_stdin);
2017 ast = load_file(parser, opt->script_name, f, 1, opt);
2018 }
2019 if (!ast->body.root) {
2020 rb_ast_dispose(ast);
2021 return NULL;
2022 }
2023 return ast;
2024}
2025
2026static void
2027prism_script(ruby_cmdline_options_t *opt, pm_string_t *input, pm_options_t *options)
2028{
2029 ruby_opt_init(opt);
2030
2031 if (strcmp(opt->script, "-") == 0) {
2032 rb_warn("Prism support for streaming code from stdin is not currently supported");
2033 pm_string_constant_init(input, "", 0);
2034 pm_options_filepath_set(options, "-e");
2035 }
2036 else if (opt->e_script) {
2037 pm_string_constant_init(input, RSTRING_PTR(opt->e_script), RSTRING_LEN(opt->e_script));
2038 pm_options_filepath_set(options, "-e");
2039 }
2040 else {
2041 pm_string_mapped_init(input, RSTRING_PTR(opt->script_name));
2042 pm_options_filepath_set(options, RSTRING_PTR(opt->script_name));
2043 }
2044}
2045
2046static VALUE
2047prism_dump_tree(pm_string_t *input, pm_options_t *options)
2048{
2049 pm_parser_t parser;
2050 pm_parser_init(&parser, pm_string_source(input), pm_string_length(input), options);
2051
2052 pm_node_t *node = pm_parse(&parser);
2053
2054 pm_buffer_t output_buffer = { 0 };
2055
2056 pm_prettyprint(&output_buffer, &parser, node);
2057
2058 VALUE tree = rb_str_new(output_buffer.value, output_buffer.length);
2059
2060 pm_buffer_free(&output_buffer);
2061 pm_node_destroy(&parser, node);
2062 pm_parser_free(&parser);
2063
2064 return tree;
2065}
2066
2067static VALUE
2068process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
2069{
2070 rb_ast_t *ast = NULL;
2071 pm_string_t pm_input = { 0 };
2072 pm_options_t pm_options = { 0 };
2073
2074#define dispose_result() \
2075 (ast ? rb_ast_dispose(ast) : (pm_string_free(&pm_input), pm_options_free(&pm_options)))
2076
2077 const rb_iseq_t *iseq;
2078 rb_encoding *enc, *lenc;
2079#if UTF8_PATH
2080 rb_encoding *ienc = 0;
2081 rb_encoding *const uenc = rb_utf8_encoding();
2082#endif
2083 const char *s;
2084 char fbuf[MAXPATHLEN];
2085 int i = (int)proc_options(argc, argv, opt, 0);
2086 unsigned int dump = opt->dump & dump_exit_bits;
2087 rb_vm_t *vm = GET_VM();
2088 const long loaded_before_enc = RARRAY_LEN(vm->loaded_features);
2089
2090 if (opt->dump & (DUMP_BIT(usage)|DUMP_BIT(help))) {
2091 int tty = isatty(1);
2092 const char *const progname =
2093 (argc > 0 && argv && argv[0] ? argv[0] :
2094 origarg.argc > 0 && origarg.argv && origarg.argv[0] ? origarg.argv[0] :
2095 ruby_engine);
2096 int columns = 0;
2097 if ((opt->dump & DUMP_BIT(help)) && tty) {
2098 const char *pager_env = getenv("RUBY_PAGER");
2099 if (!pager_env) pager_env = getenv("PAGER");
2100 if (pager_env && *pager_env && isatty(0)) {
2101 const char *columns_env = getenv("COLUMNS");
2102 if (columns_env) columns = atoi(columns_env);
2103 VALUE pager = rb_str_new_cstr(pager_env);
2104#ifdef HAVE_WORKING_FORK
2105 int fds[2];
2106 if (rb_pipe(fds) == 0) {
2107 rb_pid_t pid = rb_fork_ruby(NULL);
2108 if (pid > 0) {
2109 /* exec PAGER with reading from child */
2110 dup2(fds[0], 0);
2111 }
2112 else if (pid == 0) {
2113 /* send the help message to the parent PAGER */
2114 dup2(fds[1], 1);
2115 dup2(fds[1], 2);
2116 }
2117 close(fds[0]);
2118 close(fds[1]);
2119 if (pid > 0) {
2120 setup_pager_env();
2121 rb_f_exec(1, &pager);
2122 kill(SIGTERM, pid);
2123 rb_waitpid(pid, 0, 0);
2124 }
2125 }
2126#else
2127 setup_pager_env();
2128 VALUE port = rb_io_popen(pager, rb_str_new_lit("w"), Qnil, Qnil);
2129 if (!NIL_P(port)) {
2130 int oldout = dup(1);
2131 int olderr = dup(2);
2132 int fd = RFILE(port)->fptr->fd;
2133 tty = tty_enabled();
2134 dup2(fd, 1);
2135 dup2(fd, 2);
2136 usage(progname, 1, tty, columns);
2137 fflush(stdout);
2138 dup2(oldout, 1);
2139 dup2(olderr, 2);
2140 rb_io_close(port);
2141 return Qtrue;
2142 }
2143#endif
2144 }
2145 }
2146 usage(progname, (opt->dump & DUMP_BIT(help)), tty, columns);
2147 return Qtrue;
2148 }
2149
2150 argc -= i;
2151 argv += i;
2152
2153 if (FEATURE_SET_P(opt->features, rubyopt) && (s = getenv("RUBYOPT"))) {
2154 moreswitches(s, opt, 1);
2155 }
2156
2157 if (opt->src.enc.name)
2158 /* cannot set deprecated category, as enabling deprecation warnings based on flags
2159 * has not happened yet.
2160 */
2161 rb_warning("-K is specified; it is for 1.8 compatibility and may cause odd behavior");
2162
2163 if (!(FEATURE_SET_BITS(opt->features) & feature_jit_mask)) {
2164#if USE_YJIT
2165 if (!FEATURE_USED_P(opt->features, yjit) && env_var_truthy("RUBY_YJIT_ENABLE")) {
2166 FEATURE_SET(opt->features, FEATURE_BIT(yjit));
2167 }
2168#endif
2169 }
2170 if (MULTI_BITS_P(FEATURE_SET_BITS(opt->features) & feature_jit_mask)) {
2171 rb_warn("RJIT and YJIT cannot both be enabled at the same time. Exiting");
2172 return Qfalse;
2173 }
2174
2175#if USE_RJIT
2176 if (FEATURE_SET_P(opt->features, rjit)) {
2177 opt->rjit.on = true; // set opt->rjit.on for Init_ruby_description() and calling rb_rjit_init()
2178 }
2179#endif
2180#if USE_YJIT
2181 if (FEATURE_SET_P(opt->features, yjit)) {
2182 bool rb_yjit_option_disable(void);
2183 opt->yjit = !rb_yjit_option_disable(); // set opt->yjit for Init_ruby_description() and calling rb_yjit_init()
2184 }
2185#endif
2186
2187 ruby_mn_threads_params();
2188 Init_ruby_description(opt);
2189
2190 if (opt->dump & (DUMP_BIT(version) | DUMP_BIT(version_v))) {
2191 ruby_show_version();
2192 if (opt->dump & DUMP_BIT(version)) return Qtrue;
2193 }
2194 if (opt->dump & DUMP_BIT(copyright)) {
2195 ruby_show_copyright();
2196 return Qtrue;
2197 }
2198
2199 if (!opt->e_script) {
2200 if (argc <= 0) { /* no more args */
2201 if (opt->verbose)
2202 return Qtrue;
2203 opt->script = "-";
2204 }
2205 else {
2206 opt->script = argv[0];
2207 if (!opt->script || opt->script[0] == '\0') {
2208 opt->script = "-";
2209 }
2210 else if (opt->do_search) {
2211 const char *path = getenv("RUBYPATH");
2212
2213 opt->script = 0;
2214 if (path) {
2215 opt->script = dln_find_file_r(argv[0], path, fbuf, sizeof(fbuf));
2216 }
2217 if (!opt->script) {
2218 opt->script = dln_find_file_r(argv[0], getenv(PATH_ENV), fbuf, sizeof(fbuf));
2219 }
2220 if (!opt->script)
2221 opt->script = argv[0];
2222 }
2223 argc--;
2224 argv++;
2225 }
2226 if (opt->script[0] == '-' && !opt->script[1]) {
2227 forbid_setid("program input from stdin");
2228 }
2229 }
2230
2231 opt->script_name = rb_str_new_cstr(opt->script);
2232 opt->script = RSTRING_PTR(opt->script_name);
2233
2234#ifdef _WIN32
2235 translit_char_bin(RSTRING_PTR(opt->script_name), '\\', '/');
2236#elif defined DOSISH
2237 translit_char(RSTRING_PTR(opt->script_name), '\\', '/');
2238#endif
2239
2240 ruby_gc_set_params();
2241 ruby_init_loadpath();
2242
2243 Init_enc();
2244 lenc = rb_locale_encoding();
2245 rb_enc_associate(rb_progname, lenc);
2246 rb_obj_freeze(rb_progname);
2247 if (opt->ext.enc.name != 0) {
2248 opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
2249 }
2250 if (opt->intern.enc.name != 0) {
2251 opt->intern.enc.index = opt_enc_index(opt->intern.enc.name);
2252 }
2253 if (opt->src.enc.name != 0) {
2254 opt->src.enc.index = opt_enc_index(opt->src.enc.name);
2255 src_encoding_index = opt->src.enc.index;
2256 }
2257 if (opt->ext.enc.index >= 0) {
2258 enc = rb_enc_from_index(opt->ext.enc.index);
2259 }
2260 else {
2261 enc = IF_UTF8_PATH(uenc, lenc);
2262 }
2263 rb_enc_set_default_external(rb_enc_from_encoding(enc));
2264 if (opt->intern.enc.index >= 0) {
2265 enc = rb_enc_from_index(opt->intern.enc.index);
2266 rb_enc_set_default_internal(rb_enc_from_encoding(enc));
2267 opt->intern.enc.index = -1;
2268#if UTF8_PATH
2269 ienc = enc;
2270#endif
2271 }
2272 rb_enc_associate(opt->script_name, IF_UTF8_PATH(uenc, lenc));
2273#if UTF8_PATH
2274 if (uenc != lenc) {
2275 opt->script_name = str_conv_enc(opt->script_name, uenc, lenc);
2276 opt->script = RSTRING_PTR(opt->script_name);
2277 }
2278#endif
2279 rb_obj_freeze(opt->script_name);
2280 if (IF_UTF8_PATH(uenc != lenc, 1)) {
2281 long i;
2282 VALUE load_path = vm->load_path;
2283 const ID id_initial_load_path_mark = INITIAL_LOAD_PATH_MARK;
2284 int modifiable = FALSE;
2285
2286 rb_get_expanded_load_path();
2287 for (i = 0; i < RARRAY_LEN(load_path); ++i) {
2288 VALUE path = RARRAY_AREF(load_path, i);
2289 int mark = rb_attr_get(path, id_initial_load_path_mark) == path;
2290#if UTF8_PATH
2291 VALUE newpath = rb_str_conv_enc(path, uenc, lenc);
2292 if (newpath == path) continue;
2293 path = newpath;
2294#else
2295 if (!(path = copy_str(path, lenc, !mark))) continue;
2296#endif
2297 if (mark) rb_ivar_set(path, id_initial_load_path_mark, path);
2298 if (!modifiable) {
2299 rb_ary_modify(load_path);
2300 modifiable = TRUE;
2301 }
2302 RARRAY_ASET(load_path, i, path);
2303 }
2304 if (modifiable) {
2305 rb_ary_replace(vm->load_path_snapshot, load_path);
2306 }
2307 }
2308 {
2309 VALUE loaded_features = vm->loaded_features;
2310 bool modified = false;
2311 for (long i = loaded_before_enc; i < RARRAY_LEN(loaded_features); ++i) {
2312 VALUE path = RARRAY_AREF(loaded_features, i);
2313 if (!(path = copy_str(path, IF_UTF8_PATH(uenc, lenc), true))) continue;
2314 if (!modified) {
2315 rb_ary_modify(loaded_features);
2316 modified = true;
2317 }
2318 RARRAY_ASET(loaded_features, i, path);
2319 }
2320 if (modified) {
2321 rb_ary_replace(vm->loaded_features_snapshot, loaded_features);
2322 }
2323 }
2324
2325 if (opt->features.mask & COMPILATION_FEATURES) {
2326 VALUE option = rb_hash_new();
2327#define SET_COMPILE_OPTION(h, o, name) \
2328 rb_hash_aset((h), ID2SYM(rb_intern_const(#name)), \
2329 RBOOL(FEATURE_SET_P(o->features, name)))
2330 SET_COMPILE_OPTION(option, opt, frozen_string_literal);
2331 SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
2332 rb_funcallv(rb_cISeq, rb_intern_const("compile_option="), 1, &option);
2333#undef SET_COMPILE_OPTION
2334 }
2335 ruby_set_argv(argc, argv);
2336 opt->sflag = process_sflag(opt->sflag);
2337
2338 if (opt->e_script) {
2339 rb_encoding *eenc;
2340 if (opt->src.enc.index >= 0) {
2341 eenc = rb_enc_from_index(opt->src.enc.index);
2342 }
2343 else {
2344 eenc = lenc;
2345#if UTF8_PATH
2346 if (ienc) eenc = ienc;
2347#endif
2348 }
2349#if UTF8_PATH
2350 if (eenc != uenc) {
2351 opt->e_script = str_conv_enc(opt->e_script, uenc, eenc);
2352 }
2353#endif
2354 rb_enc_associate(opt->e_script, eenc);
2355 }
2356
2357 if (!(*rb_ruby_prism_ptr())) {
2358 if (!(ast = process_script(opt))) return Qfalse;
2359 }
2360 else {
2361 prism_script(opt, &pm_input, &pm_options);
2362 }
2363 ruby_set_script_name(opt->script_name);
2364 if ((dump & DUMP_BIT(yydebug)) && !(dump &= ~DUMP_BIT(yydebug))) {
2365 dispose_result();
2366 return Qtrue;
2367 }
2368
2369 if (opt->ext.enc.index >= 0) {
2370 enc = rb_enc_from_index(opt->ext.enc.index);
2371 }
2372 else {
2373 enc = IF_UTF8_PATH(uenc, lenc);
2374 }
2375 rb_enc_set_default_external(rb_enc_from_encoding(enc));
2376 if (opt->intern.enc.index >= 0) {
2377 /* Set in the shebang line */
2378 enc = rb_enc_from_index(opt->intern.enc.index);
2379 rb_enc_set_default_internal(rb_enc_from_encoding(enc));
2380 }
2381 else if (!rb_default_internal_encoding())
2382 /* Freeze default_internal */
2383 rb_enc_set_default_internal(Qnil);
2384 rb_stdio_set_default_encoding();
2385
2386 opt->sflag = process_sflag(opt->sflag);
2387 opt->xflag = 0;
2388
2389 if (dump & DUMP_BIT(syntax)) {
2390 printf("Syntax OK\n");
2391 dump &= ~DUMP_BIT(syntax);
2392 if (!dump) return Qtrue;
2393 }
2394
2395 if (opt->do_loop) {
2396 rb_define_global_function("sub", rb_f_sub, -1);
2397 rb_define_global_function("gsub", rb_f_gsub, -1);
2398 rb_define_global_function("chop", rb_f_chop, 0);
2399 rb_define_global_function("chomp", rb_f_chomp, -1);
2400 }
2401
2402 if (dump & (DUMP_BIT(parsetree)|DUMP_BIT(parsetree_with_comment))) {
2403 VALUE tree;
2404 if (ast) {
2405 int comment = dump & DUMP_BIT(parsetree_with_comment);
2406 tree = rb_parser_dump_tree(ast->body.root, comment);
2407 }
2408 else {
2409 tree = prism_dump_tree(&pm_input, &pm_options);
2410 }
2411 rb_io_write(rb_stdout, tree);
2412 rb_io_flush(rb_stdout);
2413 dump &= ~DUMP_BIT(parsetree)&~DUMP_BIT(parsetree_with_comment);
2414 if (!dump) {
2415 dispose_result();
2416 return Qtrue;
2417 }
2418 }
2419
2420 {
2421 VALUE path = Qnil;
2422 if (!opt->e_script && strcmp(opt->script, "-")) {
2423 path = rb_realpath_internal(Qnil, opt->script_name, 1);
2424#if UTF8_PATH
2425 if (uenc != lenc) {
2426 path = str_conv_enc(path, uenc, lenc);
2427 }
2428#endif
2429 if (!ENCODING_GET(path)) { /* ASCII-8BIT */
2430 rb_enc_copy(path, opt->script_name);
2431 }
2432 }
2433
2434 bool optimize = !(dump & DUMP_BIT(insns_without_opt));
2435
2436 if (!ast) {
2437 iseq = rb_iseq_new_main_prism(&pm_input, &pm_options, path);
2438 }
2439 else {
2440 rb_binding_t *toplevel_binding;
2441 GetBindingPtr(rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING")),
2442 toplevel_binding);
2443 const struct rb_block *base_block = toplevel_context(toplevel_binding);
2444 iseq = rb_iseq_new_main(&ast->body, opt->script_name, path, vm_block_iseq(base_block), optimize);
2445 rb_ast_dispose(ast);
2446 }
2447 }
2448
2449 if (dump & (DUMP_BIT(insns) | DUMP_BIT(insns_without_opt))) {
2450 rb_io_write(rb_stdout, rb_iseq_disasm((const rb_iseq_t *)iseq));
2451 rb_io_flush(rb_stdout);
2452 dump &= ~DUMP_BIT(insns);
2453 if (!dump) return Qtrue;
2454 }
2455 if (opt->dump & dump_exit_bits) return Qtrue;
2456
2457 if (OPT_BACKTRACE_LENGTH_LIMIT_VALID_P(opt)) {
2458 rb_backtrace_length_limit = opt->backtrace_length_limit;
2459 }
2460
2461 rb_define_readonly_boolean("$-p", opt->do_print);
2462 rb_define_readonly_boolean("$-l", opt->do_line);
2463 rb_define_readonly_boolean("$-a", opt->do_split);
2464
2465 rb_gvar_ractor_local("$-p");
2466 rb_gvar_ractor_local("$-l");
2467 rb_gvar_ractor_local("$-a");
2468
2469 if ((rb_e_script = opt->e_script) != 0) {
2470 rb_str_freeze(rb_e_script);
2471 rb_gc_register_mark_object(opt->e_script);
2472 }
2473
2474 {
2475 rb_execution_context_t *ec = GET_EC();
2476
2477 if (opt->e_script) {
2478 /* -e */
2479 rb_exec_event_hook_script_compiled(ec, iseq, opt->e_script);
2480 }
2481 else {
2482 /* file */
2483 rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
2484 }
2485 }
2486 return (VALUE)iseq;
2487}
2488
2489#ifndef DOSISH
2490static void
2491warn_cr_in_shebang(const char *str, long len)
2492{
2493 if (str[len-1] == '\n' && str[len-2] == '\r') {
2494 rb_warn("shebang line ending with \\r may cause problems");
2495 }
2496}
2497#else
2498#define warn_cr_in_shebang(str, len) (void)0
2499#endif
2500
2501void rb_reset_argf_lineno(long n);
2502
2503 struct load_file_arg {
2504 VALUE parser;
2505 VALUE fname;
2506 int script;
2507 ruby_cmdline_options_t *opt;
2508 VALUE f;
2509};
2510
2511 VALUE rb_script_lines_for(VALUE path, bool add);
2512
2513static VALUE
2514load_file_internal(VALUE argp_v)
2515{
2516 struct load_file_arg *argp = (struct load_file_arg *)argp_v;
2517 VALUE parser = argp->parser;
2518 VALUE orig_fname = argp->fname;
2519 int script = argp->script;
2520 ruby_cmdline_options_t *opt = argp->opt;
2521 VALUE f = argp->f;
2522 int line_start = 1;
2523 rb_ast_t *ast = 0;
2524 rb_encoding *enc;
2525 ID set_encoding;
2526
2527 CONST_ID(set_encoding, "set_encoding");
2528 if (script) {
2529 VALUE c = 1; /* something not nil */
2530 VALUE line;
2531 char *p, *str;
2532 long len;
2533 int no_src_enc = !opt->src.enc.name;
2534 int no_ext_enc = !opt->ext.enc.name;
2535 int no_int_enc = !opt->intern.enc.name;
2536
2537 enc = rb_ascii8bit_encoding();
2538 rb_funcall(f, set_encoding, 1, rb_enc_from_encoding(enc));
2539
2540 if (opt->xflag) {
2541 line_start--;
2542 search_shebang:
2543 while (!NIL_P(line = rb_io_gets(f))) {
2544 line_start++;
2545 RSTRING_GETMEM(line, str, len);
2546 if (len > 2 && str[0] == '#' && str[1] == '!') {
2547 if (line_start == 1) warn_cr_in_shebang(str, len);
2548 if ((p = strstr(str+2, ruby_engine)) != 0) {
2549 goto start_read;
2550 }
2551 }
2552 }
2553 rb_loaderror("no Ruby script found in input");
2554 }
2555
2556 c = rb_io_getbyte(f);
2557 if (c == INT2FIX('#')) {
2558 c = rb_io_getbyte(f);
2559 if (c == INT2FIX('!') && !NIL_P(line = rb_io_gets(f))) {
2560 RSTRING_GETMEM(line, str, len);
2561 warn_cr_in_shebang(str, len);
2562 if ((p = strstr(str, ruby_engine)) == 0) {
2563 /* not ruby script, assume -x flag */
2564 goto search_shebang;
2565 }
2566
2567 start_read:
2568 str += len - 1;
2569 if (*str == '\n') *str-- = '\0';
2570 if (*str == '\r') *str-- = '\0';
2571 /* ruby_engine should not contain a space */
2572 if ((p = strstr(p, " -")) != 0) {
2573 opt->warning = 0;
2574 moreswitches(p + 1, opt, 0);
2575 }
2576
2577 /* push back shebang for pragma may exist in next line */
2578 rb_io_ungetbyte(f, rb_str_new2("!\n"));
2579 }
2580 else if (!NIL_P(c)) {
2581 rb_io_ungetbyte(f, c);
2582 }
2583 rb_io_ungetbyte(f, INT2FIX('#'));
2584 if (no_src_enc && opt->src.enc.name) {
2585 opt->src.enc.index = opt_enc_index(opt->src.enc.name);
2586 src_encoding_index = opt->src.enc.index;
2587 }
2588 if (no_ext_enc && opt->ext.enc.name) {
2589 opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
2590 }
2591 if (no_int_enc && opt->intern.enc.name) {
2592 opt->intern.enc.index = opt_enc_index(opt->intern.enc.name);
2593 }
2594 }
2595 else if (!NIL_P(c)) {
2596 rb_io_ungetbyte(f, c);
2597 }
2598 if (NIL_P(c)) {
2599 argp->f = f = Qnil;
2600 }
2601 rb_reset_argf_lineno(0);
2602 ruby_opt_init(opt);
2603 }
2604 if (opt->src.enc.index >= 0) {
2605 enc = rb_enc_from_index(opt->src.enc.index);
2606 }
2607 else if (f == rb_stdin) {
2608 enc = rb_locale_encoding();
2609 }
2610 else {
2611 enc = rb_utf8_encoding();
2612 }
2613 rb_parser_set_options(parser, opt->do_print, opt->do_loop,
2614 opt->do_line, opt->do_split);
2615
2616 VALUE lines = rb_script_lines_for(orig_fname, true);
2617 if (!NIL_P(lines)) {
2618 rb_parser_set_script_lines(parser, lines);
2619 }
2620
2621 if (NIL_P(f)) {
2622 f = rb_str_new(0, 0);
2623 rb_enc_associate(f, enc);
2624 return (VALUE)rb_parser_compile_string_path(parser, orig_fname, f, line_start);
2625 }
2626 rb_funcall(f, set_encoding, 2, rb_enc_from_encoding(enc), rb_str_new_cstr("-"));
2627 ast = rb_parser_compile_file_path(parser, orig_fname, f, line_start);
2628 rb_funcall(f, set_encoding, 1, rb_parser_encoding(parser));
2629 if (script && rb_parser_end_seen_p(parser)) {
2630 /*
2631 * DATA is a File that contains the data section of the executed file.
2632 * To create a data section use <tt>__END__</tt>:
2633 *
2634 * $ cat t.rb
2635 * puts DATA.gets
2636 * __END__
2637 * hello world!
2638 *
2639 * $ ruby t.rb
2640 * hello world!
2641 */
2642 rb_define_global_const("DATA", f);
2643 argp->f = Qnil;
2644 }
2645 return (VALUE)ast;
2646}
2647
2648/* disabling O_NONBLOCK, and returns 0 on success, otherwise errno */
2649static inline int
2650disable_nonblock(int fd)
2651{
2652#if defined(HAVE_FCNTL) && defined(F_SETFL)
2653 if (fcntl(fd, F_SETFL, 0) < 0) {
2654 const int e = errno;
2655 ASSUME(e != 0);
2656# if defined ENOTSUP
2657 if (e == ENOTSUP) return 0;
2658# endif
2659# if defined B_UNSUPPORTED
2660 if (e == B_UNSUPPORTED) return 0;
2661# endif
2662 return e;
2663 }
2664#endif
2665 return 0;
2666}
2667
2668static VALUE
2669open_load_file(VALUE fname_v, int *xflag)
2670{
2671 const char *fname = (fname_v = rb_str_encode_ospath(fname_v),
2672 StringValueCStr(fname_v));
2673 long flen = RSTRING_LEN(fname_v);
2674 VALUE f;
2675 int e;
2676
2677 if (flen == 1 && fname[0] == '-') {
2678 f = rb_stdin;
2679 }
2680 else {
2681 int fd;
2682 /* open(2) may block if fname is point to FIFO and it's empty. Let's
2683 use O_NONBLOCK. */
2684 const int MODE_TO_LOAD = O_RDONLY | (
2685#if defined O_NONBLOCK && HAVE_FCNTL
2686 /* TODO: fix conflicting O_NONBLOCK in ruby/win32.h */
2687 !(O_NONBLOCK & O_ACCMODE) ? O_NONBLOCK :
2688#endif
2689#if defined O_NDELAY && HAVE_FCNTL
2690 !(O_NDELAY & O_ACCMODE) ? O_NDELAY :
2691#endif
2692 0);
2693 int mode = MODE_TO_LOAD;
2694#if defined DOSISH || defined __CYGWIN__
2695# define isdirsep(x) ((x) == '/' || (x) == '\\')
2696 {
2697 static const char exeext[] = ".exe";
2698 enum {extlen = sizeof(exeext)-1};
2699 if (flen > extlen && !isdirsep(fname[flen-extlen-1]) &&
2700 STRNCASECMP(fname+flen-extlen, exeext, extlen) == 0) {
2701 mode |= O_BINARY;
2702 *xflag = 1;
2703 }
2704 }
2705#endif
2706
2707 if ((fd = rb_cloexec_open(fname, mode, 0)) < 0) {
2708 e = errno;
2709 if (!rb_gc_for_fd(e)) {
2710 rb_load_fail(fname_v, strerror(e));
2711 }
2712 if ((fd = rb_cloexec_open(fname, mode, 0)) < 0) {
2713 rb_load_fail(fname_v, strerror(errno));
2714 }
2715 }
2716 rb_update_max_fd(fd);
2717
2718 if (MODE_TO_LOAD != O_RDONLY && (e = disable_nonblock(fd)) != 0) {
2719 (void)close(fd);
2720 rb_load_fail(fname_v, strerror(e));
2721 }
2722
2723 e = ruby_is_fd_loadable(fd);
2724 if (!e) {
2725 e = errno;
2726 (void)close(fd);
2727 rb_load_fail(fname_v, strerror(e));
2728 }
2729
2730 f = rb_io_fdopen(fd, mode, fname);
2731 if (e < 0) {
2732 /*
2733 We need to wait if FIFO is empty. It's FIFO's semantics.
2734 rb_thread_wait_fd() release GVL. So, it's safe.
2735 */
2736 rb_io_wait(f, RB_INT2NUM(RUBY_IO_READABLE), Qnil);
2737 }
2738 }
2739 return f;
2740}
2741
2742static VALUE
2743restore_load_file(VALUE arg)
2744{
2745 struct load_file_arg *argp = (struct load_file_arg *)arg;
2746 VALUE f = argp->f;
2747
2748 if (!NIL_P(f) && f != rb_stdin) {
2749 rb_io_close(f);
2750 }
2751 return Qnil;
2752}
2753
2754static rb_ast_t *
2755load_file(VALUE parser, VALUE fname, VALUE f, int script, ruby_cmdline_options_t *opt)
2756{
2757 struct load_file_arg arg;
2758 arg.parser = parser;
2759 arg.fname = fname;
2760 arg.script = script;
2761 arg.opt = opt;
2762 arg.f = f;
2763 return (rb_ast_t *)rb_ensure(load_file_internal, (VALUE)&arg,
2764 restore_load_file, (VALUE)&arg);
2765}
2766
2767void *
2768rb_load_file(const char *fname)
2769{
2770 VALUE fname_v = rb_str_new_cstr(fname);
2771 return rb_load_file_str(fname_v);
2772}
2773
2774void *
2775rb_load_file_str(VALUE fname_v)
2776{
2777 return rb_parser_load_file(rb_parser_new(), fname_v);
2778}
2779
2780void *
2781rb_parser_load_file(VALUE parser, VALUE fname_v)
2782{
2783 ruby_cmdline_options_t opt;
2784 int xflag = 0;
2785 VALUE f = open_load_file(fname_v, &xflag);
2786 cmdline_options_init(&opt)->xflag = xflag != 0;
2787 return load_file(parser, fname_v, f, 0, &opt);
2788}
2789
2790/*
2791 * call-seq:
2792 * Process.argv0 -> frozen_string
2793 *
2794 * Returns the name of the script being executed. The value is not
2795 * affected by assigning a new value to $0.
2796 *
2797 * This method first appeared in Ruby 2.1 to serve as a global
2798 * variable free means to get the script name.
2799 */
2800
2801static VALUE
2802proc_argv0(VALUE process)
2803{
2804 return rb_orig_progname;
2805}
2806
2807static VALUE ruby_setproctitle(VALUE title);
2808
2809/*
2810 * call-seq:
2811 * Process.setproctitle(string) -> string
2812 *
2813 * Sets the process title that appears on the ps(1) command. Not
2814 * necessarily effective on all platforms. No exception will be
2815 * raised regardless of the result, nor will NotImplementedError be
2816 * raised even if the platform does not support the feature.
2817 *
2818 * Calling this method does not affect the value of $0.
2819 *
2820 * Process.setproctitle('myapp: worker #%d' % worker_id)
2821 *
2822 * This method first appeared in Ruby 2.1 to serve as a global
2823 * variable free means to change the process title.
2824 */
2825
2826static VALUE
2827proc_setproctitle(VALUE process, VALUE title)
2828{
2829 return ruby_setproctitle(title);
2830}
2831
2832static VALUE
2833ruby_setproctitle(VALUE title)
2834{
2835 const char *ptr = StringValueCStr(title);
2836 setproctitle("%.*s", RSTRING_LENINT(title), ptr);
2837 return title;
2838}
2839
2840static void
2841set_arg0(VALUE val, ID id, VALUE *_)
2842{
2843 if (origarg.argv == 0)
2844 rb_raise(rb_eRuntimeError, "$0 not initialized");
2845
2846 rb_progname = rb_str_new_frozen(ruby_setproctitle(val));
2847}
2848
2849static inline VALUE
2850external_str_new_cstr(const char *p)
2851{
2852#if UTF8_PATH
2853 VALUE str = rb_utf8_str_new_cstr(p);
2854 str = str_conv_enc(str, NULL, rb_default_external_encoding());
2855 return str;
2856#else
2857 return rb_external_str_new_cstr(p);
2858#endif
2859}
2860
2861static void
2862set_progname(VALUE name)
2863{
2864 rb_orig_progname = rb_progname = name;
2865 rb_vm_set_progname(rb_progname);
2866}
2867
2868void
2869ruby_script(const char *name)
2870{
2871 if (name) {
2872 set_progname(rb_str_freeze(external_str_new_cstr(name)));
2873 }
2874}
2875
2880void
2881ruby_set_script_name(VALUE name)
2882{
2883 set_progname(rb_str_new_frozen(name));
2884}
2885
2886static void
2887init_ids(ruby_cmdline_options_t *opt)
2888{
2889 rb_uid_t uid = getuid();
2890 rb_uid_t euid = geteuid();
2891 rb_gid_t gid = getgid();
2892 rb_gid_t egid = getegid();
2893
2894 if (uid != euid) opt->setids |= 1;
2895 if (egid != gid) opt->setids |= 2;
2896}
2897
2898#undef forbid_setid
2899static void
2900forbid_setid(const char *s, const ruby_cmdline_options_t *opt)
2901{
2902 if (opt->setids & 1)
2903 rb_raise(rb_eSecurityError, "no %s allowed while running setuid", s);
2904 if (opt->setids & 2)
2905 rb_raise(rb_eSecurityError, "no %s allowed while running setgid", s);
2906}
2907
2908static VALUE
2909verbose_getter(ID id, VALUE *ptr)
2910{
2911 return *rb_ruby_verbose_ptr();
2912}
2913
2914static void
2915verbose_setter(VALUE val, ID id, VALUE *variable)
2916{
2917 *rb_ruby_verbose_ptr() = RTEST(val) ? Qtrue : val;
2918}
2919
2920static VALUE
2921opt_W_getter(ID id, VALUE *dmy)
2922{
2923 VALUE v = *rb_ruby_verbose_ptr();
2924
2925 switch (v) {
2926 case Qnil:
2927 return INT2FIX(0);
2928 case Qfalse:
2929 return INT2FIX(1);
2930 case Qtrue:
2931 return INT2FIX(2);
2932 default:
2933 return Qnil;
2934 }
2935}
2936
2937static VALUE
2938debug_getter(ID id, VALUE *dmy)
2939{
2940 return *rb_ruby_debug_ptr();
2941}
2942
2943static void
2944debug_setter(VALUE val, ID id, VALUE *dmy)
2945{
2946 *rb_ruby_debug_ptr() = val;
2947}
2948
2949void
2950ruby_prog_init(void)
2951{
2952 rb_define_virtual_variable("$VERBOSE", verbose_getter, verbose_setter);
2953 rb_define_virtual_variable("$-v", verbose_getter, verbose_setter);
2954 rb_define_virtual_variable("$-w", verbose_getter, verbose_setter);
2955 rb_define_virtual_variable("$-W", opt_W_getter, rb_gvar_readonly_setter);
2956 rb_define_virtual_variable("$DEBUG", debug_getter, debug_setter);
2957 rb_define_virtual_variable("$-d", debug_getter, debug_setter);
2958
2959 rb_gvar_ractor_local("$VERBOSE");
2960 rb_gvar_ractor_local("$-v");
2961 rb_gvar_ractor_local("$-w");
2962 rb_gvar_ractor_local("$-W");
2963 rb_gvar_ractor_local("$DEBUG");
2964 rb_gvar_ractor_local("$-d");
2965
2966 rb_define_hooked_variable("$0", &rb_progname, 0, set_arg0);
2967 rb_define_hooked_variable("$PROGRAM_NAME", &rb_progname, 0, set_arg0);
2968
2969 rb_define_module_function(rb_mProcess, "argv0", proc_argv0, 0);
2970 rb_define_module_function(rb_mProcess, "setproctitle", proc_setproctitle, 1);
2971
2972 /*
2973 * ARGV contains the command line arguments used to run ruby.
2974 *
2975 * A library like OptionParser can be used to process command-line
2976 * arguments.
2977 */
2978 rb_define_global_const("ARGV", rb_argv);
2979}
2980
2981void
2982ruby_set_argv(int argc, char **argv)
2983{
2984 int i;
2985 VALUE av = rb_argv;
2986
2987 rb_ary_clear(av);
2988 for (i = 0; i < argc; i++) {
2989 VALUE arg = external_str_new_cstr(argv[i]);
2990
2991 OBJ_FREEZE(arg);
2992 rb_ary_push(av, arg);
2993 }
2994}
2995
2996void *
2997ruby_process_options(int argc, char **argv)
2998{
2999 ruby_cmdline_options_t opt;
3000 VALUE iseq;
3001 const char *script_name = (argc > 0 && argv[0]) ? argv[0] : ruby_engine;
3002
3003 (*rb_ruby_prism_ptr()) = false;
3004
3005 if (!origarg.argv || origarg.argc <= 0) {
3006 origarg.argc = argc;
3007 origarg.argv = argv;
3008 }
3009 set_progname(external_str_new_cstr(script_name)); /* for the time being */
3010 rb_argv0 = rb_str_new4(rb_progname);
3011 rb_gc_register_mark_object(rb_argv0);
3012
3013#ifndef HAVE_SETPROCTITLE
3014 ruby_init_setproctitle(argc, argv);
3015#endif
3016
3017 iseq = process_options(argc, argv, cmdline_options_init(&opt));
3018
3019 if (opt.crash_report && *opt.crash_report) {
3020 void ruby_set_crash_report(const char *template);
3021 ruby_set_crash_report(opt.crash_report);
3022 }
3023 return (void*)(struct RData*)iseq;
3024}
3025
3026static void
3027fill_standard_fds(void)
3028{
3029 int f0, f1, f2, fds[2];
3030 struct stat buf;
3031 f0 = fstat(0, &buf) == -1 && errno == EBADF;
3032 f1 = fstat(1, &buf) == -1 && errno == EBADF;
3033 f2 = fstat(2, &buf) == -1 && errno == EBADF;
3034 if (f0) {
3035 if (pipe(fds) == 0) {
3036 close(fds[1]);
3037 if (fds[0] != 0) {
3038 dup2(fds[0], 0);
3039 close(fds[0]);
3040 }
3041 }
3042 }
3043 if (f1 || f2) {
3044 if (pipe(fds) == 0) {
3045 close(fds[0]);
3046 if (f1 && fds[1] != 1)
3047 dup2(fds[1], 1);
3048 if (f2 && fds[1] != 2)
3049 dup2(fds[1], 2);
3050 if (fds[1] != 1 && fds[1] != 2)
3051 close(fds[1]);
3052 }
3053 }
3054}
3055
3056void
3057ruby_sysinit(int *argc, char ***argv)
3058{
3059#if defined(_WIN32)
3060 rb_w32_sysinit(argc, argv);
3061#endif
3062 if (*argc >= 0 && *argv) {
3063 origarg.argc = *argc;
3064 origarg.argv = *argv;
3065 }
3066 fill_standard_fds();
3067}
RUBY_ASSERT
#define RUBY_ASSERT(expr)
Asserts that the given expression is truthy if and only if RUBY_DEBUG is truthy.
Definition assert.h:177
rb_define_module_function
#define rb_define_module_function(klass, mid, func, arity)
Defines klass#mid and makes it a module function.
Definition cxxanyargs.hpp:689
rb_define_global_function
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
Definition cxxanyargs.hpp:695
RUBY_EXTERN
#define RUBY_EXTERN
Declaration of externally visible global variables.
Definition dllexport.h:45
PATH_ENV
#define PATH_ENV
Definition dosish.h:63
PATH_SEP_CHAR
#define PATH_SEP_CHAR
Identical to PATH_SEP, except it is of type char.
Definition dosish.h:49
rb_define_module
VALUE rb_define_module(const char *name)
Defines a top-level module.
Definition class.c:1085
rb_str_new2
#define rb_str_new2
Old name of rb_str_new_cstr.
Definition string.h:1675
ISSPACE
#define ISSPACE
Old name of rb_isspace.
Definition ctype.h:88
T_STRING
#define T_STRING
Old name of RUBY_T_STRING.
Definition value_type.h:78
Qundef
#define Qundef
Old name of RUBY_Qundef.
Definition special_consts.h:62
INT2FIX
#define INT2FIX
Old name of RB_INT2FIX.
Definition long.h:48
rb_str_cat2
#define rb_str_cat2
Old name of rb_str_cat_cstr.
Definition string.h:1683
UNREACHABLE
#define UNREACHABLE
Old name of RBIMPL_UNREACHABLE.
Definition assume.h:28
OBJ_FREEZE_RAW
#define OBJ_FREEZE_RAW
Old name of RB_OBJ_FREEZE_RAW.
Definition fl_type.h:136
OBJ_FREEZE
#define OBJ_FREEZE
Old name of RB_OBJ_FREEZE.
Definition fl_type.h:135
ECONV_UNDEF_REPLACE
#define ECONV_UNDEF_REPLACE
Old name of RUBY_ECONV_UNDEF_REPLACE.
Definition transcode.h:526
UNREACHABLE_RETURN
#define UNREACHABLE_RETURN
Old name of RBIMPL_UNREACHABLE_RETURN.
Definition assume.h:29
ENCODING_GET
#define ENCODING_GET(obj)
Old name of RB_ENCODING_GET.
Definition encoding.h:108
ECONV_INVALID_REPLACE
#define ECONV_INVALID_REPLACE
Old name of RUBY_ECONV_INVALID_REPLACE.
Definition transcode.h:524
ASSUME
#define ASSUME
Old name of RBIMPL_ASSUME.
Definition assume.h:27
ALLOC_N
#define ALLOC_N
Old name of RB_ALLOC_N.
Definition memory.h:393
STRNCASECMP
#define STRNCASECMP
Old name of st_locale_insensitive_strncasecmp.
Definition ctype.h:103
TOLOWER
#define TOLOWER
Old name of rb_tolower.
Definition ctype.h:101
Qtrue
#define Qtrue
Old name of RUBY_Qtrue.
Definition special_consts.h:61
Qnil
#define Qnil
Old name of RUBY_Qnil.
Definition special_consts.h:60
Qfalse
#define Qfalse
Old name of RUBY_Qfalse.
Definition special_consts.h:59
ENC_CODERANGE_BROKEN
#define ENC_CODERANGE_BROKEN
Old name of RUBY_ENC_CODERANGE_BROKEN.
Definition coderange.h:182
NIL_P
#define NIL_P
Old name of RB_NIL_P.
Definition special_consts.h:55
scan_oct
#define scan_oct(s, l, e)
Old name of ruby_scan_oct.
Definition util.h:85
CONST_ID
#define CONST_ID
Old name of RUBY_CONST_ID.
Definition symbol.h:47
ISALNUM
#define ISALNUM
Old name of rb_isalnum.
Definition ctype.h:91
rb_str_new4
#define rb_str_new4
Old name of rb_str_new_frozen.
Definition string.h:1677
ruby_script
void ruby_script(const char *name)
Sets the current script name to this value.
Definition ruby.c:2869
ruby_set_argv
void ruby_set_argv(int argc, char **argv)
Sets argv that ruby understands.
Definition ruby.c:2982
ruby_set_script_name
void ruby_set_script_name(VALUE name)
Sets the current script name to this value.
Definition ruby.c:2881
ruby_init_loadpath
void ruby_init_loadpath(void)
Sets up $LOAD_PATH.
Definition ruby.c:679
ruby_process_options
void * ruby_process_options(int argc, char **argv)
Identical to ruby_options(), except it raises ruby-level exceptions on failure.
Definition ruby.c:2997
ruby_prog_init
void ruby_prog_init(void)
Defines built-in variables.
Definition ruby.c:2950
ruby_incpush
void ruby_incpush(const char *path)
Appends the given path to the end of the load path.
Definition ruby.c:522
ruby_debug
#define ruby_debug
This variable controls whether the interpreter is in debug mode.
Definition error.h:482
rb_category_warn
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:433
ruby_verbose
#define ruby_verbose
This variable controls whether the interpreter is in debug mode.
Definition error.h:471
rb_eTypeError
VALUE rb_eTypeError
TypeError exception.
Definition error.c:1344
rb_eNameError
VALUE rb_eNameError
NameError exception.
Definition error.c:1349
rb_eRuntimeError
VALUE rb_eRuntimeError
RuntimeError exception.
Definition error.c:1342
rb_warn
void rb_warn(const char *fmt,...)
Identical to rb_warning(), except it reports unless $VERBOSE is nil.
Definition error.c:423
rb_exc_new_str
VALUE rb_exc_new_str(VALUE etype, VALUE str)
Identical to rb_exc_new_cstr(), except it takes a Ruby's string instead of C's.
Definition error.c:1395
rb_loaderror
void rb_loaderror(const char *fmt,...)
Raises an instance of rb_eLoadError.
Definition error.c:3474
rb_eSecurityError
VALUE rb_eSecurityError
SecurityError exception.
Definition error.c:1353
rb_warning
void rb_warning(const char *fmt,...)
Issues a warning.
Definition error.c:454
RB_WARN_CATEGORY_DEPRECATED
@ RB_WARN_CATEGORY_DEPRECATED
Warning is for deprecated features.
Definition error.h:48
RB_WARN_CATEGORY_EXPERIMENTAL
@ RB_WARN_CATEGORY_EXPERIMENTAL
Warning is for experimental features.
Definition error.h:51
RB_WARN_CATEGORY_PERFORMANCE
@ RB_WARN_CATEGORY_PERFORMANCE
Warning is for performance issues (not enabled by -w).
Definition error.h:54
rb_mProcess
VALUE rb_mProcess
Process module.
Definition process.c:8747
rb_class_new_instance
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
Definition object.c:2099
rb_stdin
VALUE rb_stdin
STDIN constant.
Definition io.c:190
rb_stdout
VALUE rb_stdout
STDOUT constant.
Definition io.c:190
rb_cString
VALUE rb_cString
String class.
Definition string.c:78
ruby_show_copyright
void ruby_show_copyright(void)
Prints the copyright notice of the CRuby interpreter to stdout.
Definition version.c:211
ruby_sysinit
void ruby_sysinit(int *argc, char ***argv)
Initializes the process for libruby.
Definition ruby.c:3057
ruby_show_version
void ruby_show_version(void)
Prints the version information of the CRuby interpreter to stdout.
Definition version.c:197
encoding.h
Encoding relates APIs.
rb_str_conv_enc
VALUE rb_str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
Encoding conversion main routine.
Definition string.c:1149
rb_str_conv_enc_opts
VALUE rb_str_conv_enc_opts(VALUE str, rb_encoding *from, rb_encoding *to, int ecflags, VALUE ecopts)
Identical to rb_str_conv_enc(), except it additionally takes IO encoder options.
Definition string.c:1034
rb_enc_interned_str
VALUE rb_enc_interned_str(const char *ptr, long len, rb_encoding *enc)
Identical to rb_enc_str_new(), except it returns a "f"string.
Definition string.c:12088
error.h
Declares rb_raise().
rb_funcall_passing_block
VALUE rb_funcall_passing_block(VALUE recv, ID mid, int argc, const VALUE *argv)
Identical to rb_funcallv_public(), except you can pass the passed block.
Definition vm_eval.c:1184
rb_funcall
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
Definition vm_eval.c:1121
rb_io_gets
VALUE rb_io_gets(VALUE io)
Reads a "line" from the given IO.
Definition io.c:4233
rb_io_ungetbyte
VALUE rb_io_ungetbyte(VALUE io, VALUE b)
Identical to rb_io_ungetc(), except it doesn't take the encoding of the passed IO into account.
Definition io.c:5101
rb_io_getbyte
VALUE rb_io_getbyte(VALUE io)
Reads a byte from the given IO.
Definition io.c:5007
rb_io_fdopen
VALUE rb_io_fdopen(int fd, int flags, const char *path)
Creates an IO instance whose backend is the given file descriptor.
Definition io.c:9255
rb_update_max_fd
void rb_update_max_fd(int fd)
Informs the interpreter that the passed fd can be the max.
Definition io.c:226
rb_cloexec_open
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Opens a file that closes on exec.
Definition io.c:306
rb_fs
VALUE rb_fs
The field separator character for inputs, or the $;.
Definition string.c:538
rb_output_rs
VALUE rb_output_rs
The record separator character for outputs, or the $\.
Definition io.c:195
rb_pipe
int rb_pipe(int *pipes)
This is an rb_cloexec_pipe() + rb_update_max_fd() combo.
Definition io.c:7300
rb_io_close
VALUE rb_io_close(VALUE io)
Closes the IO.
Definition io.c:5688
rb_lastline_set
void rb_lastline_set(VALUE str)
Updates $_.
Definition vm.c:1811
rb_lastline_get
VALUE rb_lastline_get(void)
Queries the last line, or the $_.
Definition vm.c:1805
rb_waitpid
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Waits for a process, with releasing GVL.
Definition process.c:1269
rb_f_exec
VALUE rb_f_exec(int argc, const VALUE *argv)
Replaces the current process by running the given external command.
Definition process.c:3015
rb_reg_new
VALUE rb_reg_new(const char *src, long len, int opts)
Creates a new Regular expression.
Definition re.c:3435
rb_utf8_str_new_cstr
#define rb_utf8_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "UTF-8" encoding.
Definition string.h:1583
rb_str_new_lit
#define rb_str_new_lit(str)
Identical to rb_str_new_static(), except it cannot take string variables.
Definition string.h:1705
rb_str_tmp_new
VALUE rb_str_tmp_new(long len)
Allocates a "temporary" string.
Definition string.c:1532
rb_str_new
#define rb_str_new(str, len)
Allocates an instance of rb_cString.
Definition string.h:1498
rb_external_str_new_cstr
#define rb_external_str_new_cstr(str)
Identical to rb_str_new_cstr, except it generates a string of "defaultexternal" encoding.
Definition string.h:1604
rb_strlen_lit
#define rb_strlen_lit(str)
Length of a string literal.
Definition string.h:1692
rb_str_freeze
VALUE rb_str_freeze(VALUE str)
This is the implementation of String#freeze.
Definition string.c:2999
rb_str_cat_cstr
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1656
rb_utf8_str_new
#define rb_utf8_str_new(str, len)
Identical to rb_str_new, except it generates a string of "UTF-8" encoding.
Definition string.h:1549
rb_str_modify_expand
void rb_str_modify_expand(VALUE str, long capa)
Identical to rb_str_modify(), except it additionally expands the capacity of the receiver.
Definition string.c:2486
rb_str_new_cstr
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
Definition string.h:1514
rb_const_get
VALUE rb_const_get(VALUE space, ID name)
Identical to rb_const_defined(), except it returns the actual defined value.
Definition variable.c:3141
rb_ivar_set
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
Definition variable.c:1854
rb_const_set
void rb_const_set(VALUE space, ID name, VALUE val)
Names a constant.
Definition variable.c:3596
rb_const_remove
VALUE rb_const_remove(VALUE space, ID name)
Identical to rb_mod_remove_const(), except it takes the name as ID instead of VALUE.
Definition variable.c:3244
rb_intern_const
static ID rb_intern_const(const char *str)
This is a "tiny optimisation" over rb_intern().
Definition symbol.h:276
rb_define_global_const
void rb_define_global_const(const char *name, VALUE val)
Identical to rb_define_const(), except it defines that of "global", i.e.
Definition variable.c:3702
rb_gvar_readonly_setter
rb_gvar_setter_t rb_gvar_readonly_setter
This function just raises rb_eNameError.
Definition variable.h:135
rb_gv_set
VALUE rb_gv_set(const char *name, VALUE val)
Assigns to a global variable.
Definition variable.c:889
RUBY_IO_READABLE
@ RUBY_IO_READABLE
IO::READABLE
Definition io.h:82
rb_io_wait
VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout)
Blocks until the passed IO is ready for the passed events.
Definition io.c:1422
len
int len
Length of the buffer.
Definition io.h:8
thread.h
util.h
ruby_each_words
void ruby_each_words(const char *str, void(*func)(const char *word, int len, void *argv), void *argv)
Scans the passed string, with calling the callback function every time it encounters a "word".
Definition util.c:593
version.h
ruby_engine
const char ruby_engine[]
This is just "ruby" for us.
Definition version.c:78
ruby_patchlevel
const int ruby_patchlevel
This is a monotonic increasing integer that describes specific "patch" level.
Definition version.c:67
RB_INT2NUM
#define RB_INT2NUM
Just another name of rb_int2num_inline
Definition int.h:37
MEMZERO
#define MEMZERO(p, type, n)
Handy macro to erase a region of memory.
Definition memory.h:354
MEMMOVE
#define MEMMOVE(p1, p2, type, n)
Handy macro to call memmove.
Definition memory.h:378
ruby::backward::cxxanyargs::rb_define_hooked_variable
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
ruby::backward::cxxanyargs::type
VALUE type(ANYARGS)
ANYARGS-ed function type.
Definition cxxanyargs.hpp:56
ruby::backward::cxxanyargs::rb_define_virtual_variable
void rb_define_virtual_variable(const char *q, type *w, void_type *e)
Define a function-backended global variable.
Definition cxxanyargs.hpp:73
ruby::backward::cxxanyargs::rb_ensure
VALUE rb_ensure(type *q, VALUE w, type *e, VALUE r)
An equivalent of ensure clause.
Definition cxxanyargs.hpp:310
RARRAY_LEN
#define RARRAY_LEN
Just another name of rb_array_len
Definition rarray.h:51
RARRAY_ASET
static void RARRAY_ASET(VALUE ary, long i, VALUE v)
Assigns an object in an array.
Definition rarray.h:386
RARRAY_AREF
#define RARRAY_AREF(a, i)
Definition rarray.h:403
RARRAY_CONST_PTR
#define RARRAY_CONST_PTR
Just another name of rb_array_const_ptr
Definition rarray.h:52
RFILE
#define RFILE(obj)
Convenient casting macro.
Definition rfile.h:50
StringValuePtr
#define StringValuePtr(v)
Identical to StringValue, except it returns a char*.
Definition rstring.h:76
RSTRING_LENINT
static int RSTRING_LENINT(VALUE str)
Identical to RSTRING_LEN(), except it differs for the return type.
Definition rstring.h:468
RSTRING_GETMEM
#define RSTRING_GETMEM(str, ptrvar, lenvar)
Convenient macro to obtain the contents and length at once.
Definition rstring.h:488
StringValueCStr
#define StringValueCStr(v)
Identical to StringValuePtr, except it additionally checks for the contents for viability as a C stri...
Definition rstring.h:89
rb_argv0
VALUE rb_argv0
The value of $0 at process bootup.
Definition ruby.c:1822
rb_load_file_str
void * rb_load_file_str(VALUE file)
Identical to rb_load_file(), except it takes the argument as a Ruby's string instead of C's.
Definition ruby.c:2775
rb_load_file
void * rb_load_file(const char *file)
Loads the given file.
Definition ruby.c:2768
rb_argv
#define rb_argv
Just another name of rb_get_argv
Definition ruby.h:31
rb_obj_classname
const char * rb_obj_classname(VALUE obj)
Queries the name of the class of the passed object.
Definition variable.c:417
errno
#define errno
Ractor-aware version of errno.
Definition ruby.h:388
RTEST
#define RTEST
This is an old name of RB_TEST.
Definition special_consts.h:51
_
#define _(args)
This was a transition path from K&R to ANSI.
Definition stdarg.h:35
OnigEncodingTypeST
Definition onigmo.h:160
RData
Definition rdata.h:124
load_file_arg
Definition ruby.c:2503
pm_buffer_t
A pm_buffer_t is a simple memory buffer that stores data in a contiguous block of memory.
Definition pm_buffer.h:21
pm_buffer_t::length
size_t length
The length of the buffer in bytes.
Definition pm_buffer.h:23
pm_buffer_t::value
char * value
A pointer to the start of the buffer.
Definition pm_buffer.h:29
pm_node
This is the base structure that represents a node in the syntax tree.
Definition ast.h:1061
pm_options_t
The options that can be passed to the parser.
Definition options.h:30
pm_parser
This struct represents the overall parser.
Definition parser.h:489
pm_string_t
A generic string type that can have various ownership semantics.
Definition pm_string.h:30
rb_ast_struct
Definition rubyparser.h:1096
rb_binding_t
Definition vm_core.h:1250
rb_block
Definition vm_core.h:844
rb_execution_context_struct
Definition vm_core.h:986
rb_iseq_struct
Definition vm_core.h:534
rb_vm_struct
Definition vm_core.h:622
ruby_cmdline_options
Definition cmdlineopt.h:12
ruby_features_t
Definition cmdlineopt.h:7
ruby_opt_message
Definition cmdlineopt.h:48
__attribute__
Definition vm_insnhelper.c:2250
U
Definition dtoa.c:305
ID
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
Definition value.h:52
VALUE
uintptr_t VALUE
Type that represents a Ruby object.
Definition value.h:40