1/**********************************************************************
2
3  ruby.c -
4
5  $Author: kazu $
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/ruby.h"
19#include "ruby/encoding.h"
20#include "internal.h"
21#include "eval_intern.h"
22#include "dln.h"
23#include <stdio.h>
24#include <sys/types.h>
25#include <ctype.h>
26
27#ifdef __hpux
28#include <sys/pstat.h>
29#endif
30#if defined(LOAD_RELATIVE) && defined(HAVE_DLADDR)
31#include <dlfcn.h>
32#endif
33
34#ifdef HAVE_UNISTD_H
35#include <unistd.h>
36#endif
37#if defined(HAVE_FCNTL_H)
38#include <fcntl.h>
39#elif defined(HAVE_SYS_FCNTL_H)
40#include <sys/fcntl.h>
41#endif
42#ifdef HAVE_SYS_PARAM_H
43# include <sys/param.h>
44#endif
45#ifndef MAXPATHLEN
46# define MAXPATHLEN 1024
47#endif
48
49#include "ruby/util.h"
50
51#ifndef HAVE_STDLIB_H
52char *getenv();
53#endif
54
55#define numberof(array) (int)(sizeof(array) / sizeof((array)[0]))
56
57#if defined DISABLE_RUBYGEMS && DISABLE_RUBYGEMS
58#define DEFAULT_RUBYGEMS_ENABLED "disabled"
59#else
60#define DEFAULT_RUBYGEMS_ENABLED "enabled"
61#endif
62
63#define DISABLE_BIT(bit) (1U << disable_##bit)
64enum disable_flag_bits {
65    disable_gems,
66    disable_rubyopt,
67    disable_flag_count
68};
69
70#define DUMP_BIT(bit) (1U << dump_##bit)
71enum dump_flag_bits {
72    dump_version,
73    dump_version_v,
74    dump_copyright,
75    dump_usage,
76    dump_help,
77    dump_yydebug,
78    dump_syntax,
79    dump_parsetree,
80    dump_parsetree_with_comment,
81    dump_insns,
82    dump_flag_count
83};
84
85struct cmdline_options {
86    int sflag, xflag;
87    int do_loop, do_print;
88    int do_line, do_split;
89    int do_search;
90    unsigned int disable;
91    int verbose;
92    int safe_level;
93    unsigned int setids;
94    unsigned int dump;
95    const char *script;
96    VALUE script_name;
97    VALUE e_script;
98    struct {
99	struct {
100	    VALUE name;
101	    int index;
102	} enc;
103    } src, ext, intern;
104    VALUE req_list;
105};
106
107static void init_ids(struct cmdline_options *);
108
109#define src_encoding_index GET_VM()->src_encoding_index
110
111static struct cmdline_options *
112cmdline_options_init(struct cmdline_options *opt)
113{
114    MEMZERO(opt, *opt, 1);
115    init_ids(opt);
116    opt->src.enc.index = src_encoding_index;
117    opt->ext.enc.index = -1;
118    opt->intern.enc.index = -1;
119#if defined DISABLE_RUBYGEMS && DISABLE_RUBYGEMS
120    opt->disable |= DISABLE_BIT(gems);
121#endif
122    return opt;
123}
124
125static NODE *load_file(VALUE, VALUE, int, struct cmdline_options *);
126static void forbid_setid(const char *, struct cmdline_options *);
127#define forbid_setid(s) forbid_setid((s), opt)
128
129static struct {
130    int argc;
131    char **argv;
132} origarg;
133
134static void
135usage(const char *name, int help)
136{
137    /* This message really ought to be max 23 lines.
138     * Removed -h because the user already knows that option. Others? */
139
140    struct message {
141	const char *str;
142	unsigned short namelen, secondlen;
143    };
144#define M(shortopt, longopt, desc) { \
145    shortopt " " longopt " " desc, \
146    (unsigned short)sizeof(shortopt), \
147    (unsigned short)sizeof(longopt), \
148}
149    static const struct message usage_msg[] = {
150	M("-0[octal]",	   "",			   "specify record separator (\\0, if no argument)"),
151	M("-a",		   "",			   "autosplit mode with -n or -p (splits $_ into $F)"),
152	M("-c",		   "",			   "check syntax only"),
153	M("-Cdirectory",   "",			   "cd to directory before executing your script"),
154	M("-d",		   ", --debug",		   "set debugging flags (set $DEBUG to true)"),
155	M("-e 'command'",  "",			   "one line of script. Several -e's allowed. Omit [programfile]"),
156	M("-Eex[:in]",     ", --encoding=ex[:in]", "specify the default external and internal character encodings"),
157	M("-Fpattern",	   "",			   "split() pattern for autosplit (-a)"),
158	M("-i[extension]", "",			   "edit ARGV files in place (make backup if extension supplied)"),
159	M("-Idirectory",   "",			   "specify $LOAD_PATH directory (may be used more than once)"),
160	M("-l",		   "",			   "enable line ending processing"),
161	M("-n",		   "",			   "assume 'while gets(); ... end' loop around your script"),
162	M("-p",		   "",			   "assume loop like -n but print line also like sed"),
163	M("-rlibrary",	   "",			   "require the library before executing your script"),
164	M("-s",		   "",			   "enable some switch parsing for switches after script name"),
165	M("-S",		   "",			   "look for the script using PATH environment variable"),
166	M("-T[level=1]",   "",			   "turn on tainting checks"),
167	M("-v",		   ", --verbose",	   "print version number, then turn on verbose mode"),
168	M("-w",		   "",			   "turn warnings on for your script"),
169	M("-W[level=2]",   "",			   "set warning level; 0=silence, 1=medium, 2=verbose"),
170	M("-x[directory]", "",			   "strip off text before #!ruby line and perhaps cd to directory"),
171	M("-h",		   "",			   "show this message, --help for more info"),
172    };
173    static const struct message help_msg[] = {
174	M("--copyright",                   "", "print the copyright"),
175	M("--enable=feature[,...]",	   ", --disable=feature[,...]",
176	  "enable or disable features"),
177	M("--external-encoding=encoding",  ", --internal-encoding=encoding",
178	  "specify the default external or internal character encoding"),
179	M("--version",                     "", "print the version"),
180	M("--help",			   "", "show this message, -h for short message"),
181    };
182    static const struct message features[] = {
183	M("gems",    "",        "rubygems (default: "DEFAULT_RUBYGEMS_ENABLED")"),
184	M("rubyopt", "",        "RUBYOPT environment variable (default: enabled)"),
185    };
186    int i, w = 16, num = numberof(usage_msg) - (help ? 1 : 0);
187#define SHOW(m) do { \
188	int wrap = help && (m).namelen + (m).secondlen - 2 > w; \
189	printf("  %.*s%-*.*s%-*s%s\n", (m).namelen-1, (m).str, \
190	       (wrap ? 0 : w - (m).namelen + 1), \
191	       (help ? (m).secondlen-1 : 0), (m).str + (m).namelen, \
192	       (wrap ? w + 3 : 0), (wrap ? "\n" : ""), \
193	       (m).str + (m).namelen + (m).secondlen); \
194    } while (0)
195
196    printf("Usage: %s [switches] [--] [programfile] [arguments]\n", name);
197    for (i = 0; i < num; ++i)
198	SHOW(usage_msg[i]);
199
200    if (!help) return;
201
202    for (i = 0; i < numberof(help_msg); ++i)
203	SHOW(help_msg[i]);
204    puts("Features:");
205    for (i = 0; i < numberof(features); ++i)
206	SHOW(features[i]);
207}
208
209#ifdef MANGLED_PATH
210static VALUE
211rubylib_mangled_path(const char *s, unsigned int l)
212{
213    static char *newp, *oldp;
214    static int newl, oldl, notfound;
215    char *ptr;
216    VALUE ret;
217
218    if (!newp && !notfound) {
219	newp = getenv("RUBYLIB_PREFIX");
220	if (newp) {
221	    oldp = newp = strdup(newp);
222	    while (*newp && !ISSPACE(*newp) && *newp != ';') {
223		newp = CharNext(newp);	/* Skip digits. */
224	    }
225	    oldl = newp - oldp;
226	    while (*newp && (ISSPACE(*newp) || *newp == ';')) {
227		newp = CharNext(newp);	/* Skip whitespace. */
228	    }
229	    newl = strlen(newp);
230	    if (newl == 0 || oldl == 0) {
231		rb_fatal("malformed RUBYLIB_PREFIX");
232	    }
233	    translit_char(newp, '\\', '/');
234	}
235	else {
236	    notfound = 1;
237	}
238    }
239    if (!newp || l < oldl || STRNCASECMP(oldp, s, oldl) != 0) {
240	return rb_str_new(s, l);
241    }
242    ret = rb_str_new(0, l + newl - oldl);
243    ptr = RSTRING_PTR(ret);
244    memcpy(ptr, newp, newl);
245    memcpy(ptr + newl, s + oldl, l - oldl);
246    ptr[l + newl - oldl] = 0;
247    return ret;
248}
249#else
250#define rubylib_mangled_path rb_str_new
251#endif
252
253static void
254push_include(const char *path, VALUE (*filter)(VALUE))
255{
256    const char sep = PATH_SEP_CHAR;
257    const char *p, *s;
258    VALUE load_path = GET_VM()->load_path;
259
260    p = path;
261    while (*p) {
262	while (*p == sep)
263	    p++;
264	if (!*p) break;
265	for (s = p; *s && *s != sep; s = CharNext(s));
266	rb_ary_push(load_path, (*filter)(rubylib_mangled_path(p, s - p)));
267	p = s;
268    }
269}
270
271#ifdef __CYGWIN__
272static void
273push_include_cygwin(const char *path, VALUE (*filter)(VALUE))
274{
275    const char *p, *s;
276    char rubylib[FILENAME_MAX];
277    VALUE buf = 0;
278
279    p = path;
280    while (*p) {
281	unsigned int len;
282	while (*p == ';')
283	    p++;
284	if (!*p) break;
285	for (s = p; *s && *s != ';'; s = CharNext(s));
286	len = s - p;
287	if (*s) {
288	    if (!buf) {
289		buf = rb_str_new(p, len);
290		p = RSTRING_PTR(buf);
291	    }
292	    else {
293		rb_str_resize(buf, len);
294		p = strncpy(RSTRING_PTR(buf), p, len);
295	    }
296	}
297#ifdef HAVE_CYGWIN_CONV_PATH
298#define CONV_TO_POSIX_PATH(p, lib) \
299	cygwin_conv_path(CCP_WIN_A_TO_POSIX|CCP_RELATIVE, (p), (lib), sizeof(lib))
300#else
301#define CONV_TO_POSIX_PATH(p, lib) \
302	cygwin_conv_to_posix_path((p), (lib))
303#endif
304	if (CONV_TO_POSIX_PATH(p, rubylib) == 0)
305	    p = rubylib;
306	push_include(p, filter);
307	if (!*s) break;
308	p = s + 1;
309    }
310}
311
312#define push_include push_include_cygwin
313#endif
314
315void
316ruby_push_include(const char *path, VALUE (*filter)(VALUE))
317{
318    if (path == 0)
319	return;
320    push_include(path, filter);
321}
322
323static VALUE
324identical_path(VALUE path)
325{
326    return path;
327}
328static VALUE
329locale_path(VALUE path)
330{
331    rb_enc_associate(path, rb_locale_encoding());
332    return path;
333}
334
335void
336ruby_incpush(const char *path)
337{
338    ruby_push_include(path, locale_path);
339}
340
341static VALUE
342expand_include_path(VALUE path)
343{
344    char *p = RSTRING_PTR(path);
345    if (!p)
346	return path;
347    if (*p == '.' && p[1] == '/')
348	return path;
349    return rb_file_expand_path(path, Qnil);
350}
351
352void
353ruby_incpush_expand(const char *path)
354{
355    ruby_push_include(path, expand_include_path);
356}
357
358#if defined _WIN32 || defined __CYGWIN__
359static HMODULE libruby;
360
361BOOL WINAPI
362DllMain(HINSTANCE dll, DWORD reason, LPVOID reserved)
363{
364    if (reason == DLL_PROCESS_ATTACH)
365	libruby = dll;
366    return TRUE;
367}
368
369HANDLE
370rb_libruby_handle(void)
371{
372    return libruby;
373}
374#endif
375
376void ruby_init_loadpath_safe(int safe_level);
377
378void
379ruby_init_loadpath(void)
380{
381    ruby_init_loadpath_safe(0);
382}
383
384void
385ruby_init_loadpath_safe(int safe_level)
386{
387    VALUE load_path;
388    ID id_initial_load_path_mark;
389    extern const char ruby_initial_load_paths[];
390    const char *paths = ruby_initial_load_paths;
391#if defined LOAD_RELATIVE
392# if defined HAVE_DLADDR || defined HAVE_CYGWIN_CONV_PATH
393#   define VARIABLE_LIBPATH 1
394# else
395#   define VARIABLE_LIBPATH 0
396# endif
397# if VARIABLE_LIBPATH
398    char *libpath;
399    VALUE sopath;
400# else
401    char libpath[MAXPATHLEN + 1];
402# endif
403    size_t baselen;
404    char *p;
405
406#if defined _WIN32 || defined __CYGWIN__
407# if VARIABLE_LIBPATH
408    sopath = rb_str_new(0, MAXPATHLEN);
409    libpath = RSTRING_PTR(sopath);
410    GetModuleFileName(libruby, libpath, MAXPATHLEN);
411# else
412    GetModuleFileName(libruby, libpath, sizeof libpath);
413# endif
414#elif defined(__EMX__)
415    _execname(libpath, sizeof(libpath) - 1);
416#elif defined(HAVE_DLADDR)
417    Dl_info dli;
418    if (dladdr((void *)(VALUE)expand_include_path, &dli)) {
419	char fbuf[MAXPATHLEN];
420	char *f = dln_find_file_r(dli.dli_fname, getenv(PATH_ENV), fbuf, sizeof(fbuf));
421	VALUE fname = rb_str_new_cstr(f ? f : dli.dli_fname);
422	rb_str_freeze(fname);
423	sopath = rb_realpath_internal(Qnil, fname, 1);
424    }
425    else {
426	sopath = rb_str_new(0, 0);
427    }
428    libpath = RSTRING_PTR(sopath);
429#endif
430
431#if !VARIABLE_LIBPATH
432    libpath[sizeof(libpath) - 1] = '\0';
433#endif
434#if defined DOSISH
435    translit_char(libpath, '\\', '/');
436#elif defined __CYGWIN__
437    {
438# if VARIABLE_LIBPATH
439	const int win_to_posix = CCP_WIN_A_TO_POSIX | CCP_RELATIVE;
440	size_t newsize = cygwin_conv_path(win_to_posix, libpath, 0, 0);
441	if (newsize > 0) {
442	    VALUE rubylib = rb_str_new(0, newsize);
443	    p = RSTRING_PTR(rubylib);
444	    if (cygwin_conv_path(win_to_posix, libpath, p, newsize) == 0) {
445		rb_str_resize(sopath, 0);
446		sopath = rubylib;
447		libpath = p;
448	    }
449	}
450# else
451	char rubylib[FILENAME_MAX];
452	cygwin_conv_to_posix_path(libpath, rubylib);
453	strncpy(libpath, rubylib, sizeof(libpath));
454# endif
455    }
456#endif
457    p = strrchr(libpath, '/');
458    if (p) {
459	static const char bindir[] = "/bin";
460#ifdef LIBDIR_BASENAME
461	static const char libdir[] = "/"LIBDIR_BASENAME;
462#else
463	static const char libdir[] = "/lib";
464#endif
465	const ptrdiff_t bindir_len = (ptrdiff_t)sizeof(bindir) - 1;
466	const ptrdiff_t libdir_len = (ptrdiff_t)sizeof(libdir) - 1;
467	*p = 0;
468	if (p - libpath >= bindir_len && !STRCASECMP(p - bindir_len, bindir)) {
469	    p -= bindir_len;
470	    *p = 0;
471	}
472	else if (p - libpath >= libdir_len && !strcmp(p - libdir_len, libdir)) {
473	    p -= libdir_len;
474	    *p = 0;
475	}
476    }
477#if !VARIABLE_LIBPATH
478    else {
479	strlcpy(libpath, ".", sizeof(libpath));
480	p = libpath + 1;
481    }
482    baselen = p - libpath;
483#define PREFIX_PATH() rb_str_new(libpath, baselen)
484#else
485    baselen = p - libpath;
486    rb_str_resize(sopath, baselen);
487    libpath = RSTRING_PTR(sopath);
488#define PREFIX_PATH() sopath
489#endif
490
491#define BASEPATH() rb_str_buf_cat(rb_str_buf_new(baselen+len), libpath, baselen)
492
493#define RUBY_RELATIVE(path, len) rb_str_buf_cat(BASEPATH(), (path), (len))
494#else
495    static const char exec_prefix[] = RUBY_EXEC_PREFIX;
496#define RUBY_RELATIVE(path, len) rubylib_mangled_path((path), (len))
497#define PREFIX_PATH() RUBY_RELATIVE(exec_prefix, sizeof(exec_prefix)-1)
498#endif
499    load_path = GET_VM()->load_path;
500
501    if (safe_level == 0) {
502#ifdef MANGLED_PATH
503	rubylib_mangled_path("", 0);
504#endif
505	ruby_push_include(getenv("RUBYLIB"), identical_path);
506    }
507
508    id_initial_load_path_mark = rb_intern_const("@gem_prelude_index");
509    while (*paths) {
510	size_t len = strlen(paths);
511	VALUE path = RUBY_RELATIVE(paths, len);
512	rb_ivar_set(path, id_initial_load_path_mark, path);
513	rb_ary_push(load_path, path);
514	paths += len + 1;
515    }
516
517    rb_const_set(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX"), rb_obj_freeze(PREFIX_PATH()));
518}
519
520
521static void
522add_modules(VALUE *req_list, const char *mod)
523{
524    VALUE list = *req_list;
525    VALUE feature;
526
527    if (!list) {
528	*req_list = list = rb_ary_new();
529	RBASIC(list)->klass = 0;
530    }
531    feature = rb_str_new2(mod);
532    RBASIC(feature)->klass = 0;
533    rb_ary_push(list, feature);
534}
535
536static void
537require_libraries(VALUE *req_list)
538{
539    VALUE list = *req_list;
540    VALUE self = rb_vm_top_self();
541    ID require;
542    rb_thread_t *th = GET_THREAD();
543    rb_encoding *extenc = rb_default_external_encoding();
544    int prev_parse_in_eval = th->parse_in_eval;
545    th->parse_in_eval = 0;
546
547    Init_ext();		/* should be called here for some reason :-( */
548    CONST_ID(require, "require");
549    while (list && RARRAY_LEN(list) > 0) {
550	VALUE feature = rb_ary_shift(list);
551	rb_enc_associate(feature, extenc);
552	RBASIC(feature)->klass = rb_cString;
553	OBJ_FREEZE(feature);
554	rb_funcall2(self, require, 1, &feature);
555    }
556    *req_list = 0;
557
558    th->parse_in_eval = prev_parse_in_eval;
559}
560
561static rb_env_t*
562toplevel_context(VALUE toplevel_binding)
563{
564    rb_env_t *env;
565    rb_binding_t *bind;
566
567    GetBindingPtr(toplevel_binding, bind);
568    GetEnvPtr(bind->env, env);
569    return env;
570}
571
572static void
573process_sflag(int *sflag)
574{
575    if (*sflag > 0) {
576	long n;
577	VALUE *args;
578	VALUE argv = rb_argv;
579
580	n = RARRAY_LEN(argv);
581	args = RARRAY_PTR(argv);
582	while (n > 0) {
583	    VALUE v = *args++;
584	    char *s = StringValuePtr(v);
585	    char *p;
586	    int hyphen = FALSE;
587
588	    if (s[0] != '-')
589		break;
590	    n--;
591	    if (s[1] == '-' && s[2] == '\0')
592		break;
593
594	    v = Qtrue;
595	    /* check if valid name before replacing - with _ */
596	    for (p = s + 1; *p; p++) {
597		if (*p == '=') {
598		    *p++ = '\0';
599		    v = rb_str_new2(p);
600		    break;
601		}
602		if (*p == '-') {
603		    hyphen = TRUE;
604		}
605		else if (*p != '_' && !ISALNUM(*p)) {
606		    VALUE name_error[2];
607		    name_error[0] =
608			rb_str_new2("invalid name for global variable - ");
609		    if (!(p = strchr(p, '='))) {
610			rb_str_cat2(name_error[0], s);
611		    }
612		    else {
613			rb_str_cat(name_error[0], s, p - s);
614		    }
615		    name_error[1] = args[-1];
616		    rb_exc_raise(rb_class_new_instance(2, name_error, rb_eNameError));
617		}
618	    }
619	    s[0] = '$';
620	    if (hyphen) {
621		for (p = s + 1; *p; ++p) {
622		    if (*p == '-')
623			*p = '_';
624		}
625	    }
626	    rb_gv_set(s, v);
627	}
628	n = RARRAY_LEN(argv) - n;
629	while (n--) {
630	    rb_ary_shift(argv);
631	}
632	*sflag = -1;
633    }
634}
635
636static long proc_options(long argc, char **argv, struct cmdline_options *opt, int envopt);
637
638static void
639moreswitches(const char *s, struct cmdline_options *opt, int envopt)
640{
641    long argc, i, len;
642    char **argv, *p;
643    const char *ap = 0;
644    VALUE argstr, argary;
645
646    while (ISSPACE(*s)) s++;
647    if (!*s) return;
648    argstr = rb_str_tmp_new((len = strlen(s)) + 2);
649    argary = rb_str_tmp_new(0);
650
651    p = RSTRING_PTR(argstr);
652    *p++ = ' ';
653    memcpy(p, s, len + 1);
654    ap = 0;
655    rb_str_cat(argary, (char *)&ap, sizeof(ap));
656    while (*p) {
657	ap = p;
658	rb_str_cat(argary, (char *)&ap, sizeof(ap));
659	while (*p && !ISSPACE(*p)) ++p;
660	if (!*p) break;
661	*p++ = '\0';
662	while (ISSPACE(*p)) ++p;
663    }
664    argc = RSTRING_LEN(argary) / sizeof(ap);
665    ap = 0;
666    rb_str_cat(argary, (char *)&ap, sizeof(ap));
667    argv = (char **)RSTRING_PTR(argary);
668
669    while ((i = proc_options(argc, argv, opt, envopt)) > 1 && (argc -= i) > 0) {
670	argv += i;
671	if (**argv != '-') {
672	    *--*argv = '-';
673	}
674	if ((*argv)[1]) {
675	    ++argc;
676	    --argv;
677	}
678    }
679
680    /* get rid of GC */
681    rb_str_resize(argary, 0);
682    rb_str_resize(argstr, 0);
683}
684
685#define NAME_MATCH_P(name, str, len) \
686    ((len) < (int)sizeof(name) && strncmp((str), (name), (len)) == 0)
687
688#define UNSET_WHEN(name, bit, str, len)	\
689    if (NAME_MATCH_P((name), (str), (len))) { \
690	*(unsigned int *)arg &= ~(bit); \
691	return;				\
692    }
693
694#define SET_WHEN(name, bit, str, len)	\
695    if (NAME_MATCH_P((name), (str), (len))) { \
696	*(unsigned int *)arg |= (bit);	\
697	return;				\
698    }
699
700static void
701enable_option(const char *str, int len, void *arg)
702{
703#define UNSET_WHEN_DISABLE(bit) UNSET_WHEN(#bit, DISABLE_BIT(bit), str, len)
704    UNSET_WHEN_DISABLE(gems);
705    UNSET_WHEN_DISABLE(rubyopt);
706    if (NAME_MATCH_P("all", str, len)) {
707	*(unsigned int *)arg = 0U;
708	return;
709    }
710    rb_warn("unknown argument for --enable: `%.*s'", len, str);
711}
712
713static void
714disable_option(const char *str, int len, void *arg)
715{
716#define SET_WHEN_DISABLE(bit) SET_WHEN(#bit, DISABLE_BIT(bit), str, len)
717    SET_WHEN_DISABLE(gems);
718    SET_WHEN_DISABLE(rubyopt);
719    if (NAME_MATCH_P("all", str, len)) {
720	*(unsigned int *)arg = ~0U;
721	return;
722    }
723    rb_warn("unknown argument for --disable: `%.*s'", len, str);
724}
725
726static void
727dump_option(const char *str, int len, void *arg)
728{
729#define SET_WHEN_DUMP(bit) SET_WHEN(#bit, DUMP_BIT(bit), str, len)
730    SET_WHEN_DUMP(version);
731    SET_WHEN_DUMP(copyright);
732    SET_WHEN_DUMP(usage);
733    SET_WHEN_DUMP(help);
734    SET_WHEN_DUMP(yydebug);
735    SET_WHEN_DUMP(syntax);
736    SET_WHEN_DUMP(parsetree);
737    SET_WHEN_DUMP(parsetree_with_comment);
738    SET_WHEN_DUMP(insns);
739    rb_warn("don't know how to dump `%.*s',", len, str);
740    rb_warn("but only [version, copyright, usage, yydebug, syntax, parsetree, parsetree_with_comment, insns].");
741}
742
743static void
744set_option_encoding_once(const char *type, VALUE *name, const char *e, long elen)
745{
746    VALUE ename;
747
748    if (!elen) elen = strlen(e);
749    ename = rb_str_new(e, elen);
750
751    if (*name &&
752	rb_funcall(ename, rb_intern("casecmp"), 1, *name) != INT2FIX(0)) {
753	rb_raise(rb_eRuntimeError,
754		 "%s already set to %s", type, RSTRING_PTR(*name));
755    }
756    *name = ename;
757}
758
759#define set_internal_encoding_once(opt, e, elen) \
760    set_option_encoding_once("default_internal", &(opt)->intern.enc.name, (e), (elen))
761#define set_external_encoding_once(opt, e, elen) \
762    set_option_encoding_once("default_external", &(opt)->ext.enc.name, (e), (elen))
763#define set_source_encoding_once(opt, e, elen) \
764    set_option_encoding_once("source", &(opt)->src.enc.name, (e), (elen))
765
766static long
767proc_options(long argc, char **argv, struct cmdline_options *opt, int envopt)
768{
769    long n, argc0 = argc;
770    const char *s;
771
772    if (argc == 0)
773	return 0;
774
775    for (argc--, argv++; argc > 0; argc--, argv++) {
776	const char *const arg = argv[0];
777	if (!arg || arg[0] != '-' || !arg[1])
778	    break;
779
780	s = arg + 1;
781      reswitch:
782	switch (*s) {
783	  case 'a':
784	    if (envopt) goto noenvopt;
785	    opt->do_split = TRUE;
786	    s++;
787	    goto reswitch;
788
789	  case 'p':
790	    if (envopt) goto noenvopt;
791	    opt->do_print = TRUE;
792	    /* through */
793	  case 'n':
794	    if (envopt) goto noenvopt;
795	    opt->do_loop = TRUE;
796	    s++;
797	    goto reswitch;
798
799	  case 'd':
800	    ruby_debug = Qtrue;
801	    ruby_verbose = Qtrue;
802	    s++;
803	    goto reswitch;
804
805	  case 'y':
806	    if (envopt) goto noenvopt;
807	    opt->dump |= DUMP_BIT(yydebug);
808	    s++;
809	    goto reswitch;
810
811	  case 'v':
812	    if (opt->verbose) {
813		s++;
814		goto reswitch;
815	    }
816	    opt->dump |= DUMP_BIT(version_v);
817	    opt->verbose = 1;
818	  case 'w':
819	    ruby_verbose = Qtrue;
820	    s++;
821	    goto reswitch;
822
823	  case 'W':
824	    {
825		size_t numlen;
826		int v = 2;	/* -W as -W2 */
827
828		if (*++s) {
829		    v = scan_oct(s, 1, &numlen);
830		    if (numlen == 0)
831			v = 1;
832		    s += numlen;
833		}
834		switch (v) {
835		  case 0:
836		    ruby_verbose = Qnil;
837		    break;
838		  case 1:
839		    ruby_verbose = Qfalse;
840		    break;
841		  default:
842		    ruby_verbose = Qtrue;
843		    break;
844		}
845	    }
846	    goto reswitch;
847
848	  case 'c':
849	    if (envopt) goto noenvopt;
850	    opt->dump |= DUMP_BIT(syntax);
851	    s++;
852	    goto reswitch;
853
854	  case 's':
855	    if (envopt) goto noenvopt;
856	    forbid_setid("-s");
857	    if (!opt->sflag) opt->sflag = 1;
858	    s++;
859	    goto reswitch;
860
861	  case 'h':
862	    if (envopt) goto noenvopt;
863	    opt->dump |= DUMP_BIT(usage);
864	    goto switch_end;
865
866	  case 'l':
867	    if (envopt) goto noenvopt;
868	    opt->do_line = TRUE;
869	    rb_output_rs = rb_rs;
870	    s++;
871	    goto reswitch;
872
873	  case 'S':
874	    if (envopt) goto noenvopt;
875	    forbid_setid("-S");
876	    opt->do_search = TRUE;
877	    s++;
878	    goto reswitch;
879
880	  case 'e':
881	    if (envopt) goto noenvopt;
882	    forbid_setid("-e");
883	    if (!*++s) {
884		s = argv[1];
885		argc--, argv++;
886	    }
887	    if (!s) {
888		rb_raise(rb_eRuntimeError, "no code specified for -e");
889	    }
890	    if (!opt->e_script) {
891		opt->e_script = rb_str_new(0, 0);
892		if (opt->script == 0)
893		    opt->script = "-e";
894	    }
895	    rb_str_cat2(opt->e_script, s);
896	    rb_str_cat2(opt->e_script, "\n");
897	    break;
898
899	  case 'r':
900	    forbid_setid("-r");
901	    if (*++s) {
902		add_modules(&opt->req_list, s);
903	    }
904	    else if (argv[1]) {
905		add_modules(&opt->req_list, argv[1]);
906		argc--, argv++;
907	    }
908	    break;
909
910	  case 'i':
911	    if (envopt) goto noenvopt;
912	    forbid_setid("-i");
913	    ruby_set_inplace_mode(s + 1);
914	    break;
915
916	  case 'x':
917	    if (envopt) goto noenvopt;
918	    opt->xflag = TRUE;
919	    s++;
920	    if (*s && chdir(s) < 0) {
921		rb_fatal("Can't chdir to %s", s);
922	    }
923	    break;
924
925	  case 'C':
926	  case 'X':
927	    if (envopt) goto noenvopt;
928	    s++;
929	    if (!*s) {
930		s = argv[1];
931		argc--, argv++;
932	    }
933	    if (!s || !*s) {
934		rb_fatal("Can't chdir");
935	    }
936	    if (chdir(s) < 0) {
937		rb_fatal("Can't chdir to %s", s);
938	    }
939	    break;
940
941	  case 'F':
942	    if (envopt) goto noenvopt;
943	    if (*++s) {
944		rb_fs = rb_reg_new(s, strlen(s), 0);
945	    }
946	    break;
947
948	  case 'E':
949	    if (!*++s && (!--argc || !(s = *++argv))) {
950		rb_raise(rb_eRuntimeError, "missing argument for -E");
951	    }
952	    goto encoding;
953
954	  case 'U':
955	    set_internal_encoding_once(opt, "UTF-8", 0);
956	    ++s;
957	    goto reswitch;
958
959	  case 'K':
960	    if (*++s) {
961		const char *enc_name = 0;
962		switch (*s) {
963		  case 'E': case 'e':
964		    enc_name = "EUC-JP";
965		    break;
966		  case 'S': case 's':
967		    enc_name = "Windows-31J";
968		    break;
969		  case 'U': case 'u':
970		    enc_name = "UTF-8";
971		    break;
972		  case 'N': case 'n': case 'A': case 'a':
973		    enc_name = "ASCII-8BIT";
974		    break;
975		}
976		if (enc_name) {
977		    opt->src.enc.name = rb_str_new2(enc_name);
978		    if (!opt->ext.enc.name)
979			opt->ext.enc.name = opt->src.enc.name;
980		}
981		s++;
982	    }
983	    goto reswitch;
984
985	  case 'T':
986	    {
987		size_t numlen;
988		int v = 1;
989
990		if (*++s) {
991		    v = scan_oct(s, 2, &numlen);
992		    if (numlen == 0)
993			v = 1;
994		    s += numlen;
995		}
996		if (v > opt->safe_level) opt->safe_level = v;
997	    }
998	    goto reswitch;
999
1000	  case 'I':
1001	    forbid_setid("-I");
1002	    if (*++s)
1003		ruby_incpush_expand(s);
1004	    else if (argv[1]) {
1005		ruby_incpush_expand(argv[1]);
1006		argc--, argv++;
1007	    }
1008	    break;
1009
1010	  case '0':
1011	    if (envopt) goto noenvopt;
1012	    {
1013		size_t numlen;
1014		int v;
1015		char c;
1016
1017		v = scan_oct(s, 4, &numlen);
1018		s += numlen;
1019		if (v > 0377)
1020		    rb_rs = Qnil;
1021		else if (v == 0 && numlen >= 2) {
1022		    rb_rs = rb_str_new2("\n\n");
1023		}
1024		else {
1025		    c = v & 0xff;
1026		    rb_rs = rb_str_new(&c, 1);
1027		}
1028	    }
1029	    goto reswitch;
1030
1031	  case '-':
1032	    if (!s[1] || (s[1] == '\r' && !s[2])) {
1033		argc--, argv++;
1034		goto switch_end;
1035	    }
1036	    s++;
1037
1038#	define is_option_end(c, allow_hyphen) \
1039	    (!(c) || ((allow_hyphen) && (c) == '-') || (c) == '=')
1040#	define check_envopt(name, allow_envopt) \
1041	    (((allow_envopt) || !envopt) ? (void)0 : \
1042	     rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --" name))
1043#	define need_argument(name, s) \
1044	    ((*(s)++ ? !*(s) : (!--argc || !((s) = *++argv))) ?		\
1045	     rb_raise(rb_eRuntimeError, "missing argument for --" name) \
1046	     : (void)0)
1047#	define is_option_with_arg(name, allow_hyphen, allow_envopt) \
1048	    (strncmp((name), s, n = sizeof(name) - 1) == 0 && is_option_end(s[n], (allow_hyphen)) ? \
1049	     (check_envopt(name, (allow_envopt)), s += n, need_argument(name, s), 1) : 0)
1050
1051	    if (strcmp("copyright", s) == 0) {
1052		if (envopt) goto noenvopt_long;
1053		opt->dump |= DUMP_BIT(copyright);
1054	    }
1055	    else if (strcmp("debug", s) == 0) {
1056		ruby_debug = Qtrue;
1057                ruby_verbose = Qtrue;
1058            }
1059	    else if (is_option_with_arg("enable", Qtrue, Qtrue)) {
1060		ruby_each_words(s, enable_option, &opt->disable);
1061	    }
1062	    else if (is_option_with_arg("disable", Qtrue, Qtrue)) {
1063		ruby_each_words(s, disable_option, &opt->disable);
1064	    }
1065	    else if (is_option_with_arg("encoding", Qfalse, Qtrue)) {
1066		char *p;
1067	      encoding:
1068		do {
1069#	define set_encoding_part(type) \
1070		    if (!(p = strchr(s, ':'))) { \
1071			set_##type##_encoding_once(opt, s, 0); \
1072			break; \
1073		    } \
1074		    else if (p > s) { \
1075			set_##type##_encoding_once(opt, s, p-s); \
1076		    }
1077		    set_encoding_part(external);
1078		    if (!*(s = ++p)) break;
1079		    set_encoding_part(internal);
1080		    if (!*(s = ++p)) break;
1081#if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
1082		    set_encoding_part(source);
1083		    if (!*(s = ++p)) break;
1084#endif
1085		    rb_raise(rb_eRuntimeError, "extra argument for %s: %s",
1086			     (arg[1] == '-' ? "--encoding" : "-E"), s);
1087#	undef set_encoding_part
1088		} while (0);
1089	    }
1090	    else if (is_option_with_arg("internal-encoding", Qfalse, Qtrue)) {
1091		set_internal_encoding_once(opt, s, 0);
1092	    }
1093	    else if (is_option_with_arg("external-encoding", Qfalse, Qtrue)) {
1094		set_external_encoding_once(opt, s, 0);
1095	    }
1096#if defined ALLOW_DEFAULT_SOURCE_ENCODING && ALLOW_DEFAULT_SOURCE_ENCODING
1097	    else if (is_option_with_arg("source-encoding", Qfalse, Qtrue)) {
1098		set_source_encoding_once(opt, s, 0);
1099	    }
1100#endif
1101	    else if (strcmp("version", s) == 0) {
1102		if (envopt) goto noenvopt_long;
1103		opt->dump |= DUMP_BIT(version);
1104	    }
1105	    else if (strcmp("verbose", s) == 0) {
1106		opt->verbose = 1;
1107		ruby_verbose = Qtrue;
1108	    }
1109	    else if (strcmp("yydebug", s) == 0) {
1110		if (envopt) goto noenvopt_long;
1111		opt->dump |= DUMP_BIT(yydebug);
1112	    }
1113	    else if (is_option_with_arg("dump", Qfalse, Qfalse)) {
1114		ruby_each_words(s, dump_option, &opt->dump);
1115	    }
1116	    else if (strcmp("help", s) == 0) {
1117		if (envopt) goto noenvopt_long;
1118		opt->dump |= DUMP_BIT(help);
1119		goto switch_end;
1120	    }
1121	    else {
1122		rb_raise(rb_eRuntimeError,
1123			 "invalid option --%s  (-h will show valid options)", s);
1124	    }
1125	    break;
1126
1127	  case '\r':
1128	    if (!s[1])
1129		break;
1130
1131	  default:
1132	    {
1133		if (ISPRINT(*s)) {
1134                    rb_raise(rb_eRuntimeError,
1135			"invalid option -%c  (-h will show valid options)",
1136                        (int)(unsigned char)*s);
1137		}
1138		else {
1139                    rb_raise(rb_eRuntimeError,
1140			"invalid option -\\x%02X  (-h will show valid options)",
1141                        (int)(unsigned char)*s);
1142		}
1143	    }
1144	    goto switch_end;
1145
1146	  noenvopt:
1147	    /* "EIdvwWrKU" only */
1148	    rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: -%c", *s);
1149	    break;
1150
1151	  noenvopt_long:
1152	    rb_raise(rb_eRuntimeError, "invalid switch in RUBYOPT: --%s", s);
1153	    break;
1154
1155	  case 0:
1156	    break;
1157#	undef is_option_end
1158#	undef check_envopt
1159#	undef need_argument
1160#	undef is_option_with_arg
1161	}
1162    }
1163
1164  switch_end:
1165    return argc0 - argc;
1166}
1167
1168static void
1169ruby_init_prelude(void)
1170{
1171    Init_prelude();
1172    rb_const_remove(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX"));
1173}
1174
1175static int
1176opt_enc_index(VALUE enc_name)
1177{
1178    const char *s = RSTRING_PTR(enc_name);
1179    int i = rb_enc_find_index(s);
1180
1181    if (i < 0) {
1182	rb_raise(rb_eRuntimeError, "unknown encoding name - %s", s);
1183    }
1184    else if (rb_enc_dummy_p(rb_enc_from_index(i))) {
1185	rb_raise(rb_eRuntimeError, "dummy encoding is not acceptable - %s ", s);
1186    }
1187    return i;
1188}
1189
1190#define rb_progname (GET_VM()->progname)
1191VALUE rb_argv0;
1192
1193static VALUE
1194false_value(void)
1195{
1196    return Qfalse;
1197}
1198
1199static VALUE
1200true_value(void)
1201{
1202    return Qtrue;
1203}
1204
1205#define rb_define_readonly_boolean(name, val) \
1206    rb_define_virtual_variable((name), (val) ? true_value : false_value, 0)
1207
1208static VALUE
1209uscore_get(void)
1210{
1211    VALUE line;
1212
1213    line = rb_lastline_get();
1214    if (!RB_TYPE_P(line, T_STRING)) {
1215	rb_raise(rb_eTypeError, "$_ value need to be String (%s given)",
1216		 NIL_P(line) ? "nil" : rb_obj_classname(line));
1217    }
1218    return line;
1219}
1220
1221/*
1222 *  call-seq:
1223 *     sub(pattern, replacement)   -> $_
1224 *     sub(pattern) { block }      -> $_
1225 *
1226 *  Equivalent to <code>$_.sub(<i>args</i>)</code>, except that
1227 *  <code>$_</code> will be updated if substitution occurs.
1228 *  Available only when -p/-n command line option specified.
1229 */
1230
1231static VALUE
1232rb_f_sub(int argc, VALUE *argv)
1233{
1234    VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("sub"), argc, argv);
1235    rb_lastline_set(str);
1236    return str;
1237}
1238
1239/*
1240 *  call-seq:
1241 *     gsub(pattern, replacement)    -> string
1242 *     gsub(pattern) {|...| block }  -> string
1243 *
1244 *  Equivalent to <code>$_.gsub...</code>, except that <code>$_</code>
1245 *  receives the modified result.
1246 *  Available only when -p/-n command line option specified.
1247 *
1248 */
1249
1250static VALUE
1251rb_f_gsub(int argc, VALUE *argv)
1252{
1253    VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("gsub"), argc, argv);
1254    rb_lastline_set(str);
1255    return str;
1256}
1257
1258/*
1259 *  call-seq:
1260 *     chop   -> string
1261 *
1262 *  Equivalent to <code>($_.dup).chop!</code>, except <code>nil</code>
1263 *  is never returned. See <code>String#chop!</code>.
1264 *  Available only when -p/-n command line option specified.
1265 *
1266 */
1267
1268static VALUE
1269rb_f_chop(void)
1270{
1271    VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("chop"), 0, 0);
1272    rb_lastline_set(str);
1273    return str;
1274}
1275
1276
1277/*
1278 *  call-seq:
1279 *     chomp            -> $_
1280 *     chomp(string)    -> $_
1281 *
1282 *  Equivalent to <code>$_ = $_.chomp(<em>string</em>)</code>. See
1283 *  <code>String#chomp</code>.
1284 *  Available only when -p/-n command line option specified.
1285 *
1286 */
1287
1288static VALUE
1289rb_f_chomp(int argc, VALUE *argv)
1290{
1291    VALUE str = rb_funcall_passing_block(uscore_get(), rb_intern("chomp"), argc, argv);
1292    rb_lastline_set(str);
1293    return str;
1294}
1295
1296/* blank function in dmyext.c or generated by enc/make_encmake.rb */
1297extern void Init_enc(void);
1298
1299static VALUE
1300process_options(int argc, char **argv, struct cmdline_options *opt)
1301{
1302    NODE *tree = 0;
1303    VALUE parser;
1304    VALUE iseq;
1305    rb_encoding *enc, *lenc;
1306    const char *s;
1307    char fbuf[MAXPATHLEN];
1308    int i = (int)proc_options(argc, argv, opt, 0);
1309    rb_thread_t *th = GET_THREAD();
1310    VALUE toplevel_binding = Qundef;
1311
1312    argc -= i;
1313    argv += i;
1314
1315    if (opt->dump & (DUMP_BIT(usage)|DUMP_BIT(help))) {
1316	usage(origarg.argv[0], (opt->dump & DUMP_BIT(help)));
1317	return Qtrue;
1318    }
1319
1320    if (!(opt->disable & DISABLE_BIT(rubyopt)) &&
1321	opt->safe_level == 0 && (s = getenv("RUBYOPT"))) {
1322	VALUE src_enc_name = opt->src.enc.name;
1323	VALUE ext_enc_name = opt->ext.enc.name;
1324	VALUE int_enc_name = opt->intern.enc.name;
1325
1326	opt->src.enc.name = opt->ext.enc.name = opt->intern.enc.name = 0;
1327	moreswitches(s, opt, 1);
1328	if (src_enc_name)
1329	    opt->src.enc.name = src_enc_name;
1330	if (ext_enc_name)
1331	    opt->ext.enc.name = ext_enc_name;
1332	if (int_enc_name)
1333	    opt->intern.enc.name = int_enc_name;
1334    }
1335
1336    if (opt->src.enc.name)
1337	rb_warning("-K is specified; it is for 1.8 compatibility and may cause odd behavior");
1338
1339    if (opt->dump & (DUMP_BIT(version) | DUMP_BIT(version_v))) {
1340	ruby_show_version();
1341	if (opt->dump & DUMP_BIT(version)) return Qtrue;
1342    }
1343    if (opt->dump & DUMP_BIT(copyright)) {
1344	ruby_show_copyright();
1345    }
1346
1347    if (opt->safe_level >= 4) {
1348	OBJ_TAINT(rb_argv);
1349	OBJ_TAINT(GET_VM()->load_path);
1350    }
1351
1352    if (!opt->e_script) {
1353	if (argc == 0) {	/* no more args */
1354	    if (opt->verbose)
1355		return Qtrue;
1356	    opt->script = "-";
1357	}
1358	else {
1359	    opt->script = argv[0];
1360	    if (!opt->script || opt->script[0] == '\0') {
1361		opt->script = "-";
1362	    }
1363	    else if (opt->do_search) {
1364		char *path = getenv("RUBYPATH");
1365
1366		opt->script = 0;
1367		if (path) {
1368		    opt->script = dln_find_file_r(argv[0], path, fbuf, sizeof(fbuf));
1369		}
1370		if (!opt->script) {
1371		    opt->script = dln_find_file_r(argv[0], getenv(PATH_ENV), fbuf, sizeof(fbuf));
1372		}
1373		if (!opt->script)
1374		    opt->script = argv[0];
1375	    }
1376	    argc--;
1377	    argv++;
1378	}
1379    }
1380
1381    opt->script_name = rb_str_new_cstr(opt->script);
1382    opt->script = RSTRING_PTR(opt->script_name);
1383#if defined DOSISH || defined __CYGWIN__
1384    translit_char(RSTRING_PTR(opt->script_name), '\\', '/');
1385#endif
1386
1387    ruby_init_loadpath_safe(opt->safe_level);
1388    Init_enc();
1389    rb_enc_find_index("encdb");
1390    lenc = rb_locale_encoding();
1391    rb_enc_associate(rb_progname, lenc);
1392    rb_obj_freeze(rb_progname);
1393    parser = rb_parser_new();
1394    if (opt->dump & DUMP_BIT(yydebug)) {
1395	rb_parser_set_yydebug(parser, Qtrue);
1396    }
1397    if (opt->ext.enc.name != 0) {
1398	opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
1399    }
1400    if (opt->intern.enc.name != 0) {
1401	opt->intern.enc.index = opt_enc_index(opt->intern.enc.name);
1402    }
1403    if (opt->src.enc.name != 0) {
1404	opt->src.enc.index = opt_enc_index(opt->src.enc.name);
1405	src_encoding_index = opt->src.enc.index;
1406    }
1407    if (opt->ext.enc.index >= 0) {
1408	enc = rb_enc_from_index(opt->ext.enc.index);
1409    }
1410    else {
1411	enc = lenc;
1412    }
1413    rb_enc_set_default_external(rb_enc_from_encoding(enc));
1414    if (opt->intern.enc.index >= 0) {
1415	enc = rb_enc_from_index(opt->intern.enc.index);
1416	rb_enc_set_default_internal(rb_enc_from_encoding(enc));
1417	opt->intern.enc.index = -1;
1418    }
1419    rb_enc_associate(opt->script_name, lenc);
1420    rb_obj_freeze(opt->script_name);
1421    {
1422	long i;
1423	VALUE load_path = GET_VM()->load_path;
1424	for (i = 0; i < RARRAY_LEN(load_path); ++i) {
1425	    RARRAY_PTR(load_path)[i] =
1426		rb_enc_associate(rb_str_dup(RARRAY_PTR(load_path)[i]), lenc);
1427	}
1428    }
1429    if (!(opt->disable & DISABLE_BIT(gems))) {
1430#if defined DISABLE_RUBYGEMS && DISABLE_RUBYGEMS
1431	rb_require("rubygems");
1432#else
1433	rb_define_module("Gem");
1434#endif
1435    }
1436    ruby_init_prelude();
1437    ruby_set_argv(argc, argv);
1438    process_sflag(&opt->sflag);
1439
1440    toplevel_binding = rb_const_get(rb_cObject, rb_intern("TOPLEVEL_BINDING"));
1441
1442#define PREPARE_PARSE_MAIN(expr) do { \
1443    rb_env_t *env = toplevel_context(toplevel_binding); \
1444    th->parse_in_eval--; \
1445    th->base_block = &env->block; \
1446    expr; \
1447    th->parse_in_eval++; \
1448    th->base_block = 0; \
1449} while (0)
1450
1451    if (opt->e_script) {
1452	VALUE progname = rb_progname;
1453	rb_encoding *eenc;
1454	if (opt->src.enc.index >= 0) {
1455	    eenc = rb_enc_from_index(opt->src.enc.index);
1456	}
1457	else {
1458	    eenc = lenc;
1459	}
1460	rb_enc_associate(opt->e_script, eenc);
1461        ruby_set_script_name(opt->script_name);
1462	require_libraries(&opt->req_list);
1463        ruby_set_script_name(progname);
1464
1465	PREPARE_PARSE_MAIN({
1466	    tree = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
1467	});
1468    }
1469    else {
1470	if (opt->script[0] == '-' && !opt->script[1]) {
1471	    forbid_setid("program input from stdin");
1472	}
1473
1474	PREPARE_PARSE_MAIN({
1475	    tree = load_file(parser, opt->script_name, 1, opt);
1476	});
1477    }
1478    ruby_set_script_name(opt->script_name);
1479    if (opt->dump & DUMP_BIT(yydebug)) return Qtrue;
1480
1481    if (opt->ext.enc.index >= 0) {
1482	enc = rb_enc_from_index(opt->ext.enc.index);
1483    }
1484    else {
1485	enc = lenc;
1486    }
1487    rb_enc_set_default_external(rb_enc_from_encoding(enc));
1488    if (opt->intern.enc.index >= 0) {
1489	/* Set in the shebang line */
1490	enc = rb_enc_from_index(opt->intern.enc.index);
1491	rb_enc_set_default_internal(rb_enc_from_encoding(enc));
1492    }
1493    else if (!rb_default_internal_encoding())
1494	/* Freeze default_internal */
1495	rb_enc_set_default_internal(Qnil);
1496    rb_stdio_set_default_encoding();
1497
1498    if (!tree) return Qfalse;
1499
1500    process_sflag(&opt->sflag);
1501    opt->xflag = 0;
1502
1503    if (opt->safe_level >= 4) {
1504	FL_UNSET(rb_argv, FL_TAINT);
1505	FL_UNSET(GET_VM()->load_path, FL_TAINT);
1506    }
1507
1508    if (opt->dump & DUMP_BIT(syntax)) {
1509	printf("Syntax OK\n");
1510	return Qtrue;
1511    }
1512
1513    if (opt->do_print) {
1514	PREPARE_PARSE_MAIN({
1515	    tree = rb_parser_append_print(parser, tree);
1516	});
1517    }
1518    if (opt->do_loop) {
1519	PREPARE_PARSE_MAIN({
1520	    tree = rb_parser_while_loop(parser, tree, opt->do_line, opt->do_split);
1521	});
1522	rb_define_global_function("sub", rb_f_sub, -1);
1523	rb_define_global_function("gsub", rb_f_gsub, -1);
1524	rb_define_global_function("chop", rb_f_chop, 0);
1525	rb_define_global_function("chomp", rb_f_chomp, -1);
1526    }
1527
1528    if (opt->dump & DUMP_BIT(parsetree) || opt->dump & DUMP_BIT(parsetree_with_comment)) {
1529	rb_io_write(rb_stdout, rb_parser_dump_tree(tree, opt->dump & DUMP_BIT(parsetree_with_comment)));
1530	rb_io_flush(rb_stdout);
1531	return Qtrue;
1532    }
1533
1534    PREPARE_PARSE_MAIN({
1535	VALUE path = Qnil;
1536	if (!opt->e_script && strcmp(opt->script, "-")) {
1537	    path = rb_realpath_internal(Qnil, opt->script_name, 1);
1538	}
1539	iseq = rb_iseq_new_main(tree, opt->script_name, path);
1540    });
1541
1542    if (opt->dump & DUMP_BIT(insns)) {
1543	rb_io_write(rb_stdout, rb_iseq_disasm(iseq));
1544	rb_io_flush(rb_stdout);
1545	return Qtrue;
1546    }
1547
1548    rb_define_readonly_boolean("$-p", opt->do_print);
1549    rb_define_readonly_boolean("$-l", opt->do_line);
1550    rb_define_readonly_boolean("$-a", opt->do_split);
1551
1552    rb_set_safe_level(opt->safe_level);
1553    rb_gc_set_params();
1554
1555    return iseq;
1556}
1557
1558struct load_file_arg {
1559    VALUE parser;
1560    VALUE fname;
1561    int script;
1562    struct cmdline_options *opt;
1563};
1564
1565static VALUE
1566load_file_internal(VALUE arg)
1567{
1568    extern VALUE rb_stdin;
1569    struct load_file_arg *argp = (struct load_file_arg *)arg;
1570    VALUE parser = argp->parser;
1571    VALUE fname_v = rb_str_encode_ospath(argp->fname);
1572    const char *fname = StringValueCStr(fname_v);
1573    const char *orig_fname = StringValueCStr(argp->fname);
1574    int script = argp->script;
1575    struct cmdline_options *opt = argp->opt;
1576    VALUE f;
1577    int line_start = 1;
1578    NODE *tree = 0;
1579    rb_encoding *enc;
1580    ID set_encoding;
1581    int xflag = 0;
1582
1583    if (strcmp(fname, "-") == 0) {
1584	f = rb_stdin;
1585    }
1586    else {
1587	int fd, mode = O_RDONLY;
1588#if defined DOSISH || defined __CYGWIN__
1589	{
1590	    const char *ext = strrchr(fname, '.');
1591	    if (ext && STRCASECMP(ext, ".exe") == 0) {
1592		mode |= O_BINARY;
1593		xflag = 1;
1594	    }
1595	}
1596#endif
1597	if ((fd = rb_cloexec_open(fname, mode, 0)) < 0) {
1598	    rb_load_fail(fname_v, strerror(errno));
1599	}
1600        rb_update_max_fd(fd);
1601#if !defined DOSISH && !defined __CYGWIN__
1602	{
1603	    struct stat st;
1604	    if (fstat(fd, &st) != 0)
1605		rb_load_fail(fname_v, strerror(errno));
1606	    if (S_ISDIR(st.st_mode)) {
1607		errno = EISDIR;
1608		rb_load_fail(fname_v, strerror(EISDIR));
1609	    }
1610	}
1611#endif
1612	f = rb_io_fdopen(fd, mode, fname);
1613    }
1614
1615    CONST_ID(set_encoding, "set_encoding");
1616    if (script) {
1617	VALUE c = 1;		/* something not nil */
1618	VALUE line;
1619	char *p;
1620	int no_src_enc = !opt->src.enc.name;
1621	int no_ext_enc = !opt->ext.enc.name;
1622	int no_int_enc = !opt->intern.enc.name;
1623
1624	enc = rb_ascii8bit_encoding();
1625	rb_funcall(f, set_encoding, 1, rb_enc_from_encoding(enc));
1626
1627	if (xflag || opt->xflag) {
1628	    line_start--;
1629	  search_shebang:
1630	    forbid_setid("-x");
1631	    opt->xflag = FALSE;
1632	    while (!NIL_P(line = rb_io_gets(f))) {
1633		line_start++;
1634		if (RSTRING_LEN(line) > 2
1635		    && RSTRING_PTR(line)[0] == '#'
1636		    && RSTRING_PTR(line)[1] == '!') {
1637		    if ((p = strstr(RSTRING_PTR(line), "ruby")) != 0) {
1638			goto start_read;
1639		    }
1640		}
1641	    }
1642	    rb_loaderror("no Ruby script found in input");
1643	}
1644
1645	c = rb_io_getbyte(f);
1646	if (c == INT2FIX('#')) {
1647	    c = rb_io_getbyte(f);
1648	    if (c == INT2FIX('!')) {
1649		line = rb_io_gets(f);
1650		if (NIL_P(line))
1651		    return 0;
1652
1653		if ((p = strstr(RSTRING_PTR(line), "ruby")) == 0) {
1654		    /* not ruby script, assume -x flag */
1655		    goto search_shebang;
1656		}
1657
1658	      start_read:
1659		p += 4;
1660		RSTRING_PTR(line)[RSTRING_LEN(line) - 1] = '\0';
1661		if (RSTRING_PTR(line)[RSTRING_LEN(line) - 2] == '\r')
1662		    RSTRING_PTR(line)[RSTRING_LEN(line) - 2] = '\0';
1663		if ((p = strstr(p, " -")) != 0) {
1664		    moreswitches(p + 1, opt, 0);
1665		}
1666
1667		/* push back shebang for pragma may exist in next line */
1668		rb_io_ungetbyte(f, rb_str_new2("!\n"));
1669	    }
1670	    else if (!NIL_P(c)) {
1671		rb_io_ungetbyte(f, c);
1672	    }
1673	    rb_io_ungetbyte(f, INT2FIX('#'));
1674	    if (no_src_enc && opt->src.enc.name) {
1675		opt->src.enc.index = opt_enc_index(opt->src.enc.name);
1676		src_encoding_index = opt->src.enc.index;
1677	    }
1678	    if (no_ext_enc && opt->ext.enc.name) {
1679		opt->ext.enc.index = opt_enc_index(opt->ext.enc.name);
1680	    }
1681	    if (no_int_enc && opt->intern.enc.name) {
1682		opt->intern.enc.index = opt_enc_index(opt->intern.enc.name);
1683	    }
1684	}
1685	else if (!NIL_P(c)) {
1686	    rb_io_ungetbyte(f, c);
1687	}
1688	else {
1689	    if (f != rb_stdin) rb_io_close(f);
1690	    f = Qnil;
1691	}
1692        ruby_set_script_name(opt->script_name);
1693	require_libraries(&opt->req_list);	/* Why here? unnatural */
1694    }
1695    if (opt->src.enc.index >= 0) {
1696	enc = rb_enc_from_index(opt->src.enc.index);
1697    }
1698    else if (f == rb_stdin) {
1699	enc = rb_locale_encoding();
1700    }
1701    else {
1702	enc = rb_utf8_encoding();
1703    }
1704    if (NIL_P(f)) {
1705	f = rb_str_new(0, 0);
1706	rb_enc_associate(f, enc);
1707	return (VALUE)rb_parser_compile_string(parser, orig_fname, f, line_start);
1708    }
1709    rb_funcall(f, set_encoding, 2, rb_enc_from_encoding(enc), rb_str_new_cstr("-"));
1710    tree = rb_parser_compile_file(parser, orig_fname, f, line_start);
1711    rb_funcall(f, set_encoding, 1, rb_parser_encoding(parser));
1712    if (script && tree && rb_parser_end_seen_p(parser)) {
1713	/*
1714	 * DATA is a File that contains the data section of the executed file.
1715	 * To create a data section use <tt>__END__</tt>:
1716	 *
1717	 *   $ cat t.rb
1718	 *   puts DATA.gets
1719	 *   __END__
1720	 *   hello world!
1721	 *
1722	 *   $ ruby t.rb
1723	 *   hello world!
1724	 */
1725	rb_define_global_const("DATA", f);
1726    }
1727    else if (f != rb_stdin) {
1728	rb_io_close(f);
1729    }
1730    return (VALUE)tree;
1731}
1732
1733static VALUE
1734restore_lineno(VALUE lineno)
1735{
1736    return rb_gv_set("$.", lineno);
1737}
1738
1739static NODE *
1740load_file(VALUE parser, VALUE fname, int script, struct cmdline_options *opt)
1741{
1742    struct load_file_arg arg;
1743    arg.parser = parser;
1744    arg.fname = fname;
1745    arg.script = script;
1746    arg.opt = opt;
1747    return (NODE *)rb_ensure(load_file_internal, (VALUE)&arg, restore_lineno, rb_gv_get("$."));
1748}
1749
1750void *
1751rb_load_file(const char *fname)
1752{
1753    struct cmdline_options opt;
1754    VALUE fname_v = rb_str_new_cstr(fname);
1755
1756    return load_file(rb_parser_new(), fname_v, 0, cmdline_options_init(&opt));
1757}
1758
1759static void
1760set_arg0(VALUE val, ID id)
1761{
1762    char *s;
1763    long i;
1764
1765    if (origarg.argv == 0)
1766	rb_raise(rb_eRuntimeError, "$0 not initialized");
1767    StringValue(val);
1768    s = RSTRING_PTR(val);
1769    i = RSTRING_LEN(val);
1770
1771    setproctitle("%.*s", (int)i, s);
1772
1773    rb_progname = rb_obj_freeze(rb_external_str_new(s, i));
1774}
1775
1776/*! Sets the current script name to this value.
1777 *
1778 * This is similiar to <code>$0 = name</code> in Ruby level but also affects
1779 * <code>Method#location</code> and others.
1780 */
1781void
1782ruby_script(const char *name)
1783{
1784    if (name) {
1785	rb_progname = rb_external_str_new(name, strlen(name));
1786	rb_vm_set_progname(rb_progname);
1787    }
1788}
1789
1790/*! Sets the current script name to this value.
1791 *
1792 * Same as ruby_script() but accepts a VALUE.
1793 */
1794void
1795ruby_set_script_name(VALUE name)
1796{
1797    rb_progname = rb_str_dup(name);
1798    rb_vm_set_progname(rb_progname);
1799}
1800
1801static void
1802init_ids(struct cmdline_options *opt)
1803{
1804    rb_uid_t uid = getuid();
1805    rb_uid_t euid = geteuid();
1806    rb_gid_t gid = getgid();
1807    rb_gid_t egid = getegid();
1808
1809    if (uid != euid) opt->setids |= 1;
1810    if (egid != gid) opt->setids |= 2;
1811    if (uid && opt->setids) {
1812	if (opt->safe_level < 1) opt->safe_level = 1;
1813    }
1814}
1815
1816#undef forbid_setid
1817static void
1818forbid_setid(const char *s, struct cmdline_options *opt)
1819{
1820    if (opt->setids & 1)
1821        rb_raise(rb_eSecurityError, "no %s allowed while running setuid", s);
1822    if (opt->setids & 2)
1823        rb_raise(rb_eSecurityError, "no %s allowed while running setgid", s);
1824    if (opt->safe_level > 0)
1825        rb_raise(rb_eSecurityError, "no %s allowed in tainted mode", s);
1826}
1827
1828static void
1829verbose_setter(VALUE val, ID id, void *data)
1830{
1831    VALUE *variable = data;
1832    *variable = RTEST(val) ? Qtrue : val;
1833}
1834
1835static VALUE
1836opt_W_getter(ID id, void *data)
1837{
1838    VALUE *variable = data;
1839    switch (*variable) {
1840      case Qnil:
1841	return INT2FIX(0);
1842      case Qfalse:
1843	return INT2FIX(1);
1844      case Qtrue:
1845	return INT2FIX(2);
1846      default:
1847	return Qnil;
1848    }
1849}
1850
1851/*! Defines built-in variables */
1852void
1853ruby_prog_init(void)
1854{
1855    rb_define_hooked_variable("$VERBOSE", &ruby_verbose, 0, verbose_setter);
1856    rb_define_hooked_variable("$-v", &ruby_verbose, 0, verbose_setter);
1857    rb_define_hooked_variable("$-w", &ruby_verbose, 0, verbose_setter);
1858    rb_define_hooked_variable("$-W", &ruby_verbose, opt_W_getter, rb_gvar_readonly_setter);
1859    rb_define_variable("$DEBUG", &ruby_debug);
1860    rb_define_variable("$-d", &ruby_debug);
1861
1862    rb_define_hooked_variable("$0", &rb_progname, 0, set_arg0);
1863    rb_define_hooked_variable("$PROGRAM_NAME", &rb_progname, 0, set_arg0);
1864
1865    /*
1866     * ARGV contains the command line arguments used to run ruby with the
1867     * first value containing the name of the executable.
1868     *
1869     * A library like OptionParser can be used to process command-line
1870     * arguments.
1871     */
1872    rb_define_global_const("ARGV", rb_argv);
1873}
1874
1875void
1876ruby_set_argv(int argc, char **argv)
1877{
1878    int i;
1879    VALUE av = rb_argv;
1880
1881#if defined(USE_DLN_A_OUT)
1882    if (origarg.argv)
1883	dln_argv0 = origarg.argv[0];
1884    else
1885	dln_argv0 = argv[0];
1886#endif
1887    rb_ary_clear(av);
1888    for (i = 0; i < argc; i++) {
1889	VALUE arg = rb_external_str_new_cstr(argv[i]);
1890
1891	OBJ_FREEZE(arg);
1892	rb_ary_push(av, arg);
1893    }
1894}
1895
1896void *
1897ruby_process_options(int argc, char **argv)
1898{
1899    struct cmdline_options opt;
1900    VALUE iseq;
1901    const char *script_name = (argc > 0 && argv[0]) ? argv[0] : "ruby";
1902
1903    ruby_script(script_name);  /* for the time being */
1904    rb_argv0 = rb_str_new4(rb_progname);
1905    rb_gc_register_mark_object(rb_argv0);
1906    iseq = process_options(argc, argv, cmdline_options_init(&opt));
1907
1908#ifndef HAVE_SETPROCTITLE
1909    {
1910	extern void ruby_init_setproctitle(int argc, char *argv[]);
1911	ruby_init_setproctitle(argc, argv);
1912    }
1913#endif
1914
1915    return (void*)(struct RData*)iseq;
1916}
1917
1918static void
1919fill_standard_fds(void)
1920{
1921    int f0, f1, f2, fds[2];
1922    struct stat buf;
1923    f0 = fstat(0, &buf) == -1 && errno == EBADF;
1924    f1 = fstat(1, &buf) == -1 && errno == EBADF;
1925    f2 = fstat(2, &buf) == -1 && errno == EBADF;
1926    if (f0) {
1927        if (pipe(fds) == 0) {
1928            close(fds[1]);
1929            if (fds[0] != 0) {
1930                dup2(fds[0], 0);
1931                close(fds[0]);
1932            }
1933        }
1934    }
1935    if (f1 || f2) {
1936        if (pipe(fds) == 0) {
1937            close(fds[0]);
1938            if (f1 && fds[1] != 1)
1939                dup2(fds[1], 1);
1940            if (f2 && fds[1] != 2)
1941                dup2(fds[1], 2);
1942            if (fds[1] != 1 && fds[1] != 2)
1943                close(fds[1]);
1944        }
1945    }
1946}
1947
1948/*! Initializes the process for ruby(1).
1949 *
1950 * This function assumes this process is ruby(1) and it has just started.
1951 * Usually programs that embeds CRuby interpreter should not call this function,
1952 * and should do their own initialization.
1953 */
1954void
1955ruby_sysinit(int *argc, char ***argv)
1956{
1957#if defined(_WIN32)
1958    void rb_w32_sysinit(int *argc, char ***argv);
1959    rb_w32_sysinit(argc, argv);
1960#endif
1961    origarg.argc = *argc;
1962    origarg.argv = *argv;
1963#if defined(USE_DLN_A_OUT)
1964    dln_argv0 = origarg.argv[0];
1965#endif
1966    fill_standard_fds();
1967}
1968