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