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