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