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