1 /**********************************************************************
2 
3   ruby.c -
4 
5   $Author: nagachika $
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 #ifdef __CYGWIN__
15 #include <windows.h>
16 #include <sys/cygwin.h>
17 #endif
18 #include "ruby/encoding.h"
19 #include "ruby/thread.h"
20 #include "ruby/version.h"
21 #include "internal.h"
22 #include "eval_intern.h"
23 #include "dln.h"
24 #include <stdio.h>
25 #include <sys/types.h>
26 #include <ctype.h>
27 
28 #ifdef __hpux
29 #include <sys/pstat.h>
30 #endif
31 #if defined(LOAD_RELATIVE) && defined(HAVE_DLADDR)
32 #include <dlfcn.h>
33 #endif
34 
35 #ifdef HAVE_UNISTD_H
36 #include <unistd.h>
37 #endif
38 #if defined(HAVE_FCNTL_H)
39 #include <fcntl.h>
40 #elif defined(HAVE_SYS_FCNTL_H)
41 #include <sys/fcntl.h>
42 #endif
43 #ifdef HAVE_SYS_PARAM_H
44 # include <sys/param.h>
45 #endif
46 #ifndef MAXPATHLEN
47 # define MAXPATHLEN 1024
48 #endif
49 #ifndef O_ACCMODE
50 # define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
51 #endif
52 
53 #include "ruby/util.h"
54 
55 #include "mjit.h"
56 
57 void Init_ruby_description(void);
58 
59 #ifndef HAVE_STDLIB_H
60 char *getenv();
61 #endif
62 
63 #ifndef DISABLE_RUBYGEMS
64 # define DISABLE_RUBYGEMS 0
65 #endif
66 #if DISABLE_RUBYGEMS
67 #define DEFAULT_RUBYGEMS_ENABLED "disabled"
68 #else
69 #define DEFAULT_RUBYGEMS_ENABLED "enabled"
70 #endif
71 
72 #define COMMA ,
73 #define FEATURE_BIT(bit) (1U << feature_##bit)
74 #define EACH_FEATURES(X, SEP) \
75     X(gems) \
76     SEP \
77     X(did_you_mean) \
78     SEP \
79     X(rubyopt) \
80     SEP \
81     X(frozen_string_literal) \
82     SEP \
83     X(jit) \
84     /* END OF FEATURES */
85 #define EACH_DEBUG_FEATURES(X, SEP) \
86     X(frozen_string_literal) \
87     /* END OF DEBUG FEATURES */
88 #define AMBIGUOUS_FEATURE_NAMES 0 /* no ambiguous feature names now */
89 #define DEFINE_FEATURE(bit) feature_##bit
90 #define DEFINE_DEBUG_FEATURE(bit) feature_debug_##bit
91 enum feature_flag_bits {
92     EACH_FEATURES(DEFINE_FEATURE, COMMA),
93     feature_debug_flag_first,
94     feature_debug_flag_begin = feature_debug_flag_first - 1,
95     EACH_DEBUG_FEATURES(DEFINE_DEBUG_FEATURE, COMMA),
96     feature_flag_count
97 };
98 
99 #define DEBUG_BIT(bit) (1U << feature_debug_##bit)
100 
101 #define DUMP_BIT(bit) (1U << dump_##bit)
102 #define DEFINE_DUMP(bit) dump_##bit
103 #define EACH_DUMPS(X, SEP) \
104     X(version) \
105     SEP \
106     X(copyright) \
107     SEP \
108     X(usage) \
109     SEP \
110     X(help) \
111     SEP \
112     X(yydebug) \
113     SEP \
114     X(syntax) \
115     SEP \
116     X(parsetree) \
117     SEP \
118     X(parsetree_with_comment) \
119     SEP \
120     X(insns) \
121     /* END OF DUMPS */
122 enum dump_flag_bits {
123     dump_version_v,
124     EACH_DUMPS(DEFINE_DUMP, COMMA),
125     dump_exit_bits = (DUMP_BIT(yydebug) | DUMP_BIT(syntax) |
126 		      DUMP_BIT(parsetree) | DUMP_BIT(parsetree_with_comment) |
127 		      DUMP_BIT(insns))
128 };
129 
130 typedef struct ruby_cmdline_options ruby_cmdline_options_t;
131 
132 struct ruby_cmdline_options {
133     const char *script;
134     VALUE script_name;
135     VALUE e_script;
136     struct {
137 	struct {
138 	    VALUE name;
139 	    int index;
140 	} enc;
141     } src, ext, intern;
142     VALUE req_list;
143     unsigned int features;
144     unsigned int dump;
145 #if USE_MJIT
146     struct mjit_options mjit;
147 #endif
148     int safe_level;
149     int sflag, xflag;
150     unsigned int warning: 1;
151     unsigned int verbose: 1;
152     unsigned int do_loop: 1;
153     unsigned int do_print: 1;
154     unsigned int do_line: 1;
155     unsigned int do_split: 1;
156     unsigned int do_search: 1;
157     unsigned int setids: 2;
158 };
159 
160 static void init_ids(ruby_cmdline_options_t *);
161 
162 #define src_encoding_index GET_VM()->src_encoding_index
163 
164 enum {
165     COMPILATION_FEATURES = (
166 	0
167 	| FEATURE_BIT(frozen_string_literal)
168 	| FEATURE_BIT(debug_frozen_string_literal)
169 	),
170     DEFAULT_FEATURES = (
171 	(FEATURE_BIT(debug_flag_first)-1)
172 #if DISABLE_RUBYGEMS
173 	& ~FEATURE_BIT(gems)
174 #endif
175 	& ~FEATURE_BIT(frozen_string_literal)
176         & ~FEATURE_BIT(jit)
177 	)
178 };
179 
180 static ruby_cmdline_options_t *
cmdline_options_init(ruby_cmdline_options_t * opt)181 cmdline_options_init(ruby_cmdline_options_t *opt)
182 {
183     MEMZERO(opt, *opt, 1);
184     init_ids(opt);
185     opt->src.enc.index = src_encoding_index;
186     opt->ext.enc.index = -1;
187     opt->intern.enc.index = -1;
188     opt->features = DEFAULT_FEATURES;
189 #ifdef MJIT_FORCE_ENABLE /* to use with: ./configure cppflags="-DMJIT_FORCE_ENABLE" */
190     opt->features |= FEATURE_BIT(jit);
191 #endif
192     return opt;
193 }
194 
195 static rb_ast_t *load_file(VALUE parser, VALUE fname, VALUE f, int script,
196 		       ruby_cmdline_options_t *opt);
197 static VALUE open_load_file(VALUE fname_v, int *xflag);
198 static void forbid_setid(const char *, const ruby_cmdline_options_t *);
199 #define forbid_setid(s) forbid_setid((s), opt)
200 
201 static struct {
202     int argc;
203     char **argv;
204 } origarg;
205 
206 static void
show_usage_line(const char * str,unsigned int namelen,unsigned int secondlen,int help)207 show_usage_line(const char *str, unsigned int namelen, unsigned int secondlen, int help)
208 {
209     const unsigned int w = 16;
210     const int wrap = help && namelen + secondlen - 1 > w;
211     printf("  %.*s%-*.*s%-*s%s\n", namelen-1, str,
212 	   (wrap ? 0 : w - namelen + 1),
213 	   (help ? secondlen-1 : 0), str + namelen,
214 	   (wrap ? w + 3 : 0), (wrap ? "\n" : ""),
215 	   str + namelen + secondlen);
216 }
217 
218 static void
usage(const char * name,int help)219 usage(const char *name, int help)
220 {
221     /* This message really ought to be max 23 lines.
222      * Removed -h because the user already knows that option. Others? */
223 
224     struct message {
225 	const char *str;
226 	unsigned short namelen, secondlen;
227     };
228 #define M(shortopt, longopt, desc) { \
229     shortopt " " longopt " " desc, \
230     (unsigned short)sizeof(shortopt), \
231     (unsigned short)sizeof(longopt), \
232 }
233     static const struct message usage_msg[] = {
234 	M("-0[octal]",	   "",			   "specify record separator (\\0, if no argument)"),
235 	M("-a",		   "",			   "autosplit mode with -n or -p (splits $_ into $F)"),
236 	M("-c",		   "",			   "check syntax only"),
237 	M("-Cdirectory",   "",			   "cd to directory before executing your script"),
238 	M("-d",		   ", --debug",		   "set debugging flags (set $DEBUG to true)"),
239 	M("-e 'command'",  "",			   "one line of script. Several -e's allowed. Omit [programfile]"),
240 	M("-Eex[:in]",     ", --encoding=ex[:in]", "specify the default external and internal character encodings"),
241 	M("-Fpattern",	   "",			   "split() pattern for autosplit (-a)"),
242 	M("-i[extension]", "",			   "edit ARGV files in place (make backup if extension supplied)"),
243 	M("-Idirectory",   "",			   "specify $LOAD_PATH directory (may be used more than once)"),
244 	M("-l",		   "",			   "enable line ending processing"),
245 	M("-n",		   "",			   "assume 'while gets(); ... end' loop around your script"),
246 	M("-p",		   "",			   "assume loop like -n but print line also like sed"),
247 	M("-rlibrary",	   "",			   "require the library before executing your script"),
248 	M("-s",		   "",			   "enable some switch parsing for switches after script name"),
249 	M("-S",		   "",			   "look for the script using PATH environment variable"),
250 	M("-T[level=1]",   "",			   "turn on tainting checks"),
251 	M("-v",		   "",			   "print the version number, then turn on verbose mode"),
252 	M("-w",		   "",			   "turn warnings on for your script"),
253 	M("-W[level=2]",   "",			   "set warning level; 0=silence, 1=medium, 2=verbose"),
254 	M("-x[directory]", "",			   "strip off text before #!ruby line and perhaps cd to directory"),
255         M("--jit",         "",                     "enable JIT with default options (experimental)"),
256         M("--jit-[option]","",                     "enable JIT with an option (experimental)"),
257 	M("-h",		   "",			   "show this message, --help for more info"),
258     };
259     static const struct message help_msg[] = {
260 	M("--copyright",                            "", "print the copyright"),
261 	M("--dump={insns|parsetree|...}[,...]",     "",
262           "dump debug information. see below for available dump list"),
263 	M("--enable={gems|rubyopt|...}[,...]", ", --disable={gems|rubyopt|...}[,...]",
264 	  "enable or disable features. see below for available features"),
265 	M("--external-encoding=encoding",           ", --internal-encoding=encoding",
266 	  "specify the default external or internal character encoding"),
267 	M("--verbose",                              "", "turn on verbose mode and disable script from stdin"),
268 	M("--version",                              "", "print the version number, then exit"),
269 	M("--help",			            "", "show this message, -h for short message"),
270     };
271     static const struct message dumps[] = {
272 	M("insns",                  "", "instruction sequences"),
273 	M("yydebug",                "", "yydebug of yacc parser generator"),
274 	M("parsetree",              "", "AST"),
275 	M("parsetree_with_comment", "", "AST with comments"),
276     };
277     static const struct message features[] = {
278 	M("gems",    "",        "rubygems (default: "DEFAULT_RUBYGEMS_ENABLED")"),
279 	M("did_you_mean", "",   "did_you_mean (default: "DEFAULT_RUBYGEMS_ENABLED")"),
280 	M("rubyopt", "",        "RUBYOPT environment variable (default: enabled)"),
281 	M("frozen-string-literal", "", "freeze all string literals (default: disabled)"),
282         M("jit", "",            "JIT compiler (default: disabled)"),
283     };
284     static const struct message mjit_options[] = {
285         M("--jit-warnings",      "", "Enable printing JIT warnings"),
286         M("--jit-debug",         "", "Enable JIT debugging (very slow)"),
287         M("--jit-wait",          "", "Wait until JIT compilation is finished everytime (for testing)"),
288         M("--jit-save-temps",    "", "Save JIT temporary files in $TMP or /tmp (for testing)"),
289         M("--jit-verbose=num",   "", "Print JIT logs of level num or less to stderr (default: 0)"),
290         M("--jit-max-cache=num", "", "Max number of methods to be JIT-ed in a cache (default: 1000)"),
291         M("--jit-min-calls=num", "", "Number of calls to trigger JIT (for testing, default: 5)"),
292     };
293     int i;
294     const int num = numberof(usage_msg) - (help ? 1 : 0);
295 #define SHOW(m) show_usage_line((m).str, (m).namelen, (m).secondlen, help)
296 
297     printf("Usage: %s [switches] [--] [programfile] [arguments]\n", name);
298     for (i = 0; i < num; ++i)
299 	SHOW(usage_msg[i]);
300 
301     if (!help) return;
302 
303     for (i = 0; i < numberof(help_msg); ++i)
304 	SHOW(help_msg[i]);
305     puts("Dump List:");
306     for (i = 0; i < numberof(dumps); ++i)
307 	SHOW(dumps[i]);
308     puts("Features:");
309     for (i = 0; i < numberof(features); ++i)
310 	SHOW(features[i]);
311     puts("JIT options (experimental):");
312     for (i = 0; i < numberof(mjit_options); ++i)
313 	SHOW(mjit_options[i]);
314 }
315 
316 #define rubylib_path_new rb_str_new
317 
318 static void
push_include(const char * path,VALUE (* filter)(VALUE))319 push_include(const char *path, VALUE (*filter)(VALUE))
320 {
321     const char sep = PATH_SEP_CHAR;
322     const char *p, *s;
323     VALUE load_path = GET_VM()->load_path;
324 
325     p = path;
326     while (*p) {
327 	while (*p == sep)
328 	    p++;
329 	if (!*p) break;
330 	for (s = p; *s && *s != sep; s = CharNext(s));
331 	rb_ary_push(load_path, (*filter)(rubylib_path_new(p, s - p)));
332 	p = s;
333     }
334 }
335 
336 #ifdef __CYGWIN__
337 static void
push_include_cygwin(const char * path,VALUE (* filter)(VALUE))338 push_include_cygwin(const char *path, VALUE (*filter)(VALUE))
339 {
340     const char *p, *s;
341     char rubylib[FILENAME_MAX];
342     VALUE buf = 0;
343 
344     p = path;
345     while (*p) {
346 	unsigned int len;
347 	while (*p == ';')
348 	    p++;
349 	if (!*p) break;
350 	for (s = p; *s && *s != ';'; s = CharNext(s));
351 	len = s - p;
352 	if (*s) {
353 	    if (!buf) {
354 		buf = rb_str_new(p, len);
355 		p = RSTRING_PTR(buf);
356 	    }
357 	    else {
358 		rb_str_resize(buf, len);
359 		p = strncpy(RSTRING_PTR(buf), p, len);
360 	    }
361 	}
362 #ifdef HAVE_CYGWIN_CONV_PATH
363 #define CONV_TO_POSIX_PATH(p, lib) \
364 	cygwin_conv_path(CCP_WIN_A_TO_POSIX|CCP_RELATIVE, (p), (lib), sizeof(lib))
365 #else
366 # error no cygwin_conv_path
367 #endif
368 	if (CONV_TO_POSIX_PATH(p, rubylib) == 0)
369 	    p = rubylib;
370 	push_include(p, filter);
371 	if (!*s) break;
372 	p = s + 1;
373     }
374 }
375 
376 #define push_include push_include_cygwin
377 #endif
378 
379 void
ruby_push_include(const char * path,VALUE (* filter)(VALUE))380 ruby_push_include(const char *path, VALUE (*filter)(VALUE))
381 {
382     if (path == 0)
383 	return;
384     push_include(path, filter);
385 }
386 
387 static VALUE
identical_path(VALUE path)388 identical_path(VALUE path)
389 {
390     return path;
391 }
392 static VALUE
locale_path(VALUE path)393 locale_path(VALUE path)
394 {
395     rb_enc_associate(path, rb_locale_encoding());
396     return path;
397 }
398 
399 void
ruby_incpush(const char * path)400 ruby_incpush(const char *path)
401 {
402     ruby_push_include(path, locale_path);
403 }
404 
405 static VALUE
expand_include_path(VALUE path)406 expand_include_path(VALUE path)
407 {
408     char *p = RSTRING_PTR(path);
409     if (!p)
410 	return path;
411     if (*p == '.' && p[1] == '/')
412 	return path;
413     return rb_file_expand_path(path, Qnil);
414 }
415 
416 void
ruby_incpush_expand(const char * path)417 ruby_incpush_expand(const char *path)
418 {
419     ruby_push_include(path, expand_include_path);
420 }
421 
422 #undef UTF8_PATH
423 #if defined _WIN32 || defined __CYGWIN__
424 static HMODULE libruby;
425 
426 BOOL WINAPI
DllMain(HINSTANCE dll,DWORD reason,LPVOID reserved)427 DllMain(HINSTANCE dll, DWORD reason, LPVOID reserved)
428 {
429     if (reason == DLL_PROCESS_ATTACH)
430 	libruby = dll;
431     return TRUE;
432 }
433 
434 HANDLE
rb_libruby_handle(void)435 rb_libruby_handle(void)
436 {
437     return libruby;
438 }
439 
440 static inline void
translit_char_bin(char * p,int from,int to)441 translit_char_bin(char *p, int from, int to)
442 {
443     while (*p) {
444 	if ((unsigned char)*p == from)
445 	    *p = to;
446 	p++;
447     }
448 }
449 #endif
450 
451 #ifdef _WIN32
452 # define UTF8_PATH 1
453 #endif
454 
455 #ifndef UTF8_PATH
456 # define UTF8_PATH 0
457 #endif
458 #if UTF8_PATH
459 # define IF_UTF8_PATH(t, f) t
460 #else
461 # define IF_UTF8_PATH(t, f) f
462 #endif
463 
464 #if UTF8_PATH
465 static VALUE
str_conv_enc(VALUE str,rb_encoding * from,rb_encoding * to)466 str_conv_enc(VALUE str, rb_encoding *from, rb_encoding *to)
467 {
468     return rb_str_conv_enc_opts(str, from, to,
469 				ECONV_UNDEF_REPLACE|ECONV_INVALID_REPLACE,
470 				Qnil);
471 }
472 #else
473 # define str_conv_enc(str, from, to) (str)
474 #endif
475 
476 void ruby_init_loadpath_safe(int safe_level);
477 
478 void
ruby_init_loadpath(void)479 ruby_init_loadpath(void)
480 {
481     ruby_init_loadpath_safe(0);
482 }
483 
484 #if defined(LOAD_RELATIVE)
485 static VALUE
runtime_libruby_path(void)486 runtime_libruby_path(void)
487 {
488 #if defined _WIN32 || defined __CYGWIN__
489     DWORD len = RSTRING_EMBED_LEN_MAX, ret;
490     VALUE path;
491     VALUE wsopath = rb_str_new(0, len*sizeof(WCHAR));
492     WCHAR *wlibpath;
493     char *libpath;
494 
495     while (wlibpath = (WCHAR *)RSTRING_PTR(wsopath),
496 	   ret = GetModuleFileNameW(libruby, wlibpath, len),
497 	   (ret == len))
498     {
499 	rb_str_modify_expand(wsopath, len*sizeof(WCHAR));
500 	rb_str_set_len(wsopath, (len += len)*sizeof(WCHAR));
501     }
502     if (!ret || ret > len) rb_fatal("failed to get module file name");
503 #if defined __CYGWIN__
504     {
505 	const int win_to_posix = CCP_WIN_W_TO_POSIX | CCP_RELATIVE;
506 	size_t newsize = cygwin_conv_path(win_to_posix, wlibpath, 0, 0);
507 	if (!newsize) rb_fatal("failed to convert module path to cygwin");
508 	path = rb_str_new(0, newsize);
509 	libpath = RSTRING_PTR(path);
510 	if (cygwin_conv_path(win_to_posix, wlibpath, libpath, newsize)) {
511 	    rb_str_resize(path, 0);
512 	}
513     }
514 #else
515     {
516 	DWORD i;
517 	for (len = ret, i = 0; i < len; ++i) {
518 	    if (wlibpath[i] == L'\\') {
519 		wlibpath[i] = L'/';
520 		ret = i+1;	/* chop after the last separator */
521 	    }
522 	}
523     }
524     len = WideCharToMultiByte(CP_UTF8, 0, wlibpath, ret, NULL, 0, NULL, NULL);
525     path = rb_utf8_str_new(0, len);
526     libpath = RSTRING_PTR(path);
527     WideCharToMultiByte(CP_UTF8, 0, wlibpath, ret, libpath, len, NULL, NULL);
528 #endif
529     rb_str_resize(wsopath, 0);
530     return path;
531 #elif defined(HAVE_DLADDR)
532     Dl_info dli;
533     VALUE fname, path;
534     const void* addr = (void *)(VALUE)expand_include_path;
535 
536     if (!dladdr((void *)addr, &dli)) {
537 	return rb_str_new(0, 0);
538     }
539 #ifdef __linux__
540     else if (origarg.argc > 0 && origarg.argv && dli.dli_fname == origarg.argv[0]) {
541 	fname = rb_str_new_cstr("/proc/self/exe");
542 	path = rb_readlink(fname, NULL);
543     }
544 #endif
545     else {
546 	fname = rb_str_new_cstr(dli.dli_fname);
547 	path = rb_realpath_internal(Qnil, fname, 1);
548     }
549     rb_str_resize(fname, 0);
550     return path;
551 #else
552 # error relative load path is not supported on this platform.
553 #endif
554 }
555 #endif
556 
557 #define INITIAL_LOAD_PATH_MARK rb_intern_const("@gem_prelude_index")
558 
559 VALUE ruby_archlibdir_path, ruby_prefix_path;
560 
561 void
ruby_init_loadpath_safe(int safe_level)562 ruby_init_loadpath_safe(int safe_level)
563 {
564     VALUE load_path, archlibdir = 0;
565     ID id_initial_load_path_mark;
566     const char *paths = ruby_initial_load_paths;
567 #if defined LOAD_RELATIVE
568 #if !defined ENABLE_MULTIARCH
569 # define RUBY_ARCH_PATH ""
570 #elif defined RUBY_ARCH
571 # define RUBY_ARCH_PATH "/"RUBY_ARCH
572 #else
573 # define RUBY_ARCH_PATH "/"RUBY_PLATFORM
574 #endif
575     char *libpath;
576     VALUE sopath;
577     size_t baselen;
578     const char *p;
579 
580     sopath = runtime_libruby_path();
581     libpath = RSTRING_PTR(sopath);
582 
583     p = strrchr(libpath, '/');
584     if (p) {
585 	static const char libdir[] = "/"
586 #ifdef LIBDIR_BASENAME
587 	    LIBDIR_BASENAME
588 #else
589 	    "lib"
590 #endif
591 	    RUBY_ARCH_PATH;
592 	const ptrdiff_t libdir_len = (ptrdiff_t)sizeof(libdir)
593 	    - rb_strlen_lit(RUBY_ARCH_PATH) - 1;
594 	static const char bindir[] = "/bin";
595 	const ptrdiff_t bindir_len = (ptrdiff_t)sizeof(bindir) - 1;
596 
597 	const char *p2 = NULL;
598 
599 #ifdef ENABLE_MULTIARCH
600       multiarch:
601 #endif
602 	if (p - libpath >= bindir_len && !STRNCASECMP(p - bindir_len, bindir, bindir_len)) {
603 	    p -= bindir_len;
604 	    archlibdir = rb_str_subseq(sopath, 0, p - libpath);
605 	    rb_str_cat_cstr(archlibdir, libdir);
606 	    OBJ_FREEZE_RAW(archlibdir);
607 	}
608 	else if (p - libpath >= libdir_len && !strncmp(p - libdir_len, libdir, libdir_len)) {
609 	    archlibdir = rb_str_subseq(sopath, 0, (p2 ? p2 : p) - libpath);
610 	    OBJ_FREEZE_RAW(archlibdir);
611 	    p -= libdir_len;
612 	}
613 #ifdef ENABLE_MULTIARCH
614 	else if (p2) {
615 	    p = p2;
616 	}
617 	else {
618 	    p2 = p;
619 	    p = rb_enc_path_last_separator(libpath, p, rb_ascii8bit_encoding());
620 	    if (p) goto multiarch;
621 	    p = p2;
622 	}
623 #endif
624     }
625     baselen = p - libpath;
626     rb_str_resize(sopath, baselen);
627     libpath = RSTRING_PTR(sopath);
628 #define PREFIX_PATH() sopath
629 #define BASEPATH() rb_str_buf_cat(rb_str_buf_new(baselen+len), libpath, baselen)
630 #define RUBY_RELATIVE(path, len) rb_str_buf_cat(BASEPATH(), (path), (len))
631 #else
632     const size_t exec_prefix_len = strlen(ruby_exec_prefix);
633 #define RUBY_RELATIVE(path, len) rubylib_path_new((path), (len))
634 #define PREFIX_PATH() RUBY_RELATIVE(ruby_exec_prefix, exec_prefix_len)
635 #endif
636     rb_gc_register_address(&ruby_prefix_path);
637     ruby_prefix_path = PREFIX_PATH();
638     OBJ_FREEZE_RAW(ruby_prefix_path);
639     if (!archlibdir) archlibdir = ruby_prefix_path;
640     rb_gc_register_address(&ruby_archlibdir_path);
641     ruby_archlibdir_path = archlibdir;
642 
643     load_path = GET_VM()->load_path;
644 
645     if (safe_level == 0) {
646 	ruby_push_include(getenv("RUBYLIB"), identical_path);
647     }
648 
649     id_initial_load_path_mark = INITIAL_LOAD_PATH_MARK;
650     while (*paths) {
651 	size_t len = strlen(paths);
652 	VALUE path = RUBY_RELATIVE(paths, len);
653 	rb_ivar_set(path, id_initial_load_path_mark, path);
654 	rb_ary_push(load_path, path);
655 	paths += len + 1;
656     }
657 
658     rb_const_set(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX"), ruby_prefix_path);
659 }
660 
661 
662 static void
add_modules(VALUE * req_list,const char * mod)663 add_modules(VALUE *req_list, const char *mod)
664 {
665     VALUE list = *req_list;
666     VALUE feature;
667 
668     if (!list) {
669 	*req_list = list = rb_ary_tmp_new(0);
670     }
671     feature = rb_str_cat_cstr(rb_str_tmp_new(0), mod);
672     rb_ary_push(list, feature);
673 }
674 
675 static void
require_libraries(VALUE * req_list)676 require_libraries(VALUE *req_list)
677 {
678     VALUE list = *req_list;
679     VALUE self = rb_vm_top_self();
680     ID require;
681     rb_encoding *extenc = rb_default_external_encoding();
682 
683     CONST_ID(require, "require");
684     while (list && RARRAY_LEN(list) > 0) {
685 	VALUE feature = rb_ary_shift(list);
686 	rb_enc_associate(feature, extenc);
687 	RBASIC_SET_CLASS_RAW(feature, rb_cString);
688 	OBJ_FREEZE(feature);
689 	rb_funcallv(self, require, 1, &feature);
690     }
691     *req_list = 0;
692 }
693 
694 static const struct rb_block*
toplevel_context(rb_binding_t * bind)695 toplevel_context(rb_binding_t *bind)
696 {
697     return &bind->block;
698 }
699 
700 static void
process_sflag(int * sflag)701 process_sflag(int *sflag)
702 {
703     if (*sflag > 0) {
704 	long n;
705 	const VALUE *args;
706 	VALUE argv = rb_argv;
707 
708 	n = RARRAY_LEN(argv);
709 	args = RARRAY_CONST_PTR(argv);
710 	while (n > 0) {
711 	    VALUE v = *args++;
712 	    char *s = StringValuePtr(v);
713 	    char *p;
714 	    int hyphen = FALSE;
715 
716 	    if (s[0] != '-')
717 		break;
718 	    n--;
719 	    if (s[1] == '-' && s[2] == '\0')
720 		break;
721 
722 	    v = Qtrue;
723 	    /* check if valid name before replacing - with _ */
724 	    for (p = s + 1; *p; p++) {
725 		if (*p == '=') {
726 		    *p++ = '\0';
727 		    v = rb_str_new2(p);
728 		    break;
729 		}
730 		if (*p == '-') {
731 		    hyphen = TRUE;
732 		}
733 		else if (*p != '_' && !ISALNUM(*p)) {
734 		    VALUE name_error[2];
735 		    name_error[0] =
736 			rb_str_new2("invalid name for global variable - ");
737 		    if (!(p = strchr(p, '='))) {
738 			rb_str_cat2(name_error[0], s);
739 		    }
740 		    else {
741 			rb_str_cat(name_error[0], s, p - s);
742 		    }
743 		    name_error[1] = args[-1];
744 		    rb_exc_raise(rb_class_new_instance(2, name_error, rb_eNameError));
745 		}
746 	    }
747 	    s[0] = '$';
748 	    if (hyphen) {
749 		for (p = s + 1; *p; ++p) {
750 		    if (*p == '-')
751 			*p = '_';
752 		}
753 	    }
754 	    rb_gv_set(s, v);
755 	}
756 	n = RARRAY_LEN(argv) - n;
757 	while (n--) {
758 	    rb_ary_shift(argv);
759 	}
760 	*sflag = -1;
761     }
762 }
763 
764 static long proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt);
765 
766 static void
moreswitches(const char * s,ruby_cmdline_options_t * opt,int envopt)767 moreswitches(const char *s, ruby_cmdline_options_t *opt, int envopt)
768 {
769     long argc, i, len;
770     char **argv, *p;
771     const char *ap = 0;
772     VALUE argstr, argary;
773     void *ptr;
774 
775     while (ISSPACE(*s)) s++;
776     if (!*s) return;
777     argstr = rb_str_tmp_new((len = strlen(s)) + (envopt!=0));
778     argary = rb_str_tmp_new(0);
779 
780     p = RSTRING_PTR(argstr);
781     if (envopt) *p++ = ' ';
782     memcpy(p, s, len + 1);
783     ap = 0;
784     rb_str_cat(argary, (char *)&ap, sizeof(ap));
785     while (*p) {
786 	ap = p;
787 	rb_str_cat(argary, (char *)&ap, sizeof(ap));
788 	while (*p && !ISSPACE(*p)) ++p;
789 	if (!*p) break;
790 	*p++ = '\0';
791 	while (ISSPACE(*p)) ++p;
792     }
793     argc = RSTRING_LEN(argary) / sizeof(ap);
794     ap = 0;
795     rb_str_cat(argary, (char *)&ap, sizeof(ap));
796     argv = ptr = ALLOC_N(char *, argc);
797     MEMMOVE(argv, RSTRING_PTR(argary), char *, argc);
798 
799     while ((i = proc_options(argc, argv, opt, envopt)) > 1 && envopt && (argc -= i) > 0) {
800 	argv += i;
801 	if (**argv != '-') {
802 	    *--*argv = '-';
803 	}
804 	if ((*argv)[1]) {
805 	    ++argc;
806 	    --argv;
807 	}
808     }
809 
810     ruby_xfree(ptr);
811     /* get rid of GC */
812     rb_str_resize(argary, 0);
813     rb_str_resize(argstr, 0);
814 }
815 
816 static int
name_match_p(const char * name,const char * str,size_t len)817 name_match_p(const char *name, const char *str, size_t len)
818 {
819     if (len == 0) return 0;
820     do {
821 	while (TOLOWER(*str) == *name) {
822 	    if (!--len || !*++str) return 1;
823 	    ++name;
824 	}
825 	if (*str != '-' && *str != '_') return 0;
826 	while (ISALNUM(*name)) name++;
827 	if (*name != '-' && *name != '_') return 0;
828 	++name;
829 	++str;
830     } while (len > 0);
831     return !*name;
832 }
833 
834 #define NAME_MATCH_P(name, str, len) \
835     ((len) < (int)sizeof(name) && name_match_p((name), (str), (len)))
836 
837 #define UNSET_WHEN(name, bit, str, len)	\
838     if (NAME_MATCH_P((name), (str), (len))) { \
839 	*(unsigned int *)arg &= ~(bit); \
840 	return;				\
841     }
842 
843 #define SET_WHEN(name, bit, str, len)	\
844     if (NAME_MATCH_P((name), (str), (len))) { \
845 	*(unsigned int *)arg |= (bit);	\
846 	return;				\
847     }
848 
849 #define LITERAL_NAME_ELEMENT(name) #name
850 
851 static void
feature_option(const char * str,int len,void * arg,const unsigned int enable)852 feature_option(const char *str, int len, void *arg, const unsigned int enable)
853 {
854     static const char list[] = EACH_FEATURES(LITERAL_NAME_ELEMENT, ", ");
855     unsigned int *argp = arg;
856     unsigned int mask = ~0U;
857 #if AMBIGUOUS_FEATURE_NAMES
858     unsigned int set = 0U;
859     int matched = 0;
860 #define SET_FEATURE(bit) \
861     if (NAME_MATCH_P(#bit, str, len)) {set |= mask = FEATURE_BIT(bit); ++matched;}
862 #else
863 #define SET_FEATURE(bit) \
864     if (NAME_MATCH_P(#bit, str, len)) {mask = FEATURE_BIT(bit); goto found;}
865 #endif
866     EACH_FEATURES(SET_FEATURE, ;);
867     if (NAME_MATCH_P("all", str, len)) {
868       found:
869 	*argp = (*argp & ~mask) | (mask & enable);
870 	return;
871     }
872 #if AMBIGUOUS_FEATURE_NAMES
873     if (matched == 1) goto found;
874     if (matched > 1) {
875 	VALUE mesg = rb_sprintf("ambiguous feature: `%.*s' (", len, str);
876 #define ADD_FEATURE_NAME(bit) \
877 	if (FEATURE_BIT(bit) & set) { \
878 	    rb_str_cat_cstr(mesg, #bit); \
879 	    if (--matched) rb_str_cat_cstr(mesg, ", "); \
880 	}
881 	EACH_FEATURES(ADD_FEATURE_NAME, ;);
882 	rb_str_cat_cstr(mesg, ")");
883 	rb_exc_raise(rb_exc_new_str(rb_eRuntimeError, mesg));
884 #undef ADD_FEATURE_NAME
885     }
886 #endif
887     rb_warn("unknown argument for --%s: `%.*s'",
888 	    enable ? "enable" : "disable", len, str);
889     rb_warn("features are [%.*s].", (int)strlen(list), list);
890 }
891 
892 static void
enable_option(const char * str,int len,void * arg)893 enable_option(const char *str, int len, void *arg)
894 {
895     feature_option(str, len, arg, ~0U);
896 }
897 
898 static void
disable_option(const char * str,int len,void * arg)899 disable_option(const char *str, int len, void *arg)
900 {
901     feature_option(str, len, arg, 0U);
902 }
903 
904 RUBY_EXTERN const int  ruby_patchlevel;
905 int ruby_env_debug_option(const char *str, int len, void *arg);
906 
907 static void
debug_option(const char * str,int len,void * arg)908 debug_option(const char *str, int len, void *arg)
909 {
910     static const char list[] = EACH_DEBUG_FEATURES(LITERAL_NAME_ELEMENT, ", ");
911 #define SET_WHEN_DEBUG(bit) SET_WHEN(#bit, DEBUG_BIT(bit), str, len)
912     EACH_DEBUG_FEATURES(SET_WHEN_DEBUG, ;);
913 #ifdef RUBY_DEVEL
914     if (ruby_patchlevel < 0 && ruby_env_debug_option(str, len, 0)) return;
915 #endif
916     rb_warn("unknown argument for --debug: `%.*s'", len, str);
917     rb_warn("debug features are [%.*s].", (int)strlen(list), list);
918 }
919 
920 static void
dump_option(const char * str,int len,void * arg)921 dump_option(const char *str, int len, void *arg)
922 {
923     static const char list[] = EACH_DUMPS(LITERAL_NAME_ELEMENT, ", ");
924 #define SET_WHEN_DUMP(bit) SET_WHEN(#bit, DUMP_BIT(bit), str, len)
925     EACH_DUMPS(SET_WHEN_DUMP, ;);
926     rb_warn("don't know how to dump `%.*s',", len, str);
927     rb_warn("but only [%.*s].", (int)strlen(list), list);
928 }
929 
930 static void
set_option_encoding_once(const char * type,VALUE * name,const char * e,long elen)931 set_option_encoding_once(const char *type, VALUE *name, const char *e, long elen)
932 {
933     VALUE ename;
934 
935     if (!elen) elen = strlen(e);
936     ename = rb_str_new(e, elen);
937 
938     if (*name &&
939 	rb_funcall(ename, rb_intern("casecmp"), 1, *name) != INT2FIX(0)) {
940 	rb_raise(rb_eRuntimeError,
941 		 "%s already set to %"PRIsVALUE, type, *name);
942     }
943     *name = ename;
944 }
945 
946 #define set_internal_encoding_once(opt, e, elen) \
947     set_option_encoding_once("default_internal", &(opt)->intern.enc.name, (e), (elen))
948 #define set_external_encoding_once(opt, e, elen) \
949     set_option_encoding_once("default_external", &(opt)->ext.enc.name, (e), (elen))
950 #define set_source_encoding_once(opt, e, elen) \
951     set_option_encoding_once("source", &(opt)->src.enc.name, (e), (elen))
952 
953 #if USE_MJIT
954 static void
setup_mjit_options(const char * s,struct mjit_options * mjit_opt)955 setup_mjit_options(const char *s, struct mjit_options *mjit_opt)
956 {
957     if (*s == 0) return;
958     else if (strcmp(s, "-warnings") == 0) {
959         mjit_opt->warnings = 1;
960     }
961     else if (strcmp(s, "-debug") == 0) {
962         mjit_opt->debug = 1;
963     }
964     else if (strcmp(s, "-wait") == 0) {
965         mjit_opt->wait = 1;
966     }
967     else if (strcmp(s, "-save-temps") == 0) {
968         mjit_opt->save_temps = 1;
969     }
970     else if (strncmp(s, "-verbose=", 9) == 0) {
971         mjit_opt->verbose = atoi(s + 9);
972     }
973     else if (strncmp(s, "-max-cache=", 11) == 0) {
974         mjit_opt->max_cache_size = atoi(s + 11);
975     }
976     else if (strncmp(s, "-min-calls=", 11) == 0) {
977         mjit_opt->min_calls = atoi(s + 11);
978     }
979     else {
980         rb_raise(rb_eRuntimeError,
981                  "invalid MJIT option `%s' (--help will show valid MJIT options)", s + 1);
982     }
983 }
984 #endif
985 
986 static long
proc_options(long argc,char ** argv,ruby_cmdline_options_t * opt,int envopt)987 proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt)
988 {
989     long n, argc0 = argc;
990     const char *s;
991     int warning = opt->warning;
992 
993     if (argc <= 0 || !argv)
994 	return 0;
995 
996     for (argc--, argv++; argc > 0; argc--, argv++) {
997 	const char *const arg = argv[0];
998 	if (!arg || arg[0] != '-' || !arg[1])
999 	    break;
1000 
1001 	s = arg + 1;
1002       reswitch:
1003 	switch (*s) {
1004 	  case 'a':
1005 	    if (envopt) goto noenvopt;
1006 	    opt->do_split = TRUE;
1007 	    s++;
1008 	    goto reswitch;
1009 
1010 	  case 'p':
1011 	    if (envopt) goto noenvopt;
1012 	    opt->do_print = TRUE;
1013 	    /* through */
1014 	  case 'n':
1015 	    if (envopt) goto noenvopt;
1016 	    opt->do_loop = TRUE;
1017 	    s++;
1018 	    goto reswitch;
1019 
1020 	  case 'd':
1021 	    ruby_debug = Qtrue;
1022 	    ruby_verbose = Qtrue;
1023 	    s++;
1024 	    goto reswitch;
1025 
1026 	  case 'y':
1027 	    if (envopt) goto noenvopt;
1028 	    opt->dump |= DUMP_BIT(yydebug);
1029 	    s++;
1030 	    goto reswitch;
1031 
1032 	  case 'v':
1033 	    if (opt->verbose) {
1034 		s++;
1035 		goto reswitch;
1036 	    }
1037 	    opt->dump |= DUMP_BIT(version_v);
1038 	    opt->verbose = 1;
1039 	  case 'w':
1040 	    if (!opt->warning) {
1041 		warning = 1;
1042 		ruby_verbose = Qtrue;
1043 	    }
1044 	    s++;
1045 	    goto reswitch;
1046 
1047 	  case 'W':
1048 	    {
1049 		size_t numlen;
1050 		int v = 2;	/* -W as -W2 */
1051 
1052 		if (*++s) {
1053 		    v = scan_oct(s, 1, &numlen);
1054 		    if (numlen == 0)
1055 			v = 1;
1056 		    s += numlen;
1057 		}
1058 		if (!opt->warning) {
1059 		    switch (v) {
1060 		      case 0:
1061 			ruby_verbose = Qnil;
1062 			break;
1063 		      case 1:
1064 			ruby_verbose = Qfalse;
1065 			break;
1066 		      default:
1067 			ruby_verbose = Qtrue;
1068 			break;
1069 		    }
1070 		}
1071 		warning = 1;
1072 	    }
1073 	    goto reswitch;
1074 
1075 	  case 'c':
1076 	    if (envopt) goto noenvopt;
1077 	    opt->dump |= DUMP_BIT(syntax);
1078 	    s++;
1079 	    goto reswitch;
1080 
1081 	  case 's':
1082 	    if (envopt) goto noenvopt;
1083 	    forbid_setid("-s");
1084 	    if (!opt->sflag) opt->sflag = 1;
1085 	    s++;
1086 	    goto reswitch;
1087 
1088 	  case 'h':
1089 	    if (envopt) goto noenvopt;
1090 	    opt->dump |= DUMP_BIT(usage);
1091 	    goto switch_end;
1092 
1093 	  case 'l':
1094 	    if (envopt) goto noenvopt;
1095 	    opt->do_line = TRUE;
1096 	    rb_output_rs = rb_rs;
1097 	    s++;
1098 	    goto reswitch;
1099 
1100 	  case 'S':
1101 	    if (envopt) goto noenvopt;
1102 	    forbid_setid("-S");
1103 	    opt->do_search = TRUE;
1104 	    s++;
1105 	    goto reswitch;
1106 
1107 	  case 'e':
1108 	    if (envopt) goto noenvopt;
1109 	    forbid_setid("-e");
1110 	    if (!*++s) {
1111 		if (!--argc)
1112 		    rb_raise(rb_eRuntimeError, "no code specified for -e");
1113 		s = *++argv;
1114 	    }
1115 	    if (!opt->e_script) {
1116 		opt->e_script = rb_str_new(0, 0);
1117 		if (opt->script == 0)
1118 		    opt->script = "-e";
1119 	    }
1120 	    rb_str_cat2(opt->e_script, s);
1121 	    rb_str_cat2(opt->e_script, "\n");
1122 	    break;
1123 
1124 	  case 'r':
1125 	    forbid_setid("-r");
1126 	    if (*++s) {
1127 		add_modules(&opt->req_list, s);
1128 	    }
1129 	    else if (argc > 1) {
1130 		add_modules(&opt->req_list, argv[1]);
1131 		argc--, argv++;
1132 	    }
1133 	    break;
1134 
1135 	  case 'i':
1136 	    if (envopt) goto noenvopt;
1137 	    forbid_setid("-i");
1138 	    ruby_set_inplace_mode(s + 1);
1139 	    break;
1140 
1141 	  case 'x':
1142 	    if (envopt) goto noenvopt;
1143 	    forbid_setid("-x");
1144 	    opt->xflag = TRUE;
1145 	    s++;
1146 	    if (*s && chdir(s) < 0) {
1147 		rb_fatal("Can't chdir to %s", s);
1148 	    }
1149 	    break;
1150 
1151 	  case 'C':
1152 	  case 'X':
1153 	    if (envopt) goto noenvopt;
1154 	    if (!*++s && (!--argc || !(s = *++argv) || !*s)) {
1155 		rb_fatal("Can't chdir");
1156 	    }
1157 	    if (chdir(s) < 0) {
1158 		rb_fatal("Can't chdir to %s", s);
1159 	    }
1160 	    break;
1161 
1162 	  case 'F':
1163 	    if (envopt) goto noenvopt;
1164 	    if (*++s) {
1165 		rb_fs = rb_reg_new(s, strlen(s), 0);
1166 	    }
1167 	    break;
1168 
1169 	  case 'E':
1170 	    if (!*++s && (!--argc || !(s = *++argv))) {
1171 		rb_raise(rb_eRuntimeError, "missing argument for -E");
1172 	    }
1173 	    goto encoding;
1174 
1175 	  case 'U':
1176 	    set_internal_encoding_once(opt, "UTF-8", 0);
1177 	    ++s;
1178 	    goto reswitch;
1179 
1180 	  case 'K':
1181 	    if (*++s) {
1182 		const char *enc_name = 0;
1183 		switch (*s) {
1184 		  case 'E': case 'e':
1185 		    enc_name = "EUC-JP";
1186 		    break;
1187 		  case 'S': case 's':
1188 		    enc_name = "Windows-31J";
1189 		    break;
1190 		  case 'U': case 'u':
1191 		    enc_name = "UTF-8";
1192 		    break;
1193 		  case 'N': case 'n': case 'A': case 'a':
1194 		    enc_name = "ASCII-8BIT";
1195 		    break;
1196 		}
1197 		if (enc_name) {
1198 		    opt->src.enc.name = rb_str_new2(enc_name);
1199 		    if (!opt->ext.enc.name)
1200 			opt->ext.enc.name = opt->src.enc.name;
1201 		}
1202 		s++;
1203 	    }
1204 	    goto reswitch;
1205 
1206 	  case 'T':
1207 	    {
1208 		size_t numlen;
1209 		int v = 1;
1210 
1211 		if (*++s) {
1212 		    v = scan_oct(s, 2, &numlen);
1213 		    if (numlen == 0)
1214 			v = 1;
1215 		    s += numlen;
1216 		}
1217 		if (v > opt->safe_level) opt->safe_level = v;
1218 	    }
1219 	    goto reswitch;
1220 
1221 	  case 'I':
1222 	    forbid_setid("-I");
1223 	    if (*++s)
1224 		ruby_incpush_expand(s);
1225 	    else if (argc > 1) {
1226 		ruby_incpush_expand(argv[1]);
1227 		argc--, argv++;
1228 	    }
1229 	    break;
1230 
1231 	  case '0':
1232 	    if (envopt) goto noenvopt;
1233 	    {
1234 		size_t numlen;
1235 		int v;
1236 		char c;
1237 
1238 		v = scan_oct(s, 4, &numlen);
1239 		s += numlen;
1240 		if (v > 0377)
1241 		    rb_rs = Qnil;
1242 		else if (v == 0 && numlen >= 2) {
1243 		    rb_rs = rb_str_new2("");
1244 		}
1245 		else {
1246 		    c = v & 0xff;
1247 		    rb_rs = rb_str_new(&c, 1);
1248 		}
1249 	    }
1250 	    goto reswitch;
1251 
1252 	  case '-':
1253 	    if (!s[1] || (s[1] == '\r' && !s[2])) {
1254 		argc--, argv++;
1255 		goto switch_end;
1256 	    }
1257 	    s++;
1258 
1259 #	define is_option_end(c, allow_hyphen) \
1260 	    (!(c) || ((allow_hyphen) && (c) == '-') || (c) == '=')
1261 #	define check_envopt(name, allow_envopt) \
1262 	    (((allow_envopt) || !envopt) ? (void)0 : \
1263 	     rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --" name))
1264 #	define need_argument(name, s, needs_arg, next_arg)			\
1265 	    ((*(s) ? !*++(s) : (next_arg) && (!argc || !((s) = argv[1]) || (--argc, ++argv, 0))) && (needs_arg) ? \
1266 	     rb_raise(rb_eRuntimeError, "missing argument for --" name) \
1267 	     : (void)0)
1268 #	define is_option_with_arg(name, allow_hyphen, allow_envopt)	\
1269 	    is_option_with_optarg(name, allow_hyphen, allow_envopt, Qtrue, Qtrue)
1270 #	define is_option_with_optarg(name, allow_hyphen, allow_envopt, needs_arg, next_arg) \
1271 	    (strncmp((name), s, n = sizeof(name) - 1) == 0 && is_option_end(s[n], (allow_hyphen)) ? \
1272 	     (check_envopt(name, (allow_envopt)), s += n, \
1273 	      need_argument(name, s, needs_arg, next_arg), 1) : 0)
1274 
1275 	    if (strcmp("copyright", s) == 0) {
1276 		if (envopt) goto noenvopt_long;
1277 		opt->dump |= DUMP_BIT(copyright);
1278 	    }
1279 	    else if (is_option_with_optarg("debug", Qtrue, Qtrue, Qfalse, Qfalse)) {
1280 		if (s && *s) {
1281 		    ruby_each_words(s, debug_option, &opt->features);
1282 		}
1283 		else {
1284 		    ruby_debug = Qtrue;
1285 		    ruby_verbose = Qtrue;
1286 		}
1287             }
1288 	    else if (is_option_with_arg("enable", Qtrue, Qtrue)) {
1289 		ruby_each_words(s, enable_option, &opt->features);
1290 	    }
1291 	    else if (is_option_with_arg("disable", Qtrue, Qtrue)) {
1292 		ruby_each_words(s, disable_option, &opt->features);
1293 	    }
1294 	    else if (is_option_with_arg("encoding", Qfalse, Qtrue)) {
1295 		char *p;
1296 	      encoding:
1297 		do {
1298 #	define set_encoding_part(type) \
1299 		    if (!(p = strchr(s, ':'))) { \
1300 			set_##type##_encoding_once(opt, s, 0); \
1301 			break; \
1302 		    } \
1303 		    else if (p > s) { \
1304 			set_##type##_encoding_once(opt, s, p-s); \
1305 		    }
1306 		    set_encoding_part(external);
1307 		    if (!*(s = ++p)) break;
1308 		    set_encoding_part(internal);
1309 		    if (!*(s = ++p)) break;
1310 #if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
1311 		    set_encoding_part(source);
1312 		    if (!*(s = ++p)) break;
1313 #endif
1314 		    rb_raise(rb_eRuntimeError, "extra argument for %s: %s",
1315 			     (arg[1] == '-' ? "--encoding" : "-E"), s);
1316 #	undef set_encoding_part
1317 		} while (0);
1318 	    }
1319 	    else if (is_option_with_arg("internal-encoding", Qfalse, Qtrue)) {
1320 		set_internal_encoding_once(opt, s, 0);
1321 	    }
1322 	    else if (is_option_with_arg("external-encoding", Qfalse, Qtrue)) {
1323 		set_external_encoding_once(opt, s, 0);
1324 	    }
1325 #if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
1326 	    else if (is_option_with_arg("source-encoding", Qfalse, Qtrue)) {
1327 		set_source_encoding_once(opt, s, 0);
1328 	    }
1329 #endif
1330 	    else if (strcmp("version", s) == 0) {
1331 		if (envopt) goto noenvopt_long;
1332 		opt->dump |= DUMP_BIT(version);
1333 	    }
1334 	    else if (strcmp("verbose", s) == 0) {
1335 		opt->verbose = 1;
1336 		ruby_verbose = Qtrue;
1337 	    }
1338             else if (strncmp("jit", s, 3) == 0) {
1339 #if USE_MJIT
1340                 opt->features |= FEATURE_BIT(jit);
1341                 setup_mjit_options(s + 3, &opt->mjit);
1342 #else
1343                 rb_warn("MJIT support is disabled.");
1344 #endif
1345             }
1346 	    else if (strcmp("yydebug", s) == 0) {
1347 		if (envopt) goto noenvopt_long;
1348 		opt->dump |= DUMP_BIT(yydebug);
1349 	    }
1350 	    else if (is_option_with_arg("dump", Qfalse, Qfalse)) {
1351 		ruby_each_words(s, dump_option, &opt->dump);
1352 	    }
1353 	    else if (strcmp("help", s) == 0) {
1354 		if (envopt) goto noenvopt_long;
1355 		opt->dump |= DUMP_BIT(help);
1356 		goto switch_end;
1357 	    }
1358 	    else {
1359 		rb_raise(rb_eRuntimeError,
1360 			 "invalid option --%s  (-h will show valid options)", s);
1361 	    }
1362 	    break;
1363 
1364 	  case '\r':
1365 	    if (!s[1])
1366 		break;
1367 
1368 	  default:
1369 	    {
1370 		if (ISPRINT(*s)) {
1371                     rb_raise(rb_eRuntimeError,
1372 			"invalid option -%c  (-h will show valid options)",
1373                         (int)(unsigned char)*s);
1374 		}
1375 		else {
1376                     rb_raise(rb_eRuntimeError,
1377 			"invalid option -\\x%02X  (-h will show valid options)",
1378                         (int)(unsigned char)*s);
1379 		}
1380 	    }
1381 	    goto switch_end;
1382 
1383 	  noenvopt:
1384 	    /* "EIdvwWrKU" only */
1385 	    rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: -%c", *s);
1386 	    break;
1387 
1388 	  noenvopt_long:
1389 	    rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --%s", s);
1390 	    break;
1391 
1392 	  case 0:
1393 	    break;
1394 #	undef is_option_end
1395 #	undef check_envopt
1396 #	undef need_argument
1397 #	undef is_option_with_arg
1398 #	undef is_option_with_optarg
1399 	}
1400     }
1401 
1402   switch_end:
1403     if (warning) opt->warning = warning;
1404     return argc0 - argc;
1405 }
1406 
1407 static void
ruby_init_prelude(void)1408 ruby_init_prelude(void)
1409 {
1410     Init_prelude();
1411     rb_const_remove(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX"));
1412 }
1413 
1414 static int
opt_enc_index(VALUE enc_name)1415 opt_enc_index(VALUE enc_name)
1416 {
1417     const char *s = RSTRING_PTR(enc_name);
1418     int i = rb_enc_find_index(s);
1419 
1420     if (i < 0) {
1421 	rb_raise(rb_eRuntimeError, "unknown encoding name - %s", s);
1422     }
1423     else if (rb_enc_dummy_p(rb_enc_from_index(i))) {
1424 	rb_raise(rb_eRuntimeError, "dummy encoding is not acceptable - %s ", s);
1425     }
1426     return i;
1427 }
1428 
1429 #define rb_progname      (GET_VM()->progname)
1430 #define rb_orig_progname (GET_VM()->orig_progname)
1431 VALUE rb_argv0;
1432 VALUE rb_e_script;
1433 
1434 static VALUE
false_value(void)1435 false_value(void)
1436 {
1437     return Qfalse;
1438 }
1439 
1440 static VALUE
true_value(void)1441 true_value(void)
1442 {
1443     return Qtrue;
1444 }
1445 
1446 #define rb_define_readonly_boolean(name, val) \
1447     rb_define_virtual_variable((name), (val) ? true_value : false_value, 0)
1448 
1449 static VALUE
uscore_get(void)1450 uscore_get(void)
1451 {
1452     VALUE line;
1453 
1454     line = rb_lastline_get();
1455     if (!RB_TYPE_P(line, T_STRING)) {
1456 	rb_raise(rb_eTypeError, "$_ value need to be String (%s given)",
1457 		 NIL_P(line) ? "nil" : rb_obj_classname(line));
1458     }
1459     return line;
1460 }
1461 
1462 /*
1463  *  call-seq:
1464  *     sub(pattern, replacement)   -> $_
1465  *     sub(pattern) {|...| block } -> $_
1466  *
1467  *  Equivalent to <code>$_.sub(<i>args</i>)</code>, except that
1468  *  <code>$_</code> will be updated if substitution occurs.
1469  *  Available only when -p/-n command line option specified.
1470  */
1471 
1472 static VALUE
rb_f_sub(int argc,VALUE * argv)1473 rb_f_sub(int argc, VALUE *argv)
1474 {
1475     VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("sub"), argc, argv);
1476     rb_lastline_set(str);
1477     return str;
1478 }
1479 
1480 /*
1481  *  call-seq:
1482  *     gsub(pattern, replacement)    -> $_
1483  *     gsub(pattern) {|...| block }  -> $_
1484  *
1485  *  Equivalent to <code>$_.gsub...</code>, except that <code>$_</code>
1486  *  will be updated if substitution occurs.
1487  *  Available only when -p/-n command line option specified.
1488  *
1489  */
1490 
1491 static VALUE
rb_f_gsub(int argc,VALUE * argv)1492 rb_f_gsub(int argc, VALUE *argv)
1493 {
1494     VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("gsub"), argc, argv);
1495     rb_lastline_set(str);
1496     return str;
1497 }
1498 
1499 /*
1500  *  call-seq:
1501  *     chop   -> $_
1502  *
1503  *  Equivalent to <code>($_.dup).chop!</code>, except <code>nil</code>
1504  *  is never returned. See <code>String#chop!</code>.
1505  *  Available only when -p/-n command line option specified.
1506  *
1507  */
1508 
1509 static VALUE
rb_f_chop(void)1510 rb_f_chop(void)
1511 {
1512     VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("chop"), 0, 0);
1513     rb_lastline_set(str);
1514     return str;
1515 }
1516 
1517 
1518 /*
1519  *  call-seq:
1520  *     chomp            -> $_
1521  *     chomp(string)    -> $_
1522  *
1523  *  Equivalent to <code>$_ = $_.chomp(<em>string</em>)</code>. See
1524  *  <code>String#chomp</code>.
1525  *  Available only when -p/-n command line option specified.
1526  *
1527  */
1528 
1529 static VALUE
rb_f_chomp(int argc,VALUE * argv)1530 rb_f_chomp(int argc, VALUE *argv)
1531 {
1532     VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("chomp"), argc, argv);
1533     rb_lastline_set(str);
1534     return str;
1535 }
1536 
1537 static VALUE
process_options(int argc,char ** argv,ruby_cmdline_options_t * opt)1538 process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
1539 {
1540     rb_ast_t *ast = 0;
1541     VALUE parser;
1542     VALUE script_name;
1543     const rb_iseq_t *iseq;
1544     rb_encoding *enc, *lenc;
1545 #if UTF8_PATH
1546     rb_encoding *uenc, *ienc = 0;
1547 #endif
1548     const char *s;
1549     char fbuf[MAXPATHLEN];
1550     int i = (int)proc_options(argc, argv, opt, 0);
1551     rb_binding_t *toplevel_binding;
1552     const struct rb_block *base_block;
1553     unsigned int dump = opt->dump & dump_exit_bits;
1554 
1555     if (opt->dump & (DUMP_BIT(usage)|DUMP_BIT(help))) {
1556 	const char *const progname =
1557 	    (argc > 0 && argv && argv[0] ? argv[0] :
1558 	     origarg.argc > 0 && origarg.argv && origarg.argv[0] ? origarg.argv[0] :
1559 	     ruby_engine);
1560 	usage(progname, (opt->dump & DUMP_BIT(help)));
1561 	return Qtrue;
1562     }
1563 
1564     argc -= i;
1565     argv += i;
1566 
1567     if ((opt->features & FEATURE_BIT(rubyopt)) &&
1568 	opt->safe_level == 0 && (s = getenv("RUBYOPT"))) {
1569 	VALUE src_enc_name = opt->src.enc.name;
1570 	VALUE ext_enc_name = opt->ext.enc.name;
1571 	VALUE int_enc_name = opt->intern.enc.name;
1572 
1573 	opt->src.enc.name = opt->ext.enc.name = opt->intern.enc.name = 0;
1574 	moreswitches(s, opt, 1);
1575 	if (src_enc_name)
1576 	    opt->src.enc.name = src_enc_name;
1577 	if (ext_enc_name)
1578 	    opt->ext.enc.name = ext_enc_name;
1579 	if (int_enc_name)
1580 	    opt->intern.enc.name = int_enc_name;
1581     }
1582 
1583     if (opt->src.enc.name)
1584 	rb_warning("-K is specified; it is for 1.8 compatibility and may cause odd behavior");
1585 
1586 #if USE_MJIT
1587     if (opt->features & FEATURE_BIT(jit)) {
1588         opt->mjit.on = TRUE; /* set mjit.on for ruby_show_version() API and check to call mjit_init() */
1589     }
1590 #endif
1591     if (opt->dump & (DUMP_BIT(version) | DUMP_BIT(version_v))) {
1592 #if USE_MJIT
1593         mjit_opts.on = opt->mjit.on; /* used by ruby_show_version(). mjit_init() still can't be called here. */
1594 #endif
1595 	ruby_show_version();
1596 	if (opt->dump & DUMP_BIT(version)) return Qtrue;
1597     }
1598     if (opt->dump & DUMP_BIT(copyright)) {
1599 	ruby_show_copyright();
1600 	return Qtrue;
1601     }
1602 
1603     if (!opt->e_script) {
1604 	if (argc <= 0) {	/* no more args */
1605 	    if (opt->verbose)
1606 		return Qtrue;
1607 	    opt->script = "-";
1608 	}
1609 	else {
1610 	    opt->script = argv[0];
1611 	    if (!opt->script || opt->script[0] == '\0') {
1612 		opt->script = "-";
1613 	    }
1614 	    else if (opt->do_search) {
1615 		char *path = getenv("RUBYPATH");
1616 
1617 		opt->script = 0;
1618 		if (path) {
1619 		    opt->script = dln_find_file_r(argv[0], path, fbuf, sizeof(fbuf));
1620 		}
1621 		if (!opt->script) {
1622 		    opt->script = dln_find_file_r(argv[0], getenv(PATH_ENV), fbuf, sizeof(fbuf));
1623 		}
1624 		if (!opt->script)
1625 		    opt->script = argv[0];
1626 	    }
1627 	    argc--;
1628 	    argv++;
1629 	}
1630 	if (opt->script[0] == '-' && !opt->script[1]) {
1631 	    forbid_setid("program input from stdin");
1632 	}
1633     }
1634 
1635     opt->script_name = rb_str_new_cstr(opt->script);
1636     opt->script = RSTRING_PTR(opt->script_name);
1637 
1638 #if _WIN32
1639     translit_char_bin(RSTRING_PTR(opt->script_name), '\\', '/');
1640 #elif defined DOSISH
1641     translit_char(RSTRING_PTR(opt->script_name), '\\', '/');
1642 #endif
1643 
1644     ruby_gc_set_params(opt->safe_level);
1645     ruby_init_loadpath_safe(opt->safe_level);
1646 
1647 #if USE_MJIT
1648     if (opt->mjit.on)
1649         /* Using TMP_RUBY_PREFIX created by ruby_init_loadpath_safe(). */
1650         mjit_init(&opt->mjit);
1651 #endif
1652 
1653     Init_ruby_description();
1654     Init_enc();
1655     lenc = rb_locale_encoding();
1656     rb_enc_associate(rb_progname, lenc);
1657     rb_obj_freeze(rb_progname);
1658     parser = rb_parser_new();
1659     if (opt->dump & DUMP_BIT(yydebug)) {
1660 	rb_parser_set_yydebug(parser, Qtrue);
1661     }
1662     if (opt->ext.enc.name != 0) {
1663 	opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
1664     }
1665     if (opt->intern.enc.name != 0) {
1666 	opt->intern.enc.index = opt_enc_index(opt->intern.enc.name);
1667     }
1668     if (opt->src.enc.name != 0) {
1669 	opt->src.enc.index = opt_enc_index(opt->src.enc.name);
1670 	src_encoding_index = opt->src.enc.index;
1671     }
1672     if (opt->ext.enc.index >= 0) {
1673 	enc = rb_enc_from_index(opt->ext.enc.index);
1674     }
1675     else {
1676 	enc = lenc;
1677     }
1678     rb_enc_set_default_external(rb_enc_from_encoding(enc));
1679     if (opt->intern.enc.index >= 0) {
1680 	enc = rb_enc_from_index(opt->intern.enc.index);
1681 	rb_enc_set_default_internal(rb_enc_from_encoding(enc));
1682 	opt->intern.enc.index = -1;
1683 #if UTF8_PATH
1684 	ienc = enc;
1685 #endif
1686     }
1687     script_name = opt->script_name;
1688     rb_enc_associate(opt->script_name,
1689 		     IF_UTF8_PATH(uenc = rb_utf8_encoding(), lenc));
1690 #if UTF8_PATH
1691     if (uenc != lenc) {
1692 	opt->script_name = str_conv_enc(opt->script_name, uenc, lenc);
1693 	opt->script = RSTRING_PTR(opt->script_name);
1694     }
1695 #endif
1696     rb_obj_freeze(opt->script_name);
1697     if (IF_UTF8_PATH(uenc != lenc, 1)) {
1698 	long i;
1699         rb_vm_t *vm = GET_VM();
1700         VALUE load_path = vm->load_path;
1701 	const ID id_initial_load_path_mark = INITIAL_LOAD_PATH_MARK;
1702         int modifiable = FALSE;
1703 
1704         rb_get_expanded_load_path();
1705 	for (i = 0; i < RARRAY_LEN(load_path); ++i) {
1706 	    VALUE path = RARRAY_AREF(load_path, i);
1707 	    int mark = rb_attr_get(path, id_initial_load_path_mark) == path;
1708 #if UTF8_PATH
1709 	    VALUE newpath = rb_str_conv_enc(path, uenc, lenc);
1710 	    if (newpath == path) continue;
1711 	    path = newpath;
1712 #else
1713 	    path = rb_enc_associate(rb_str_dup(path), lenc);
1714 #endif
1715 	    if (mark) rb_ivar_set(path, id_initial_load_path_mark, path);
1716             if (!modifiable) {
1717                 rb_ary_modify(load_path);
1718                 modifiable = TRUE;
1719             }
1720 	    RARRAY_ASET(load_path, i, path);
1721 	}
1722         if (modifiable) {
1723             rb_ary_replace(vm->load_path_snapshot, load_path);
1724         }
1725     }
1726     Init_ext();		/* load statically linked extensions before rubygems */
1727     if (opt->features & FEATURE_BIT(gems)) {
1728 	rb_define_module("Gem");
1729 	if (opt->features & FEATURE_BIT(did_you_mean)) {
1730 	    rb_define_module("DidYouMean");
1731 	}
1732     }
1733     ruby_init_prelude();
1734     if ((opt->features ^ DEFAULT_FEATURES) & COMPILATION_FEATURES) {
1735 	VALUE option = rb_hash_new();
1736 #define SET_COMPILE_OPTION(h, o, name) \
1737 	rb_hash_aset((h), ID2SYM(rb_intern_const(#name)),		\
1738 		     ((o)->features & FEATURE_BIT(name) ? Qtrue : Qfalse));
1739 	SET_COMPILE_OPTION(option, opt, frozen_string_literal);
1740 	SET_COMPILE_OPTION(option, opt, debug_frozen_string_literal);
1741 	rb_funcallv(rb_cISeq, rb_intern_const("compile_option="), 1, &option);
1742 #undef SET_COMPILE_OPTION
1743     }
1744     ruby_set_argv(argc, argv);
1745     process_sflag(&opt->sflag);
1746 
1747     GetBindingPtr(rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING")),
1748 		  toplevel_binding);
1749     /* need to acquire env from toplevel_binding each time, since it
1750      * may update after eval() */
1751 
1752     base_block = toplevel_context(toplevel_binding);
1753     rb_parser_set_context(parser, base_block, TRUE);
1754 
1755     if (opt->e_script) {
1756 	VALUE progname = rb_progname;
1757 	rb_encoding *eenc;
1758 	if (opt->src.enc.index >= 0) {
1759 	    eenc = rb_enc_from_index(opt->src.enc.index);
1760 	}
1761 	else {
1762 	    eenc = lenc;
1763 #if UTF8_PATH
1764 	    if (ienc) eenc = ienc;
1765 #endif
1766 	}
1767 #if UTF8_PATH
1768 	if (eenc != uenc) {
1769 	    opt->e_script = str_conv_enc(opt->e_script, uenc, eenc);
1770 	}
1771 #endif
1772 	rb_enc_associate(opt->e_script, eenc);
1773 	if (!(opt->dump & ~DUMP_BIT(version_v))) {
1774 	    ruby_set_script_name(opt->script_name);
1775 	    require_libraries(&opt->req_list);
1776 	}
1777         ruby_set_script_name(progname);
1778 	rb_parser_set_options(parser, opt->do_print, opt->do_loop,
1779 			      opt->do_line, opt->do_split);
1780 	ast = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
1781     }
1782     else {
1783 	VALUE f;
1784 	f = open_load_file(script_name, &opt->xflag);
1785 	ast = load_file(parser, opt->script_name, f, 1, opt);
1786     }
1787     ruby_set_script_name(opt->script_name);
1788     if (dump & DUMP_BIT(yydebug)) {
1789 	dump &= ~DUMP_BIT(yydebug);
1790 	if (!dump) return Qtrue;
1791     }
1792 
1793     if (opt->ext.enc.index >= 0) {
1794 	enc = rb_enc_from_index(opt->ext.enc.index);
1795     }
1796     else {
1797 	enc = lenc;
1798     }
1799     rb_enc_set_default_external(rb_enc_from_encoding(enc));
1800     if (opt->intern.enc.index >= 0) {
1801 	/* Set in the shebang line */
1802 	enc = rb_enc_from_index(opt->intern.enc.index);
1803 	rb_enc_set_default_internal(rb_enc_from_encoding(enc));
1804     }
1805     else if (!rb_default_internal_encoding())
1806 	/* Freeze default_internal */
1807 	rb_enc_set_default_internal(Qnil);
1808     rb_stdio_set_default_encoding();
1809 
1810     if (!ast->body.root) {
1811 	rb_ast_dispose(ast);
1812 	return Qfalse;
1813     }
1814 
1815     process_sflag(&opt->sflag);
1816     opt->xflag = 0;
1817 
1818     if (dump & DUMP_BIT(syntax)) {
1819 	printf("Syntax OK\n");
1820 	dump &= ~DUMP_BIT(syntax);
1821 	if (!dump) return Qtrue;
1822     }
1823 
1824     if (opt->do_loop) {
1825 	rb_define_global_function("sub", rb_f_sub, -1);
1826 	rb_define_global_function("gsub", rb_f_gsub, -1);
1827 	rb_define_global_function("chop", rb_f_chop, 0);
1828 	rb_define_global_function("chomp", rb_f_chomp, -1);
1829     }
1830 
1831     if (dump & (DUMP_BIT(parsetree)|DUMP_BIT(parsetree_with_comment))) {
1832 	rb_io_write(rb_stdout, rb_parser_dump_tree(ast->body.root, dump & DUMP_BIT(parsetree_with_comment)));
1833 	rb_io_flush(rb_stdout);
1834 	dump &= ~DUMP_BIT(parsetree)&~DUMP_BIT(parsetree_with_comment);
1835 	if (!dump) {
1836 	    rb_ast_dispose(ast);
1837 	    return Qtrue;
1838 	}
1839     }
1840 
1841     {
1842 	VALUE path = Qnil;
1843 	if (!opt->e_script && strcmp(opt->script, "-")) {
1844 	    path = rb_realpath_internal(Qnil, script_name, 1);
1845 #if UTF8_PATH
1846 	    if (uenc != lenc) {
1847 		path = str_conv_enc(path, uenc, lenc);
1848 	    }
1849 #endif
1850 	    if (!ENCODING_GET(path)) { /* ASCII-8BIT */
1851 		rb_enc_copy(path, opt->script_name);
1852 	    }
1853 	}
1854 	base_block = toplevel_context(toplevel_binding);
1855 	iseq = rb_iseq_new_main(&ast->body, opt->script_name, path, vm_block_iseq(base_block));
1856 	rb_ast_dispose(ast);
1857     }
1858 
1859     if (dump & DUMP_BIT(insns)) {
1860 	rb_io_write(rb_stdout, rb_iseq_disasm((const rb_iseq_t *)iseq));
1861 	rb_io_flush(rb_stdout);
1862 	dump &= ~DUMP_BIT(insns);
1863 	if (!dump) return Qtrue;
1864     }
1865     if (opt->dump & dump_exit_bits) return Qtrue;
1866 
1867     rb_define_readonly_boolean("$-p", opt->do_print);
1868     rb_define_readonly_boolean("$-l", opt->do_line);
1869     rb_define_readonly_boolean("$-a", opt->do_split);
1870 
1871     if ((rb_e_script = opt->e_script) != 0) {
1872         rb_gc_register_mark_object(opt->e_script);
1873     }
1874 
1875     rb_set_safe_level(opt->safe_level);
1876 
1877     {
1878         rb_execution_context_t *ec = GET_EC();
1879 
1880         if (opt->e_script) {
1881             /* -e */
1882             rb_exec_event_hook_script_compiled(ec, iseq, opt->e_script);
1883         }
1884         else {
1885             /* file */
1886             rb_exec_event_hook_script_compiled(ec, iseq, Qnil);
1887         }
1888     }
1889     return (VALUE)iseq;
1890 }
1891 
1892 #ifndef DOSISH
1893 static void
warn_cr_in_shebang(const char * str,long len)1894 warn_cr_in_shebang(const char *str, long len)
1895 {
1896     if (str[len-1] == '\n' && str[len-2] == '\r') {
1897 	rb_warn("shebang line ending with \\r may cause problems");
1898     }
1899 }
1900 #else
1901 #define warn_cr_in_shebang(str, len) (void)0
1902 #endif
1903 
1904 struct load_file_arg {
1905     VALUE parser;
1906     VALUE fname;
1907     int script;
1908     ruby_cmdline_options_t *opt;
1909     VALUE f;
1910 };
1911 
1912 static VALUE
load_file_internal(VALUE argp_v)1913 load_file_internal(VALUE argp_v)
1914 {
1915     struct load_file_arg *argp = (struct load_file_arg *)argp_v;
1916     VALUE parser = argp->parser;
1917     VALUE orig_fname = argp->fname;
1918     int script = argp->script;
1919     ruby_cmdline_options_t *opt = argp->opt;
1920     VALUE f = argp->f;
1921     int line_start = 1;
1922     rb_ast_t *ast = 0;
1923     rb_encoding *enc;
1924     ID set_encoding;
1925 
1926     CONST_ID(set_encoding, "set_encoding");
1927     if (script) {
1928 	VALUE c = 1;		/* something not nil */
1929 	VALUE line;
1930 	char *p, *str;
1931 	long len;
1932 	int no_src_enc = !opt->src.enc.name;
1933 	int no_ext_enc = !opt->ext.enc.name;
1934 	int no_int_enc = !opt->intern.enc.name;
1935 
1936 	enc = rb_ascii8bit_encoding();
1937 	rb_funcall(f, set_encoding, 1, rb_enc_from_encoding(enc));
1938 
1939 	if (opt->xflag) {
1940 	    line_start--;
1941 	  search_shebang:
1942 	    while (!NIL_P(line = rb_io_gets(f))) {
1943 		line_start++;
1944 		RSTRING_GETMEM(line, str, len);
1945 		if (len > 2 && str[0] == '#' && str[1] == '!') {
1946 		    if (line_start == 1) warn_cr_in_shebang(str, len);
1947 		    if ((p = strstr(str+2, ruby_engine)) != 0) {
1948 			goto start_read;
1949 		    }
1950 		}
1951 	    }
1952 	    rb_loaderror("no Ruby script found in input");
1953 	}
1954 
1955 	c = rb_io_getbyte(f);
1956 	if (c == INT2FIX('#')) {
1957 	    c = rb_io_getbyte(f);
1958             if (c == INT2FIX('!') && !NIL_P(line = rb_io_gets(f))) {
1959 		RSTRING_GETMEM(line, str, len);
1960 		warn_cr_in_shebang(str, len);
1961 		if ((p = strstr(str, ruby_engine)) == 0) {
1962 		    /* not ruby script, assume -x flag */
1963 		    goto search_shebang;
1964 		}
1965 
1966 	      start_read:
1967 		str += len - 1;
1968 		if (*str == '\n') *str-- = '\0';
1969 		if (*str == '\r') *str-- = '\0';
1970 		/* ruby_engine should not contain a space */
1971 		if ((p = strstr(p, " -")) != 0) {
1972 		    opt->warning = 0;
1973 		    moreswitches(p + 1, opt, 0);
1974 		}
1975 
1976 		/* push back shebang for pragma may exist in next line */
1977 		rb_io_ungetbyte(f, rb_str_new2("!\n"));
1978 	    }
1979 	    else if (!NIL_P(c)) {
1980 		rb_io_ungetbyte(f, c);
1981 	    }
1982 	    rb_io_ungetbyte(f, INT2FIX('#'));
1983 	    if (no_src_enc && opt->src.enc.name) {
1984 		opt->src.enc.index = opt_enc_index(opt->src.enc.name);
1985 		src_encoding_index = opt->src.enc.index;
1986 	    }
1987 	    if (no_ext_enc && opt->ext.enc.name) {
1988 		opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
1989 	    }
1990 	    if (no_int_enc && opt->intern.enc.name) {
1991 		opt->intern.enc.index = opt_enc_index(opt->intern.enc.name);
1992 	    }
1993 	}
1994 	else if (!NIL_P(c)) {
1995 	    rb_io_ungetbyte(f, c);
1996 	}
1997 	else {
1998 	    argp->f = f = Qnil;
1999 	}
2000 	if (!(opt->dump & ~DUMP_BIT(version_v))) {
2001 	    ruby_set_script_name(opt->script_name);
2002 	    require_libraries(&opt->req_list);	/* Why here? unnatural */
2003 	}
2004     }
2005     if (opt->src.enc.index >= 0) {
2006 	enc = rb_enc_from_index(opt->src.enc.index);
2007     }
2008     else if (f == rb_stdin) {
2009 	enc = rb_locale_encoding();
2010     }
2011     else {
2012 	enc = rb_utf8_encoding();
2013     }
2014     rb_parser_set_options(parser, opt->do_print, opt->do_loop,
2015 			  opt->do_line, opt->do_split);
2016     if (NIL_P(f)) {
2017 	f = rb_str_new(0, 0);
2018 	rb_enc_associate(f, enc);
2019 	return (VALUE)rb_parser_compile_string_path(parser, orig_fname, f, line_start);
2020     }
2021     rb_funcall(f, set_encoding, 2, rb_enc_from_encoding(enc), rb_str_new_cstr("-"));
2022     ast = rb_parser_compile_file_path(parser, orig_fname, f, line_start);
2023     rb_funcall(f, set_encoding, 1, rb_parser_encoding(parser));
2024     if (script && rb_parser_end_seen_p(parser)) {
2025 	/*
2026 	 * DATA is a File that contains the data section of the executed file.
2027 	 * To create a data section use <tt>__END__</tt>:
2028 	 *
2029 	 *   $ cat t.rb
2030 	 *   puts DATA.gets
2031 	 *   __END__
2032 	 *   hello world!
2033 	 *
2034 	 *   $ ruby t.rb
2035 	 *   hello world!
2036 	 */
2037 	rb_define_global_const("DATA", f);
2038 	argp->f = Qnil;
2039     }
2040     return (VALUE)ast;
2041 }
2042 
2043 static VALUE
open_load_file(VALUE fname_v,int * xflag)2044 open_load_file(VALUE fname_v, int *xflag)
2045 {
2046     const char *fname = (fname_v = rb_str_encode_ospath(fname_v),
2047 			 StringValueCStr(fname_v));
2048     long flen = RSTRING_LEN(fname_v);
2049     VALUE f;
2050     int e;
2051 
2052     if (flen == 1 && fname[0] == '-') {
2053 	f = rb_stdin;
2054     }
2055     else {
2056 	int fd;
2057 	/* open(2) may block if fname is point to FIFO and it's empty. Let's
2058 	   use O_NONBLOCK. */
2059 #if defined O_NONBLOCK && HAVE_FCNTL && !(O_NONBLOCK & O_ACCMODE)
2060 	/* TODO: fix conflicting O_NONBLOCK in ruby/win32.h */
2061 # define MODE_TO_LOAD (O_RDONLY | O_NONBLOCK)
2062 #elif defined O_NDELAY && HAVE_FCNTL && !(O_NDELAY & O_ACCMODE)
2063 # define MODE_TO_LOAD (O_RDONLY | O_NDELAY)
2064 #else
2065 # define MODE_TO_LOAD (O_RDONLY)
2066 #endif
2067 	int mode = MODE_TO_LOAD;
2068 #if defined DOSISH || defined __CYGWIN__
2069 # define isdirsep(x) ((x) == '/' || (x) == '\\')
2070 	{
2071 	    static const char exeext[] = ".exe";
2072 	    enum {extlen = sizeof(exeext)-1};
2073 	    if (flen > extlen && !isdirsep(fname[flen-extlen-1]) &&
2074 		STRNCASECMP(fname+flen-extlen, exeext, extlen) == 0) {
2075 		mode |= O_BINARY;
2076 		*xflag = 1;
2077 	    }
2078 	}
2079 #endif
2080 
2081 	if ((fd = rb_cloexec_open(fname, mode, 0)) < 0) {
2082 	    e = errno;
2083 	    if (!rb_gc_for_fd(e)) {
2084 		rb_load_fail(fname_v, strerror(e));
2085 	    }
2086 	    if ((fd = rb_cloexec_open(fname, mode, 0)) < 0) {
2087 		rb_load_fail(fname_v, strerror(errno));
2088 	    }
2089 	}
2090 	rb_update_max_fd(fd);
2091 
2092 #if defined HAVE_FCNTL && MODE_TO_LOAD != O_RDONLY
2093 	/* disabling O_NONBLOCK */
2094 	if (fcntl(fd, F_SETFL, 0) < 0) {
2095 	    e = errno;
2096 	    (void)close(fd);
2097 	    rb_load_fail(fname_v, strerror(e));
2098 	}
2099 #endif
2100 
2101 	e = ruby_is_fd_loadable(fd);
2102 	if (!e) {
2103 	    e = errno;
2104 	    (void)close(fd);
2105 	    rb_load_fail(fname_v, strerror(e));
2106 	}
2107 
2108 	f = rb_io_fdopen(fd, mode, fname);
2109 	if (e < 0) {
2110 	    /*
2111 	      We need to wait if FIFO is empty. It's FIFO's semantics.
2112 	      rb_thread_wait_fd() release GVL. So, it's safe.
2113 	    */
2114 	    rb_thread_wait_fd(fd);
2115 	}
2116     }
2117     return f;
2118 }
2119 
2120 static VALUE
restore_load_file(VALUE arg)2121 restore_load_file(VALUE arg)
2122 {
2123     struct load_file_arg *argp = (struct load_file_arg *)arg;
2124     VALUE f = argp->f;
2125 
2126     if (!NIL_P(f) && f != rb_stdin) {
2127 	rb_io_close(f);
2128     }
2129     return Qnil;
2130 }
2131 
2132 static rb_ast_t *
load_file(VALUE parser,VALUE fname,VALUE f,int script,ruby_cmdline_options_t * opt)2133 load_file(VALUE parser, VALUE fname, VALUE f, int script, ruby_cmdline_options_t *opt)
2134 {
2135     struct load_file_arg arg;
2136     arg.parser = parser;
2137     arg.fname = fname;
2138     arg.script = script;
2139     arg.opt = opt;
2140     arg.f = f;
2141     return (rb_ast_t *)rb_ensure(load_file_internal, (VALUE)&arg,
2142 			      restore_load_file, (VALUE)&arg);
2143 }
2144 
2145 void *
rb_load_file(const char * fname)2146 rb_load_file(const char *fname)
2147 {
2148     VALUE fname_v = rb_str_new_cstr(fname);
2149     return rb_load_file_str(fname_v);
2150 }
2151 
2152 void *
rb_load_file_str(VALUE fname_v)2153 rb_load_file_str(VALUE fname_v)
2154 {
2155     return rb_parser_load_file(rb_parser_new(), fname_v);
2156 }
2157 
2158 void *
rb_parser_load_file(VALUE parser,VALUE fname_v)2159 rb_parser_load_file(VALUE parser, VALUE fname_v)
2160 {
2161     ruby_cmdline_options_t opt;
2162     VALUE f = open_load_file(fname_v, &cmdline_options_init(&opt)->xflag);
2163     return load_file(parser, fname_v, f, 0, &opt);
2164 }
2165 
2166 /*
2167  *  call-seq:
2168  *     Process.argv0  -> frozen_string
2169  *
2170  *  Returns the name of the script being executed.  The value is not
2171  *  affected by assigning a new value to $0.
2172  *
2173  *  This method first appeared in Ruby 2.1 to serve as a global
2174  *  variable free means to get the script name.
2175  */
2176 
2177 static VALUE
proc_argv0(VALUE process)2178 proc_argv0(VALUE process)
2179 {
2180     return rb_orig_progname;
2181 }
2182 
2183 static VALUE ruby_setproctitle(VALUE title);
2184 
2185 /*
2186  *  call-seq:
2187  *     Process.setproctitle(string)  -> string
2188  *
2189  *  Sets the process title that appears on the ps(1) command.  Not
2190  *  necessarily effective on all platforms.  No exception will be
2191  *  raised regardless of the result, nor will NotImplementedError be
2192  *  raised even if the platform does not support the feature.
2193  *
2194  *  Calling this method does not affect the value of $0.
2195  *
2196  *     Process.setproctitle('myapp: worker #%d' % worker_id)
2197  *
2198  *  This method first appeared in Ruby 2.1 to serve as a global
2199  *  variable free means to change the process title.
2200  */
2201 
2202 static VALUE
proc_setproctitle(VALUE process,VALUE title)2203 proc_setproctitle(VALUE process, VALUE title)
2204 {
2205     return ruby_setproctitle(title);
2206 }
2207 
2208 static VALUE
ruby_setproctitle(VALUE title)2209 ruby_setproctitle(VALUE title)
2210 {
2211     const char *ptr = StringValueCStr(title);
2212     setproctitle("%.*s", RSTRING_LENINT(title), ptr);
2213     return title;
2214 }
2215 
2216 static void
set_arg0(VALUE val,ID id)2217 set_arg0(VALUE val, ID id)
2218 {
2219     if (origarg.argv == 0)
2220 	rb_raise(rb_eRuntimeError, "$0 not initialized");
2221 
2222     rb_progname = rb_str_new_frozen(ruby_setproctitle(val));
2223 }
2224 
2225 static inline VALUE
external_str_new_cstr(const char * p)2226 external_str_new_cstr(const char *p)
2227 {
2228 #if UTF8_PATH
2229     VALUE str = rb_utf8_str_new_cstr(p);
2230     str = str_conv_enc(str, NULL, rb_default_external_encoding());
2231     OBJ_TAINT_RAW(str);
2232     return str;
2233 #else
2234     return rb_external_str_new_cstr(p);
2235 #endif
2236 }
2237 
2238 /*! Sets the current script name to this value.
2239  *
2240  * This is similar to <code>$0 = name</code> in Ruby level but also affects
2241  * <code>Method#location</code> and others.
2242  */
2243 void
ruby_script(const char * name)2244 ruby_script(const char *name)
2245 {
2246     if (name) {
2247 	rb_orig_progname = rb_progname = external_str_new_cstr(name);
2248 	rb_vm_set_progname(rb_progname);
2249     }
2250 }
2251 
2252 /*! Sets the current script name to this value.
2253  *
2254  * Same as ruby_script() but accepts a VALUE.
2255  */
2256 void
ruby_set_script_name(VALUE name)2257 ruby_set_script_name(VALUE name)
2258 {
2259     rb_orig_progname = rb_progname = rb_str_dup(name);
2260     rb_vm_set_progname(rb_progname);
2261 }
2262 
2263 static void
init_ids(ruby_cmdline_options_t * opt)2264 init_ids(ruby_cmdline_options_t *opt)
2265 {
2266     rb_uid_t uid = getuid();
2267     rb_uid_t euid = geteuid();
2268     rb_gid_t gid = getgid();
2269     rb_gid_t egid = getegid();
2270 
2271     if (uid != euid) opt->setids |= 1;
2272     if (egid != gid) opt->setids |= 2;
2273     if (uid && opt->setids) {
2274 	if (opt->safe_level < 1) opt->safe_level = 1;
2275     }
2276 }
2277 
2278 #undef forbid_setid
2279 static void
forbid_setid(const char * s,const ruby_cmdline_options_t * opt)2280 forbid_setid(const char *s, const ruby_cmdline_options_t *opt)
2281 {
2282     if (opt->setids & 1)
2283         rb_raise(rb_eSecurityError, "no %s allowed while running setuid", s);
2284     if (opt->setids & 2)
2285         rb_raise(rb_eSecurityError, "no %s allowed while running setgid", s);
2286     if (opt->safe_level > 0)
2287         rb_raise(rb_eSecurityError, "no %s allowed in tainted mode", s);
2288 }
2289 
2290 static void
verbose_setter(VALUE val,ID id,void * data)2291 verbose_setter(VALUE val, ID id, void *data)
2292 {
2293     VALUE *variable = data;
2294     *variable = RTEST(val) ? Qtrue : val;
2295 }
2296 
2297 static VALUE
opt_W_getter(ID id,void * data)2298 opt_W_getter(ID id, void *data)
2299 {
2300     VALUE *variable = data;
2301     switch (*variable) {
2302       case Qnil:
2303 	return INT2FIX(0);
2304       case Qfalse:
2305 	return INT2FIX(1);
2306       case Qtrue:
2307 	return INT2FIX(2);
2308       default:
2309 	return Qnil;
2310     }
2311 }
2312 
2313 /*! Defines built-in variables */
2314 void
ruby_prog_init(void)2315 ruby_prog_init(void)
2316 {
2317     rb_define_hooked_variable("$VERBOSE", &ruby_verbose, 0, verbose_setter);
2318     rb_define_hooked_variable("$-v", &ruby_verbose, 0, verbose_setter);
2319     rb_define_hooked_variable("$-w", &ruby_verbose, 0, verbose_setter);
2320     rb_define_hooked_variable("$-W", &ruby_verbose, opt_W_getter, rb_gvar_readonly_setter);
2321     rb_define_variable("$DEBUG", &ruby_debug);
2322     rb_define_variable("$-d", &ruby_debug);
2323 
2324     rb_define_hooked_variable("$0", &rb_progname, 0, set_arg0);
2325     rb_define_hooked_variable("$PROGRAM_NAME", &rb_progname, 0, set_arg0);
2326 
2327     rb_define_module_function(rb_mProcess, "argv0", proc_argv0, 0);
2328     rb_define_module_function(rb_mProcess, "setproctitle", proc_setproctitle, 1);
2329 
2330     /*
2331      * ARGV contains the command line arguments used to run ruby.
2332      *
2333      * A library like OptionParser can be used to process command-line
2334      * arguments.
2335      */
2336     rb_define_global_const("ARGV", rb_argv);
2337 }
2338 
2339 void
ruby_set_argv(int argc,char ** argv)2340 ruby_set_argv(int argc, char **argv)
2341 {
2342     int i;
2343     VALUE av = rb_argv;
2344 
2345 #if defined(USE_DLN_A_OUT)
2346     if (origarg.argc > 0 && origarg.argv)
2347 	dln_argv0 = origarg.argv[0];
2348     else if (argc > 0 && argv)
2349 	dln_argv0 = argv[0];
2350 #endif
2351     rb_ary_clear(av);
2352     for (i = 0; i < argc; i++) {
2353 	VALUE arg = external_str_new_cstr(argv[i]);
2354 
2355 	OBJ_FREEZE(arg);
2356 	rb_ary_push(av, arg);
2357     }
2358 }
2359 
2360 void *
ruby_process_options(int argc,char ** argv)2361 ruby_process_options(int argc, char **argv)
2362 {
2363     ruby_cmdline_options_t opt;
2364     VALUE iseq;
2365     const char *script_name = (argc > 0 && argv[0]) ? argv[0] : ruby_engine;
2366 
2367     if (!origarg.argv || origarg.argc <= 0) {
2368 	origarg.argc = argc;
2369 	origarg.argv = argv;
2370     }
2371     ruby_script(script_name);  /* for the time being */
2372     rb_argv0 = rb_str_new4(rb_progname);
2373     rb_gc_register_mark_object(rb_argv0);
2374     iseq = process_options(argc, argv, cmdline_options_init(&opt));
2375 
2376 #ifndef HAVE_SETPROCTITLE
2377     ruby_init_setproctitle(argc, argv);
2378 #endif
2379 
2380     return (void*)(struct RData*)iseq;
2381 }
2382 
2383 static void
fill_standard_fds(void)2384 fill_standard_fds(void)
2385 {
2386     int f0, f1, f2, fds[2];
2387     struct stat buf;
2388     f0 = fstat(0, &buf) == -1 && errno == EBADF;
2389     f1 = fstat(1, &buf) == -1 && errno == EBADF;
2390     f2 = fstat(2, &buf) == -1 && errno == EBADF;
2391     if (f0) {
2392         if (pipe(fds) == 0) {
2393             close(fds[1]);
2394             if (fds[0] != 0) {
2395                 dup2(fds[0], 0);
2396                 close(fds[0]);
2397             }
2398         }
2399     }
2400     if (f1 || f2) {
2401         if (pipe(fds) == 0) {
2402             close(fds[0]);
2403             if (f1 && fds[1] != 1)
2404                 dup2(fds[1], 1);
2405             if (f2 && fds[1] != 2)
2406                 dup2(fds[1], 2);
2407             if (fds[1] != 1 && fds[1] != 2)
2408                 close(fds[1]);
2409         }
2410     }
2411 }
2412 
2413 /*! Initializes the process for libruby.
2414  *
2415  * This function assumes this process is ruby(1) and it has just started.
2416  * Usually programs that embed CRuby interpreter may not call this function,
2417  * and may do their own initialization.
2418  * argc and argv cannot be NULL.
2419  */
2420 void
ruby_sysinit(int * argc,char *** argv)2421 ruby_sysinit(int *argc, char ***argv)
2422 {
2423 #if defined(_WIN32)
2424     rb_w32_sysinit(argc, argv);
2425 #endif
2426     if (*argc >= 0 && *argv) {
2427 	origarg.argc = *argc;
2428 	origarg.argv = *argv;
2429 #if defined(USE_DLN_A_OUT)
2430 	dln_argv0 = origarg.argv[0];
2431 #endif
2432     }
2433     fill_standard_fds();
2434 }
2435