Ruby 2.0.0p247(2013-06-27revision41674)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

ruby.c
Go to the documentation of this file.
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
52 char *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)
64 enum disable_flag_bits {
65 disable_gems,
66 disable_rubyopt,
67 disable_flag_count
68 };
69
70 #define DUMP_BIT(bit) (1U << dump_##bit)
71 enum 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
85 struct 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
107 static void init_ids(struct cmdline_options *);
108
109 #define src_encoding_index GET_VM()->src_encoding_index
110
111 static struct cmdline_options *
112 cmdline_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
125 static NODE *load_file(VALUE, VALUE, int, struct cmdline_options *);
126 static void forbid_setid(const char *, struct cmdline_options *);
127 #define forbid_setid(s) forbid_setid((s), opt)
128
129 static struct {
130 int argc;
131 char **argv;
132 } origarg;
133
134 static void
135 usage(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
210 static VALUE
211 rubylib_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
253 static void
254 push_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__
272 static void
273 push_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
315 void
316 ruby_push_include(const char *path, VALUE (*filter)(VALUE))
317 {
318 if (path == 0)
319 return;
320 push_include(path, filter);
321 }
322
323 static VALUE
324 identical_path(VALUE path)
325 {
326 return path;
327 }
328 static VALUE
329 locale_path(VALUE path)
330 {
331 rb_enc_associate(path, rb_locale_encoding());
332 return path;
333 }
334
335 void
336 ruby_incpush(const char *path)
337 {
338 ruby_push_include(path, locale_path);
339 }
340
341 static VALUE
342 expand_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
352 void
353 ruby_incpush_expand(const char *path)
354 {
355 ruby_push_include(path, expand_include_path);
356 }
357
358 #if defined _WIN32 || defined __CYGWIN__
359 static HMODULE libruby;
360
361 BOOL WINAPI
362 DllMain(HINSTANCE dll, DWORD reason, LPVOID reserved)
363 {
364 if (reason == DLL_PROCESS_ATTACH)
365 libruby = dll;
366 return TRUE;
367 }
368
369 HANDLE
370 rb_libruby_handle(void)
371 {
372 return libruby;
373 }
374 #endif
375
376 void ruby_init_loadpath_safe(int safe_level);
377
378 void
379 ruby_init_loadpath(void)
380 {
381 ruby_init_loadpath_safe(0);
382 }
383
384 void
385 ruby_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
521 static void
522 add_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
536 static void
537 require_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
561 static rb_env_t*
562 toplevel_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
572 static void
573 process_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
636 static long proc_options(long argc, char **argv, struct cmdline_options *opt, int envopt);
637
638 static void
639 moreswitches(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
700 static void
701 enable_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
713 static void
714 disable_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
726 static void
727 dump_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
743 static void
744 set_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
766 static long
767 proc_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
1168 static void
1169 ruby_init_prelude(void)
1170 {
1171 Init_prelude();
1172 rb_const_remove(rb_cObject, rb_intern_const("TMP_RUBY_PREFIX"));
1173 }
1174
1175 static int
1176 opt_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)
1191 VALUE rb_argv0;
1192
1193 static VALUE
1194 false_value(void)
1195 {
1196 return Qfalse;
1197 }
1198
1199 static VALUE
1200 true_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
1208 static VALUE
1209 uscore_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
1231 static VALUE
1232 rb_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
1250 static VALUE
1251 rb_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
1268 static VALUE
1269 rb_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
1288 static VALUE
1289 rb_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 */
1297 extern void Init_enc(void);
1298
1299 static VALUE
1300 process_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
1558 struct load_file_arg {
1559 VALUE parser;
1560 VALUE fname;
1561 int script;
1562 struct cmdline_options *opt;
1563 };
1564
1565 static VALUE
1566 load_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
1733 static VALUE
1734 restore_lineno(VALUE lineno)
1735 {
1736 return rb_gv_set("$.", lineno);
1737 }
1738
1739 static NODE *
1740 load_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
1750 void *
1751 rb_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
1759 static void
1760 set_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
1781 void
1782 ruby_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
1794 void
1795 ruby_set_script_name(VALUE name)
1796 {
1797 rb_progname = rb_str_dup(name);
1798 rb_vm_set_progname(rb_progname);
1799 }
1800
1801 static void
1802 init_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
1817 static void
1818 forbid_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
1828 static void
1829 verbose_setter(VALUE val, ID id, void *data)
1830 {
1831 VALUE *variable = data;
1832 *variable = RTEST(val) ? Qtrue : val;
1833 }
1834
1835 static VALUE
1836 opt_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
1852 void
1853 ruby_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
1875 void
1876 ruby_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
1896 void *
1897 ruby_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
1918 static void
1919 fill_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
1954 void
1955 ruby_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